diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcAudioOutputToggleButton.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcAudioOutputToggleButton.kt index 83d69504ed..8582bf506e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcAudioOutputToggleButton.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcAudioOutputToggleButton.kt @@ -72,21 +72,27 @@ class WebRtcAudioOutputToggleButton @JvmOverloads constructor(context: Context, } /** - * DO NOT REMOVE THE ELVIS OPERATOR IN THE FIRST LINE + * DO NOT REMOVE senseless comparison suppression. * Somehow, through XML inflation (reflection?), [outputState] can actually be null, * even though the compiler disagrees. * */ override fun onCreateDrawableState(extraSpace: Int): IntArray { - val currentState = outputState ?: return super.onCreateDrawableState(extraSpace) // DO NOT REMOVE - val currentOutput = currentState.getCurrentOutput() + @Suppress("SENSELESS_COMPARISON") + if (outputState == null) { + return super.onCreateDrawableState(extraSpace) + } + + val currentOutput = outputState.getCurrentOutput() val extra = when (currentOutput) { WebRtcAudioOutput.HANDSET -> intArrayOf(R.attr.state_handset_selected) WebRtcAudioOutput.SPEAKER -> intArrayOf(R.attr.state_speaker_selected) WebRtcAudioOutput.BLUETOOTH_HEADSET -> intArrayOf(R.attr.state_bt_headset_selected) WebRtcAudioOutput.WIRED_HEADSET -> intArrayOf(R.attr.state_wired_headset_selected) } - val oldLabel = context.getString(currentOutput.labelRes) - Log.i(TAG, "Switching drawable to $oldLabel") + + val label = context.getString(currentOutput.labelRes) + Log.i(TAG, "Switching to $label") + val drawableState = super.onCreateDrawableState(extraSpace + extra.size) mergeDrawableStates(drawableState, extra) return drawableState @@ -96,9 +102,10 @@ class WebRtcAudioOutputToggleButton @JvmOverloads constructor(context: Context, throw UnsupportedOperationException("This View does not support custom click listeners.") } - fun setControlAvailability(isEarpieceAvailable: Boolean, isBluetoothHeadsetAvailable: Boolean) { + fun setControlAvailability(isEarpieceAvailable: Boolean, isBluetoothHeadsetAvailable: Boolean, isHeadsetAvailable: Boolean) { outputState.isEarpieceAvailable = isEarpieceAvailable outputState.isBluetoothHeadsetAvailable = isBluetoothHeadsetAvailable + outputState.isWiredHeadsetAvailable = isHeadsetAvailable } fun setAudioOutput(audioOutput: WebRtcAudioOutput, notifyListener: Boolean) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallView.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallView.java index 4c0444bf62..ad4ec813b5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallView.java @@ -670,7 +670,8 @@ public class WebRtcCallView extends ConstraintLayout { visibleViewSet.add(audioToggle); audioToggle.setControlAvailability(webRtcControls.isEarpieceAvailableForAudioToggle(), - webRtcControls.isBluetoothHeadsetAvailableForAudioToggle()); + webRtcControls.isBluetoothHeadsetAvailableForAudioToggle(), + webRtcControls.isWiredHeadsetAvailableForAudioToggle()); audioToggle.setAudioOutput(webRtcControls.getAudioOutput(), false); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcControls.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcControls.java index b2b51c2eb3..f5bef150bd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcControls.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcControls.java @@ -153,7 +153,7 @@ public final class WebRtcControls { } boolean displayAudioToggle() { - return (isPreJoin() || isAtLeastOutgoing()) && (!isLocalVideoEnabled || isBluetoothHeadsetAvailableForAudioToggle()); + return (isPreJoin() || isAtLeastOutgoing()) && (!isLocalVideoEnabled || isBluetoothHeadsetAvailableForAudioToggle() || isWiredHeadsetAvailableForAudioToggle()); } boolean displayCameraToggle() { @@ -180,6 +180,10 @@ public final class WebRtcControls { return availableDevices.contains(SignalAudioManager.AudioDevice.BLUETOOTH); } + boolean isWiredHeadsetAvailableForAudioToggle() { + return availableDevices.contains(SignalAudioManager.AudioDevice.BLUETOOTH); + } + boolean isFadeOutEnabled() { return isAtLeastOutgoing() && isRemoteVideoEnabled && callState != CallState.RECONNECTING; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/FullSignalAudioManagerApi31.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/FullSignalAudioManagerApi31.kt index 4de106e3c0..b8497149de 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/FullSignalAudioManagerApi31.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/audio/FullSignalAudioManagerApi31.kt @@ -170,12 +170,10 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener androidAudioManager.communicationDevice = userSelectedAudioDevice eventListener?.onAudioDeviceChanged(AudioDeviceMapping.fromPlatformType(userSelectedAudioDevice!!.type), availableCommunicationDevices.map { AudioDeviceMapping.fromPlatformType(it.type) }.toSet()) } else { - val excludedDevices = emptyList() // TODO: pull this from somewhere. Preferences? - val autoSelectableDevices = availableCommunicationDevices.filterNot { excludedDevices.contains(it.address) } var candidate: AudioDeviceInfo? = null - val searchOrder: List = listOf(AudioDevice.BLUETOOTH, defaultAudioDevice, AudioDevice.WIRED_HEADSET, AudioDevice.EARPIECE, AudioDevice.SPEAKER_PHONE, AudioDevice.NONE).distinct() + val searchOrder: List = listOf(AudioDevice.BLUETOOTH, AudioDevice.WIRED_HEADSET, defaultAudioDevice, AudioDevice.EARPIECE, AudioDevice.SPEAKER_PHONE, AudioDevice.NONE).distinct() for (deviceType in searchOrder) { - candidate = autoSelectableDevices.find { AudioDeviceMapping.fromPlatformType(it.type) == deviceType } + candidate = availableCommunicationDevices.find { AudioDeviceMapping.fromPlatformType(it.type) == deviceType } if (candidate != null) { break } @@ -183,10 +181,9 @@ class FullSignalAudioManagerApi31(context: Context, eventListener: EventListener when (candidate) { null -> { - Log.e(TAG, "Tried to switch audio devices but could not find suitable device in list of types: ${autoSelectableDevices.map { it.type }.joinToString()}") + Log.e(TAG, "Tried to switch audio devices but could not find suitable device in list of types: ${availableCommunicationDevices.map { it.type }.joinToString()}") androidAudioManager.clearCommunicationDevice() } - currentAudioDevice -> Log.d(TAG, "Request to switch to existing audio device ignored.") else -> { Log.d(TAG, "Switching to new device of type ${candidate.type} from ${currentAudioDevice?.type}") androidAudioManager.communicationDevice = candidate