Better handling of Bluetooth connections/disconnections during calls.

fork-5.53.8
Nicholas 2022-09-28 15:35:46 -04:00 zatwierdzone przez Cody Henthorne
rodzic aaf8bf3280
commit aeb5a9cf57
4 zmienionych plików z 52 dodań i 31 usunięć

Wyświetl plik

@ -35,7 +35,7 @@ public final class WebRtcUtil {
public static @NonNull LockManager.PhoneState getInCallPhoneState(@NonNull Context context) {
AudioManagerCompat audioManager = ApplicationDependencies.getAndroidCallAudioManager();
if (audioManager.isSpeakerphoneOn() || audioManager.isBluetoothScoOn() || audioManager.isWiredHeadsetOn()) {
if (audioManager.isSpeakerphoneOn() || audioManager.isBluetoothConnected() || audioManager.isWiredHeadsetOn()) {
return LockManager.PhoneState.IN_HANDS_FREE_CALL;
} else {
return LockManager.PhoneState.IN_CALL;

Wyświetl plik

@ -0,0 +1,29 @@
package org.thoughtcrime.securesms.webrtc.audio
import android.media.AudioDeviceInfo
import androidx.annotation.RequiresApi
@RequiresApi(31)
object AudioDeviceMapping {
private val systemDeviceTypeMap: Map<SignalAudioManager.AudioDevice, List<Int>> = mapOf(
SignalAudioManager.AudioDevice.BLUETOOTH to listOf(AudioDeviceInfo.TYPE_BLUETOOTH_SCO, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLE_HEADSET),
SignalAudioManager.AudioDevice.EARPIECE to listOf(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE),
SignalAudioManager.AudioDevice.SPEAKER_PHONE to listOf(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE),
SignalAudioManager.AudioDevice.WIRED_HEADSET to listOf(AudioDeviceInfo.TYPE_WIRED_HEADSET, AudioDeviceInfo.TYPE_USB_HEADSET),
SignalAudioManager.AudioDevice.NONE to emptyList()
)
@JvmStatic
fun getEquivalentPlatformTypes(audioDevice: SignalAudioManager.AudioDevice): List<Int> {
return systemDeviceTypeMap[audioDevice]!!
}
@JvmStatic
fun fromPlatformType(type: Int): SignalAudioManager.AudioDevice {
for (kind in SignalAudioManager.AudioDevice.values()) {
if (getEquivalentPlatformTypes(kind).contains(type)) return kind
}
return SignalAudioManager.AudioDevice.NONE
}
}

Wyświetl plik

@ -52,6 +52,15 @@ public abstract class AudioManagerCompat {
audioManager.stopBluetoothSco();
}
public boolean isBluetoothConnected() {
if (Build.VERSION.SDK_INT >= 31) {
final SignalAudioManager.AudioDevice audioDevice = AudioDeviceMapping.fromPlatformType(audioManager.getCommunicationDevice().getType());
return SignalAudioManager.AudioDevice.BLUETOOTH == audioDevice;
} else {
return isBluetoothScoOn();
}
}
public boolean isBluetoothScoOn() {
return audioManager.isBluetoothScoOn();
}

Wyświetl plik

@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId
class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener?) : SignalAudioManager(context, eventListener) {
private val TAG = Log.tag(FullSignalAudioManagerApi31::class.java)
private var defaultDevice = AudioDevice.NONE
private var defaultDevice = AudioDevice.EARPIECE
private val deviceCallback = object : AudioDeviceCallback() {
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>) {
@ -26,7 +26,7 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
if (state == State.RUNNING) {
// Switch to any new audio devices immediately.
Log.i(TAG, "onAudioDevicesAdded $addedDevices")
val firstNewlyAddedDevice = addedDevices.firstNotNullOf { fromPlatformType(it.type) }
val firstNewlyAddedDevice = addedDevices.firstNotNullOf { AudioDeviceMapping.fromPlatformType(it.type) }
selectAudioDevice(null, firstNewlyAddedDevice)
}
}
@ -34,33 +34,11 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>) {
super.onAudioDevicesRemoved(removedDevices)
if (state == State.RUNNING) {
val currentDevice = androidAudioManager.communicationDevice
if (currentDevice != null && removedDevices.map { it.address }.contains(currentDevice.address)) {
selectAudioDevice(null, defaultDevice)
}
audioDeviceChangedCallback()
}
}
}
private val systemDeviceTypeMap: Map<AudioDevice, List<Int>> = mapOf(
AudioDevice.BLUETOOTH to listOf(AudioDeviceInfo.TYPE_BLUETOOTH_SCO, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLE_HEADSET),
AudioDevice.EARPIECE to listOf(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE),
AudioDevice.SPEAKER_PHONE to listOf(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE),
AudioDevice.WIRED_HEADSET to listOf(AudioDeviceInfo.TYPE_WIRED_HEADSET, AudioDeviceInfo.TYPE_USB_HEADSET),
AudioDevice.NONE to emptyList()
)
private fun getEquivalentPlatformTypes(audioDevice: AudioDevice): List<Int> {
return systemDeviceTypeMap[audioDevice]!!
}
private fun fromPlatformType(type: Int): AudioDevice {
for (kind in AudioDevice.values()) {
if (getEquivalentPlatformTypes(kind).contains(type)) return kind
}
return AudioDevice.NONE
}
override fun setDefaultAudioDevice(recipientId: RecipientId?, newDefaultDevice: AudioDevice, clearUserEarpieceSelection: Boolean) {
defaultDevice = newDefaultDevice
}
@ -83,9 +61,9 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
handler.postDelayed({ androidAudioManager.requestCallAudioFocus() }, 500)
}
if (androidAudioManager.availableCommunicationDevices.any { getEquivalentPlatformTypes(AudioDevice.BLUETOOTH).contains(it.type) }) {
if (androidAudioManager.availableCommunicationDevices.any { AudioDeviceMapping.getEquivalentPlatformTypes(AudioDevice.BLUETOOTH).contains(it.type) }) {
selectAudioDevice(null, AudioDevice.BLUETOOTH)
} else if (androidAudioManager.availableCommunicationDevices.any { getEquivalentPlatformTypes(AudioDevice.WIRED_HEADSET).contains(it.type) }) {
} else if (androidAudioManager.availableCommunicationDevices.any { AudioDeviceMapping.getEquivalentPlatformTypes(AudioDevice.WIRED_HEADSET).contains(it.type) }) {
selectAudioDevice(null, AudioDevice.WIRED_HEADSET)
}
@ -112,11 +90,11 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
val devices: List<AudioDeviceInfo> = androidAudioManager.availableCommunicationDevices
try {
val chosenDevice: AudioDeviceInfo = devices.first { getEquivalentPlatformTypes(device).contains(it.type) }
val chosenDevice: AudioDeviceInfo = devices.first { AudioDeviceMapping.getEquivalentPlatformTypes(device).contains(it.type) }
val result = androidAudioManager.setCommunicationDevice(chosenDevice)
if (result) {
Log.i(TAG, "Set active device to ID ${chosenDevice.id}, type ${chosenDevice.type}")
eventListener?.onAudioDeviceChanged(activeDevice = device, devices = devices.map { fromPlatformType(it.type) }.toSet())
eventListener?.onAudioDeviceChanged(activeDevice = device, devices = devices.map { AudioDeviceMapping.fromPlatformType(it.type) }.toSet())
} else {
Log.w(TAG, "Setting device $chosenDevice failed.")
}
@ -125,13 +103,18 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener
}
}
private fun audioDeviceChangedCallback() {
val activeDevice: AudioDevice = AudioDeviceMapping.fromPlatformType(androidAudioManager.communicationDevice.type)
val devices: Set<AudioDevice> = androidAudioManager.availableCommunicationDevices.map { AudioDeviceMapping.fromPlatformType(it.type) }.toSet()
eventListener?.onAudioDeviceChanged(activeDevice, devices)
}
override fun startIncomingRinger(ringtoneUri: Uri?, vibrate: Boolean) {
Log.i(TAG, "startIncomingRinger(): uri: ${if (ringtoneUri != null) "present" else "null"} vibrate: $vibrate")
androidAudioManager.mode = AudioManager.MODE_RINGTONE
if (androidAudioManager.isMicrophoneMute) {
androidAudioManager.isMicrophoneMute = false
}
setDefaultAudioDevice(null, AudioDevice.SPEAKER_PHONE, false)
incomingRinger.start(ringtoneUri, vibrate)
}