From e67dfb30db0df0fbcdf18fed2225d09ac897dae5 Mon Sep 17 00:00:00 2001 From: Akito Date: Fri, 18 Nov 2022 03:03:33 +0100 Subject: [PATCH] Disable speakerphone when headphones are plugged --- atox/src/main/kotlin/ui/call/CallFragment.kt | 41 +++++++++++++++++++ atox/src/main/kotlin/ui/call/CallViewModel.kt | 13 +++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/atox/src/main/kotlin/ui/call/CallFragment.kt b/atox/src/main/kotlin/ui/call/CallFragment.kt index 7cd5c0d69..01343fc96 100644 --- a/atox/src/main/kotlin/ui/call/CallFragment.kt +++ b/atox/src/main/kotlin/ui/call/CallFragment.kt @@ -5,10 +5,19 @@ package ltd.evilcorp.atox.ui.call import android.Manifest +import android.media.AudioDeviceInfo.TYPE_BLE_HEADSET +import android.media.AudioDeviceInfo.TYPE_BLE_SPEAKER +import android.media.AudioDeviceInfo.TYPE_BLUETOOTH_SCO +import android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES +import android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET +import android.media.AudioManager +import android.os.Build import android.os.Bundle import android.view.View import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresApi +import androidx.core.content.ContextCompat.getSystemService import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding @@ -25,9 +34,23 @@ import ltd.evilcorp.atox.vmFactory import ltd.evilcorp.domain.feature.CallState import ltd.evilcorp.domain.tox.PublicKey + private const val PERMISSION = Manifest.permission.RECORD_AUDIO class CallFragment : BaseFragment(FragmentCallBinding::inflate) { + + companion object { + private var hasCalled = false + @RequiresApi(Build.VERSION_CODES.S) + private val audioOutputDevices = arrayOf( + TYPE_WIRED_HEADPHONES, + TYPE_WIRED_HEADSET, + TYPE_BLE_HEADSET, + TYPE_BLE_SPEAKER, + TYPE_BLUETOOTH_SCO + ) + } + private val vm: CallViewModel by viewModels { vmFactory } private val requestPermissionLauncher = registerForActivityResult( @@ -40,6 +63,7 @@ class CallFragment : BaseFragment(FragmentCallBinding::infl } } + @RequiresApi(Build.VERSION_CODES.S) override fun onViewCreated(view: View, savedInstanceState: Bundle?) = binding.run { ViewCompat.setOnApplyWindowInsetsListener(view) { _, compat -> val insets = compat.getInsets(WindowInsetsCompat.Type.systemBars()) @@ -77,6 +101,7 @@ class CallFragment : BaseFragment(FragmentCallBinding::infl } } + updateSpeakerphoneOnDetectHeadphones() updateSpeakerphoneIcon() speakerphone.setOnClickListener { vm.toggleSpeakerphone() @@ -108,12 +133,28 @@ class CallFragment : BaseFragment(FragmentCallBinding::infl binding.speakerphone.setImageResource(icon) } + + @RequiresApi(Build.VERSION_CODES.S) + private fun updateSpeakerphoneOnDetectHeadphones() { + vm.disableSpeakerphone() + } + private fun startCall() { vm.startCall() vm.inCall.asLiveData().observe(viewLifecycleOwner) { inCall -> if (inCall == CallState.NotInCall) { findNavController().popBackStack() + hasCalled = false } } } + + @RequiresApi(Build.VERSION_CODES.S) + private fun headphonesArePlugged(): Boolean { + val ctx = context ?: return false + val audioManager = getSystemService(ctx, AudioManager::class.java) ?: return false + return audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS).any { info -> + audioOutputDevices.contains(info.type) + } + } } diff --git a/atox/src/main/kotlin/ui/call/CallViewModel.kt b/atox/src/main/kotlin/ui/call/CallViewModel.kt index 5d310ccf2..35507328c 100644 --- a/atox/src/main/kotlin/ui/call/CallViewModel.kt +++ b/atox/src/main/kotlin/ui/call/CallViewModel.kt @@ -49,8 +49,7 @@ class CallViewModel @Inject constructor( fun startSendingAudio() = callManager.startSendingAudio() fun stopSendingAudio() = callManager.stopSendingAudio() - fun toggleSpeakerphone() { - speakerphoneOn = !speakerphoneOn + fun applyProximityScreenSetting() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (speakerphoneOn) { proximityScreenOff.release() @@ -60,6 +59,16 @@ class CallViewModel @Inject constructor( } } + fun disableSpeakerphone() { + speakerphoneOn = false + applyProximityScreenSetting() + } + + fun toggleSpeakerphone() { + speakerphoneOn = !speakerphoneOn + applyProximityScreenSetting() + } + val inCall = callManager.inCall val sendingAudio = callManager.sendingAudio