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
@@ -25,9 +34,23 @@ import ltd.evilcorp.atox.vmFactory
2534import ltd.evilcorp.domain.feature.CallState
2635import ltd.evilcorp.domain.tox.PublicKey
2736
37+
2838private const val PERMISSION = Manifest .permission.RECORD_AUDIO
2939
3040class CallFragment : BaseFragment <FragmentCallBinding >(FragmentCallBinding : :inflate) {
41+
42+ companion object {
43+ private var hasCalled = false
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+
137+ @RequiresApi(Build .VERSION_CODES .S )
138+ private fun updateSpeakerphoneOnDetectHeadphones () {
139+ vm.disableSpeakerphone()
140+ }
141+
111142 private fun startCall () {
112143 vm.startCall()
113144 vm.inCall.asLiveData().observe(viewLifecycleOwner) { inCall ->
114145 if (inCall == CallState .NotInCall ) {
115146 findNavController().popBackStack()
147+ hasCalled = false
116148 }
117149 }
118150 }
151+
152+ @RequiresApi(Build .VERSION_CODES .S )
153+ private fun headphonesArePlugged (): Boolean {
154+ val ctx = context ? : return false
155+ val audioManager = getSystemService(ctx, 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