From 1608e6233abd20442011ab19b8c2118a9a7730af Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sat, 21 Jan 2023 01:08:50 +0200 Subject: [PATCH] Hack to support toggling of speakerphone in Andoid API 31+ --- .../com/tutpro/baresip/BaresipService.kt | 2 +- .../kotlin/com/tutpro/baresip/MainActivity.kt | 20 +++--- .../main/kotlin/com/tutpro/baresip/Utils.kt | 61 ++++++++++++++----- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt index 39cc8d28..65cde5b0 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt @@ -880,9 +880,9 @@ class BaresipService: Service() { if (Call.calls().size == 0) { resetCallVolume() Utils.setSpeakerPhone(am, false) + am.mode = AudioManager.MODE_NORMAL am.stopBluetoothSco() abandonAudioFocus() - am.mode = AudioManager.MODE_NORMAL proximitySensing(false) } val missed = call.startTime == null && call.dir == "in" && !call.rejected diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index bbff9c65..d906dcc6 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -1144,12 +1144,12 @@ class MainActivity : AppCompatActivity() { if (acc.missedCalls) callsButton.setImageResource(R.drawable.calls_missed) } - if (speakerIcon != null) { - if (am.isSpeakerphoneOn) + Handler(Looper.getMainLooper()).postDelayed({ + if (Utils.isSpeakerPhoneOn(am)) speakerIcon!!.setIcon(R.drawable.speaker_on) else speakerIcon!!.setIcon(R.drawable.speaker_off) - } + }, 750) if ((Build.VERSION.SDK_INT >= 22 && kgm.isDeviceLocked) || (Build.VERSION.SDK_INT < 22 && kgm.isKeyguardLocked && kgm.isKeyguardSecure)) Utils.setShowWhenLocked(this, false) @@ -1208,7 +1208,7 @@ class MainActivity : AppCompatActivity() { menuInflater.inflate(R.menu.speaker_icon, menu) speakerIcon = menu.findItem(R.id.speakerIcon) - if (am.isSpeakerphoneOn) + if (Utils.isSpeakerPhoneOn(am)) speakerIcon!!.setIcon(R.drawable.speaker_on) else speakerIcon!!.setIcon(R.drawable.speaker_off) @@ -1234,11 +1234,13 @@ class MainActivity : AppCompatActivity() { } R.id.speakerIcon -> { - Utils.setSpeakerPhone(am, !am.isSpeakerphoneOn) - if (am.isSpeakerphoneOn) - item.setIcon(R.drawable.speaker_on) - else - item.setIcon(R.drawable.speaker_off) + Utils.toggleSpeakerPhone(am) + Handler(Looper.getMainLooper()).postDelayed({ + if (Utils.isSpeakerPhoneOn(am)) + item.setIcon(R.drawable.speaker_on) + else + item.setIcon(R.drawable.speaker_off) + }, 750) } R.id.config -> { diff --git a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt index ee400798..fae09532 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt @@ -12,9 +12,6 @@ import android.graphics.Canvas import android.graphics.Color import android.net.Uri import android.net.wifi.WifiManager -import android.os.Build -import android.os.Bundle -import android.os.Environment import android.provider.DocumentsContract import android.provider.MediaStore import android.provider.OpenableColumns @@ -27,6 +24,7 @@ import android.widget.ImageView import android.widget.TextView import android.media.AudioDeviceInfo import android.media.AudioManager +import android.os.* import androidx.activity.result.ActivityResultLauncher import androidx.annotation.RequiresApi import androidx.core.content.ContextCompat @@ -892,11 +890,19 @@ object Utils { return bitmap } - fun setSpeakerPhone(am: AudioManager, state: Boolean) { + fun isSpeakerPhoneOn(am: AudioManager): Boolean { + return if (Build.VERSION.SDK_INT >= 31) + am.communicationDevice!!.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER + else + am.isSpeakerphoneOn + } + + fun setSpeakerPhone(am: AudioManager, enabled: Boolean) { // Currently at API levels 31+, speakerphone cannot be turned on during call - Log.d(TAG, "Speakerphone is ${am.isSpeakerphoneOn}") - if (state) { - if (Build.VERSION.SDK_INT >= 31 && am.mode != AudioManager.MODE_IN_COMMUNICATION) { + if (enabled) { + if (Build.VERSION.SDK_INT >= 31) { + Log.d(TAG, "Setting current device from ${am.communicationDevice!!.type} to " + + "${AudioDeviceInfo.TYPE_BUILTIN_SPEAKER} in mode ${am.mode}") var speakerDevice: AudioDeviceInfo? = null for (device in am.availableCommunicationDevices) if (device.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { @@ -904,20 +910,45 @@ object Utils { break } if (speakerDevice != null) { - if (!am.setCommunicationDevice(speakerDevice)) - Log.e(TAG, "Could not turn on speaker device") + am.mode = AudioManager.MODE_NORMAL + Handler(Looper.getMainLooper()).postDelayed({ + if (!am.setCommunicationDevice(speakerDevice)) + Log.e(TAG, "Could not turn on speaker device") + Log.d(TAG, "Type of current device is ${am.communicationDevice!!.type}") + }, 500) } } else { - if (Build.VERSION.SDK_INT < 31) - am.isSpeakerphoneOn = true + am.isSpeakerphoneOn = true + Log.d(TAG, "Speakerphone is ${am.isSpeakerphoneOn}") } } else { - if (Build.VERSION.SDK_INT >= 31) - am.clearCommunicationDevice() - else + if (Build.VERSION.SDK_INT >= 31) { + Log.d(TAG, "Setting current device from type ${am.communicationDevice!!.type} to " + + "${AudioDeviceInfo.TYPE_BUILTIN_EARPIECE} in mode ${am.mode}") + var earDevice: AudioDeviceInfo? = null + for (device in am.availableCommunicationDevices) + if (device.type == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { + earDevice = device + break + } + if (earDevice != null) { + if (!am.setCommunicationDevice(earDevice)) + Log.e(TAG, "Could not turn on earpiece device") + am.mode = AudioManager.MODE_IN_COMMUNICATION + } + Log.d(TAG, "Type of current device is ${am.communicationDevice!!.type}") + } else { am.isSpeakerphoneOn = false + Log.d(TAG, "Speakerphone is ${am.isSpeakerphoneOn}") + } } - Log.d(TAG, "Speakerphone is ${am.isSpeakerphoneOn}") } + fun toggleSpeakerPhone(am: AudioManager) { + if (Build.VERSION.SDK_INT >= 31) + setSpeakerPhone(am, + am.communicationDevice!!.type == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) + else + setSpeakerPhone(am, !am.isSpeakerphoneOn) + } }