diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt index 09bd90a9e3..25e856444c 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt @@ -8,6 +8,9 @@ package io.element.android.features.call.impl.ui import android.annotation.SuppressLint +import android.content.Context +import android.media.AudioDeviceCallback +import android.media.AudioDeviceInfo import android.media.AudioManager import android.util.Log import android.view.ViewGroup @@ -22,6 +25,10 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalInspectionMode @@ -151,15 +158,11 @@ private fun CallWebView( Text("WebView - can't be previewed") } } else { + var audioDeviceCallback: AudioDeviceCallback? by remember { mutableStateOf(null) } AndroidView( modifier = modifier, factory = { context -> - // Set 'voice call' mode so volume keys actually control the call volume - val audioManager = context.getSystemService() - audioManager?.mode = AudioManager.MODE_IN_COMMUNICATION - - audioManager?.enableExternalAudioDevice() - + audioDeviceCallback = context.setupAudioConfiguration() WebView(context).apply { onWebViewCreate(this) setup(userAgent, onPermissionsRequest) @@ -172,16 +175,40 @@ private fun CallWebView( }, onRelease = { webView -> // Reset audio mode - val audioManager = webView.context.getSystemService() - audioManager?.disableExternalAudioDevice() - audioManager?.mode = AudioManager.MODE_NORMAL - + webView.context.releaseAudioConfiguration(audioDeviceCallback) webView.destroy() } ) } } +private fun Context.setupAudioConfiguration(): AudioDeviceCallback? { + val audioManager = getSystemService() ?: return null + // Set 'voice call' mode so volume keys actually control the call volume + audioManager.mode = AudioManager.MODE_IN_COMMUNICATION + audioManager.enableExternalAudioDevice() + return object : AudioDeviceCallback() { + override fun onAudioDevicesAdded(addedDevices: Array?) { + Timber.d("Audio devices added") + audioManager.enableExternalAudioDevice() + } + + override fun onAudioDevicesRemoved(removedDevices: Array?) { + Timber.d("Audio devices removed") + audioManager.enableExternalAudioDevice() + } + }.also { + audioManager.registerAudioDeviceCallback(it, null) + } +} + +private fun Context.releaseAudioConfiguration(audioDeviceCallback: AudioDeviceCallback?) { + val audioManager = getSystemService() ?: return + audioManager.unregisterAudioDeviceCallback(audioDeviceCallback) + audioManager.disableExternalAudioDevice() + audioManager.mode = AudioManager.MODE_NORMAL +} + @SuppressLint("SetJavaScriptEnabled") private fun WebView.setup( userAgent: String, diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/compat/AudioManager.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/compat/AudioManager.kt index ce092f15f9..5e77d0d00a 100644 --- a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/compat/AudioManager.kt +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/compat/AudioManager.kt @@ -10,6 +10,8 @@ package io.element.android.libraries.androidutils.compat import android.media.AudioDeviceInfo import android.media.AudioManager import android.os.Build +import io.element.android.libraries.core.data.tryOrNull +import timber.log.Timber fun AudioManager.enableExternalAudioDevice() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { @@ -30,10 +32,26 @@ fun AudioManager.enableExternalAudioDevice() { AudioDeviceInfo.TYPE_BUILTIN_EARPIECE, ) val devices = availableCommunicationDevices - val selectedDevice = devices.find { - wantedDeviceTypes.contains(it.type) + val selectedDevice = devices.minByOrNull { + wantedDeviceTypes.indexOf(it.type).let { index -> + // If the device type is not in the wantedDeviceTypes list, we give it a low priority + if (index == -1) Int.MAX_VALUE else index + } + } + selectedDevice?.let { device -> + Timber.d("Audio device selected, type: ${device.type}") + tryOrNull( + onError = { failure -> + Timber.e(failure, "Audio: exception when setting communication device") + } + ) { + setCommunicationDevice(device).also { + if (!it) { + Timber.w("Audio: unable to set the communication device") + } + } + } } - selectedDevice?.let { setCommunicationDevice(it) } } else { // If we don't have access to the new APIs, use the deprecated ones @Suppress("DEPRECATION") diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en.png index 29b1a5cb41..241ad3330b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ddbe76235df4343660750e42512a431d10911442db54a2441fcb204ee4a6eb38 -size 230808 +oid sha256:03afa6a6d6c2b3ce7fd8b665e3bdf2b1cfdfe8414449817ec5d8c8f4ec5c6d7e +size 227835 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en.png index 6aa56907d4..f6c22c0964 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.customreaction_EmojiPicker_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bcc7cc69fdcae48da59f2bec88950aad996b869813d7f569bb205235efbd2731 -size 233656 +oid sha256:d6ac3b50611b79a15d5d80fdbc3790fda66f7877d58e65c64362577e377bd4db +size 230660