diff --git a/app/src/main/java/org/thoughtcrime/securesms/audio/BluetoothVoiceNoteUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/audio/BluetoothVoiceNoteUtil.kt index c6821088b2..61d681b52b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/audio/BluetoothVoiceNoteUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/audio/BluetoothVoiceNoteUtil.kt @@ -25,14 +25,14 @@ sealed interface BluetoothVoiceNoteUtil { fun destroy() companion object { - fun create(context: Context, listener: () -> Unit, bluetoothPermissionDeniedHandler: () -> Unit): BluetoothVoiceNoteUtil { + fun create(context: Context, listener: (Boolean) -> Unit, bluetoothPermissionDeniedHandler: () -> Unit): BluetoothVoiceNoteUtil { return if (Build.VERSION.SDK_INT >= 31) BluetoothVoiceNoteUtil31(listener) else BluetoothVoiceNoteUtilLegacy(context, listener, bluetoothPermissionDeniedHandler) } } } @RequiresApi(31) -private class BluetoothVoiceNoteUtil31(val listener: () -> Unit) : BluetoothVoiceNoteUtil { +private class BluetoothVoiceNoteUtil31(val listener: (Boolean) -> Unit) : BluetoothVoiceNoteUtil { override fun connectBluetoothScoConnection() { val audioManager = ApplicationDependencies.getAndroidCallAudioManager() val device: AudioDeviceInfo? = audioManager.connectedBluetoothDevice @@ -40,13 +40,15 @@ private class BluetoothVoiceNoteUtil31(val listener: () -> Unit) : BluetoothVoic val result: Boolean = audioManager.setCommunicationDevice(device) if (result) { Log.d(TAG, "Successfully set Bluetooth device as active communication device.") + listener(true) } else { Log.d(TAG, "Found Bluetooth device but failed to set it as active communication device.") + listener(false) } } else { Log.d(TAG, "Could not find Bluetooth device in list of communications devices, falling back to current input.") + listener(false) } - listener() } override fun disconnectBluetoothScoConnection() { @@ -64,15 +66,23 @@ private class BluetoothVoiceNoteUtil31(val listener: () -> Unit) : BluetoothVoic * @param listener This will be executed on the main thread after the Bluetooth connection connects, or if it doesn't. * @param bluetoothPermissionDeniedHandler called when we detect the Bluetooth permission has been denied to our app. */ -private class BluetoothVoiceNoteUtilLegacy(val context: Context, val listener: () -> Unit, val bluetoothPermissionDeniedHandler: () -> Unit) : BluetoothVoiceNoteUtil { +private class BluetoothVoiceNoteUtilLegacy(val context: Context, val listener: (Boolean) -> Unit, val bluetoothPermissionDeniedHandler: () -> Unit) : BluetoothVoiceNoteUtil { private val commandAndControlThread: HandlerThread = SignalExecutors.getAndStartHandlerThread("voice-note-audio", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD) private val uiThreadHandler = Handler(context.mainLooper) private val audioHandler: SignalAudioHandler = SignalAudioHandler(commandAndControlThread.looper) private val deviceUpdatedListener: AudioDeviceUpdatedListener = object : AudioDeviceUpdatedListener { override fun onAudioDeviceUpdated() { - if (signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTED) { - Log.d(TAG, "Bluetooth SCO connected. Starting voice note recording on UI thread.") - uiThreadHandler.post { listener() } + when (signalBluetoothManager.state) { + SignalBluetoothManager.State.CONNECTED -> { + Log.d(TAG, "Bluetooth SCO connected. Starting voice note recording on UI thread.") + uiThreadHandler.post { listener(true) } + } + SignalBluetoothManager.State.ERROR, + SignalBluetoothManager.State.PERMISSION_DENIED -> { + Log.w(TAG, "Unable to complete Bluetooth connection due to ${signalBluetoothManager.state}. Starting voice note recording anyway on UI thread.") + uiThreadHandler.post { listener(false) } + } + else -> Log.d(TAG, "Current Bluetooth connection state: ${signalBluetoothManager.state}.") } } } @@ -105,7 +115,7 @@ private class BluetoothVoiceNoteUtilLegacy(val context: Context, val listener: ( bluetoothPermissionDeniedHandler() hasWarnedAboutBluetooth = true } - listener() + listener(false) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index 88892f9c88..cb6607a51e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -58,6 +58,7 @@ import androidx.annotation.ColorRes; import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.annotation.WorkerThread; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.SearchView; @@ -304,7 +305,6 @@ import org.whispersystems.signalservice.api.SignalSessionLock; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -513,7 +513,7 @@ public class ConversationParentFragment extends Fragment voiceNoteMediaController = new VoiceNoteMediaController(requireActivity(), true); voiceRecorderWakeLock = new VoiceRecorderWakeLock(requireActivity()); - bluetoothVoiceNoteUtil = BluetoothVoiceNoteUtil.Companion.create(requireContext(), this::beginRecording, this::onBluetoothPermissionDenied); + bluetoothVoiceNoteUtil = BluetoothVoiceNoteUtil.Companion.create(requireContext(), this::onBluetoothConnectionAttempt, this::onBluetoothPermissionDenied); // TODO [alex] LargeScreenSupport -- Should be removed once we move to multi-pane layout. new FullscreenHelper(requireActivity()).showSystemUI(); @@ -3306,6 +3306,11 @@ public class ConversationParentFragment extends Fragment } } + private Unit onBluetoothConnectionAttempt(Boolean success) { + beginRecording(); + return Unit.INSTANCE; + } + private Unit beginRecording() { Vibrator vibrator = ServiceUtil.getVibrator(requireContext()); vibrator.vibrate(20); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate.kt index 68e09afe4b..204c2be9bc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/VoiceMessageRecordingDelegate.kt @@ -47,7 +47,7 @@ class VoiceMessageRecordingDelegate( private val voiceRecorderWakeLock = VoiceRecorderWakeLock(fragment.requireActivity()) private val bluetoothVoiceNoteUtil = BluetoothVoiceNoteUtil.create( fragment.requireContext(), - this::beginRecording, + this::onBluetoothConnectionAttempt, this::onBluetoothPermissionDenied ) @@ -104,6 +104,10 @@ class VoiceMessageRecordingDelegate( bluetoothVoiceNoteUtil.connectBluetoothScoConnection() } + private fun onBluetoothConnectionAttempt(success: Boolean) { + beginRecording() + } + @Suppress("DEPRECATION") private fun beginRecording() { val vibrator = ServiceUtil.getVibrator(fragment.requireContext())