55package ltd.evilcorp.atox.ui.call
66
77import android.Manifest
8+ import android.media.AudioDeviceInfo.TYPE_BLE_HEADSET
9+ import android.media.AudioDeviceInfo.TYPE_BLE_SPEAKER
10+ import android.media.AudioDeviceInfo.TYPE_BLUETOOTH_SCO
11+ import android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES
12+ import android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET
13+ import android.media.AudioManager
14+ import android.os.Build
815import android.os.Bundle
916import android.view.View
1017import android.widget.Toast
1118import androidx.activity.result.contract.ActivityResultContracts
19+ import androidx.annotation.RequiresApi
20+ import androidx.core.content.ContextCompat.getSystemService
1221import androidx.core.view.ViewCompat
1322import androidx.core.view.WindowInsetsCompat
1423import androidx.core.view.updatePadding
@@ -28,6 +37,20 @@ import ltd.evilcorp.domain.tox.PublicKey
2837private const val PERMISSION = Manifest .permission.RECORD_AUDIO
2938
3039class CallFragment : BaseFragment <FragmentCallBinding >(FragmentCallBinding : :inflate) {
40+
41+ companion object {
42+ private var hasCalled = false
43+
44+ @RequiresApi(Build .VERSION_CODES .S )
45+ private val audioOutputDevices = arrayOf(
46+ TYPE_WIRED_HEADPHONES ,
47+ TYPE_WIRED_HEADSET ,
48+ TYPE_BLE_HEADSET ,
49+ TYPE_BLE_SPEAKER ,
50+ TYPE_BLUETOOTH_SCO ,
51+ )
52+ }
53+
3154 private val vm: CallViewModel by viewModels { vmFactory }
3255
3356 private val requestPermissionLauncher = registerForActivityResult(
@@ -40,6 +63,7 @@ class CallFragment : BaseFragment<FragmentCallBinding>(FragmentCallBinding::infl
4063 }
4164 }
4265
66+ @RequiresApi(Build .VERSION_CODES .S )
4367 override fun onViewCreated (view : View , savedInstanceState : Bundle ? ) = binding.run {
4468 ViewCompat .setOnApplyWindowInsetsListener(view) { _, compat ->
4569 val insets = compat.getInsets(WindowInsetsCompat .Type .systemBars())
@@ -77,6 +101,7 @@ class CallFragment : BaseFragment<FragmentCallBinding>(FragmentCallBinding::infl
77101 }
78102 }
79103
104+ updateSpeakerphoneOnDetectHeadphones()
80105 updateSpeakerphoneIcon()
81106 speakerphone.setOnClickListener {
82107 vm.toggleSpeakerphone()
@@ -108,12 +133,28 @@ class CallFragment : BaseFragment<FragmentCallBinding>(FragmentCallBinding::infl
108133 binding.speakerphone.setImageResource(icon)
109134 }
110135
136+ @RequiresApi(Build .VERSION_CODES .S )
137+ private fun updateSpeakerphoneOnDetectHeadphones () {
138+ if (headphonesArePlugged()) {
139+ vm.disableSpeakerphone()
140+ }
141+ }
142+
111143 private fun startCall () {
112144 vm.startCall()
113145 vm.inCall.asLiveData().observe(viewLifecycleOwner) { inCall ->
114146 if (inCall == CallState .NotInCall ) {
115147 findNavController().popBackStack()
148+ hasCalled = false
116149 }
117150 }
118151 }
152+
153+ @RequiresApi(Build .VERSION_CODES .S )
154+ private fun headphonesArePlugged (): Boolean {
155+ val audioManager = context?.let { getSystemService(it, AudioManager ::class .java) } ? : return false
156+ return audioManager.getDevices(AudioManager .GET_DEVICES_INPUTS ).any { info ->
157+ audioOutputDevices.contains(info.type)
158+ }
159+ }
119160}
0 commit comments