More speakerphone and call related enhancements for API 31+
This commit is contained in:
@@ -637,8 +637,6 @@ class BaresipService: Service() {
|
|||||||
if (call!!.status == "transferring")
|
if (call!!.status == "transferring")
|
||||||
break
|
break
|
||||||
stopMediaPlayer()
|
stopMediaPlayer()
|
||||||
if (am.mode != AudioManager.MODE_IN_COMMUNICATION)
|
|
||||||
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
|
||||||
requestAudioFocus(AudioAttributes.CONTENT_TYPE_SPEECH)
|
requestAudioFocus(AudioAttributes.CONTENT_TYPE_SPEECH)
|
||||||
setCallVolume()
|
setCallVolume()
|
||||||
proximitySensing(true)
|
proximitySensing(true)
|
||||||
@@ -879,7 +877,6 @@ class BaresipService: Service() {
|
|||||||
call.remove()
|
call.remove()
|
||||||
if (Call.calls().size == 0) {
|
if (Call.calls().size == 0) {
|
||||||
resetCallVolume()
|
resetCallVolume()
|
||||||
Utils.setSpeakerPhone(am, false)
|
|
||||||
am.mode = AudioManager.MODE_NORMAL
|
am.mode = AudioManager.MODE_NORMAL
|
||||||
am.stopBluetoothSco()
|
am.stopBluetoothSco()
|
||||||
abandonAudioFocus()
|
abandonAudioFocus()
|
||||||
|
|||||||
@@ -112,5 +112,11 @@ class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: Str
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun connectedCall(): Call? {
|
||||||
|
for (c in BaresipService.calls.reversed())
|
||||||
|
if (c.status == "connected") return c
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import android.content.*
|
|||||||
import android.content.Intent.ACTION_CALL
|
import android.content.Intent.ACTION_CALL
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.Configuration.ORIENTATION_PORTRAIT
|
import android.content.res.Configuration.ORIENTATION_PORTRAIT
|
||||||
|
import android.media.AudioDeviceInfo
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.*
|
import android.os.*
|
||||||
@@ -85,11 +86,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private lateinit var restoreRequest: ActivityResultLauncher<Intent>
|
private lateinit var restoreRequest: ActivityResultLauncher<Intent>
|
||||||
private lateinit var contactsRequest: ActivityResultLauncher<Intent>
|
private lateinit var contactsRequest: ActivityResultLauncher<Intent>
|
||||||
private lateinit var callsRequest: ActivityResultLauncher<Intent>
|
private lateinit var callsRequest: ActivityResultLauncher<Intent>
|
||||||
|
private lateinit var comDevChangedListener: AudioManager.OnCommunicationDeviceChangedListener
|
||||||
|
|
||||||
private var callHandler: Handler = Handler(Looper.getMainLooper())
|
private var callHandler: Handler = Handler(Looper.getMainLooper())
|
||||||
private var callRunnable: Runnable? = null
|
private var callRunnable: Runnable? = null
|
||||||
private var downloadsInputUri: Uri? = null
|
private var downloadsInputUri: Uri? = null
|
||||||
private var downloadsOutputUri: Uri? = null
|
private var downloadsOutputUri: Uri? = null
|
||||||
|
private var audioModeChangedListener: AudioManager.OnModeChangedListener? = null
|
||||||
|
|
||||||
private lateinit var baresipService: Intent
|
private lateinit var baresipService: Intent
|
||||||
|
|
||||||
@@ -188,6 +191,21 @@ class MainActivity : AppCompatActivity() {
|
|||||||
addAction(Intent.ACTION_SCREEN_ON)
|
addAction(Intent.ACTION_SCREEN_ON)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 31) {
|
||||||
|
comDevChangedListener = AudioManager.OnCommunicationDeviceChangedListener { device ->
|
||||||
|
if (device != null) {
|
||||||
|
Log.d(TAG, "Com device changed to type ${device.type} in mode ${am.mode}")
|
||||||
|
if (speakerIcon != null) {
|
||||||
|
if (device.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER)
|
||||||
|
speakerIcon!!.setIcon(R.drawable.speaker_on)
|
||||||
|
else
|
||||||
|
speakerIcon!!.setIcon(R.drawable.speaker_off)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
am.addOnCommunicationDeviceChangedListener(mainExecutor, comDevChangedListener)
|
||||||
|
}
|
||||||
|
|
||||||
uaAdapter = UaSpinnerAdapter(applicationContext, BaresipService.uas)
|
uaAdapter = UaSpinnerAdapter(applicationContext, BaresipService.uas)
|
||||||
aorSpinner.adapter = uaAdapter
|
aorSpinner.adapter = uaAdapter
|
||||||
aorSpinner.setSelection(-1)
|
aorSpinner.setSelection(-1)
|
||||||
@@ -340,12 +358,22 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
hangupButton.setOnClickListener {
|
hangupButton.setOnClickListener {
|
||||||
val ua = BaresipService.uas[aorSpinner.selectedItemPosition]
|
val ua = BaresipService.uas[aorSpinner.selectedItemPosition]
|
||||||
if (callRunnable != null && callHandler.hasCallbacks(callRunnable!!)) {
|
if (Build.VERSION.SDK_INT < 31) {
|
||||||
callHandler.removeCallbacks(callRunnable!!)
|
if (callRunnable != null && callHandler.hasCallbacks(callRunnable!!)) {
|
||||||
callRunnable = null
|
callHandler.removeCallbacks(callRunnable!!)
|
||||||
am.mode = AudioManager.MODE_NORMAL
|
callRunnable = null
|
||||||
showCall(ua)
|
am.mode = AudioManager.MODE_NORMAL
|
||||||
return@setOnClickListener
|
showCall(ua)
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (audioModeChangedListener != null) {
|
||||||
|
am.removeOnModeChangedListener(audioModeChangedListener!!)
|
||||||
|
audioModeChangedListener = null
|
||||||
|
am.mode = AudioManager.MODE_NORMAL
|
||||||
|
showCall(ua)
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val aor = ua.account.aor
|
val aor = ua.account.aor
|
||||||
val uaCalls = ua.calls()
|
val uaCalls = ua.calls()
|
||||||
@@ -744,6 +772,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
Log.d(TAG, "Main onDestroy")
|
Log.d(TAG, "Main onDestroy")
|
||||||
this.unregisterReceiver(screenEventReceiver)
|
this.unregisterReceiver(screenEventReceiver)
|
||||||
|
if (Build.VERSION.SDK_INT >= 31)
|
||||||
|
am.removeOnCommunicationDeviceChangedListener(comDevChangedListener)
|
||||||
BaresipService.serviceEvent.removeObserver(serviceEventObserver)
|
BaresipService.serviceEvent.removeObserver(serviceEventObserver)
|
||||||
BaresipService.serviceEvents.clear()
|
BaresipService.serviceEvents.clear()
|
||||||
BaresipService.activities.clear()
|
BaresipService.activities.clear()
|
||||||
@@ -1234,13 +1264,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.speakerIcon -> {
|
R.id.speakerIcon -> {
|
||||||
Utils.toggleSpeakerPhone(am)
|
Utils.toggleSpeakerPhone(mainExecutor, 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 -> {
|
R.id.config -> {
|
||||||
@@ -1783,21 +1807,46 @@ class MainActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
callUri.isFocusable = false
|
callUri.isFocusable = false
|
||||||
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
|
||||||
uaAdapter.notifyDataSetChanged()
|
uaAdapter.notifyDataSetChanged()
|
||||||
callButton.visibility = View.INVISIBLE
|
callButton.visibility = View.INVISIBLE
|
||||||
callButton.isEnabled = false
|
callButton.isEnabled = false
|
||||||
hangupButton.visibility = View.VISIBLE
|
hangupButton.visibility = View.VISIBLE
|
||||||
hangupButton.isEnabled = true
|
hangupButton.isEnabled = true
|
||||||
callRunnable = Runnable {
|
if (Build.VERSION.SDK_INT < 31) {
|
||||||
if (!call(ua, uri)) {
|
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||||
callButton.visibility = View.VISIBLE
|
callRunnable = Runnable {
|
||||||
callButton.isEnabled = true
|
if (!call(ua, uri)) {
|
||||||
hangupButton.visibility = View.INVISIBLE
|
callButton.visibility = View.VISIBLE
|
||||||
hangupButton.isEnabled = false
|
callButton.isEnabled = true
|
||||||
|
hangupButton.visibility = View.INVISIBLE
|
||||||
|
hangupButton.isEnabled = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
callHandler.postDelayed(callRunnable!!, 1000)
|
||||||
|
} else {
|
||||||
|
audioModeChangedListener = AudioManager.OnModeChangedListener { mode ->
|
||||||
|
if (mode == AudioManager.MODE_IN_COMMUNICATION) {
|
||||||
|
Log.d(TAG, "Audio mode changed to MODE_IN_COMMUNICATION using " +
|
||||||
|
"device ${am.communicationDevice!!.type}")
|
||||||
|
if (audioModeChangedListener != null) {
|
||||||
|
am.removeOnModeChangedListener(audioModeChangedListener!!)
|
||||||
|
audioModeChangedListener = null
|
||||||
|
}
|
||||||
|
if (!call(ua, uri)) {
|
||||||
|
callButton.visibility = View.VISIBLE
|
||||||
|
callButton.isEnabled = true
|
||||||
|
hangupButton.visibility = View.INVISIBLE
|
||||||
|
hangupButton.isEnabled = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Audio mode changed to MODE_NORMAL using " +
|
||||||
|
"device ${am.communicationDevice!!.type}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
am.addOnModeChangedListener(mainExecutor, audioModeChangedListener!!)
|
||||||
|
Log.d(TAG, "Setting audio mode to MODE_IN_COMMUNICATION")
|
||||||
|
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||||
}
|
}
|
||||||
callHandler.postDelayed(callRunnable!!, 1000)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val latestPeerUri = NewCallHistory.aorLatestPeerUri(aor)
|
val latestPeerUri = NewCallHistory.aorLatestPeerUri(aor)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import java.net.SocketException
|
|||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.Executor
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipFile
|
import java.util.zip.ZipFile
|
||||||
import java.util.zip.ZipOutputStream
|
import java.util.zip.ZipOutputStream
|
||||||
@@ -897,9 +898,10 @@ object Utils {
|
|||||||
am.isSpeakerphoneOn
|
am.isSpeakerphoneOn
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSpeakerPhone(am: AudioManager, enabled: Boolean) {
|
private fun setSpeakerPhone(executor: Executor, am: AudioManager, enable: Boolean) {
|
||||||
// Currently at API levels 31+, speakerphone cannot be turned on during call
|
if (enable == isSpeakerPhoneOn(am))
|
||||||
if (enabled) {
|
return
|
||||||
|
if (enable) {
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= 31) {
|
||||||
Log.d(TAG, "Setting current device from ${am.communicationDevice!!.type} to " +
|
Log.d(TAG, "Setting current device from ${am.communicationDevice!!.type} to " +
|
||||||
"${AudioDeviceInfo.TYPE_BUILTIN_SPEAKER} in mode ${am.mode}")
|
"${AudioDeviceInfo.TYPE_BUILTIN_SPEAKER} in mode ${am.mode}")
|
||||||
@@ -910,12 +912,25 @@ object Utils {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (speakerDevice != null) {
|
if (speakerDevice != null) {
|
||||||
am.mode = AudioManager.MODE_NORMAL
|
if (am.mode == AudioManager.MODE_NORMAL) {
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
|
||||||
if (!am.setCommunicationDevice(speakerDevice))
|
if (!am.setCommunicationDevice(speakerDevice))
|
||||||
Log.e(TAG, "Could not turn on speaker device")
|
Log.e(TAG, "Could not turn on speaker device")
|
||||||
Log.d(TAG, "Type of current device is ${am.communicationDevice!!.type}")
|
Log.d(TAG, "Type of current device is ${am.communicationDevice!!.type}")
|
||||||
}, 500)
|
} else {
|
||||||
|
// Currently at API levels 31+, speakerphone needs to be turned on in normal mode
|
||||||
|
val normalListener = object : AudioManager.OnModeChangedListener {
|
||||||
|
override fun onModeChanged(mode: Int) {
|
||||||
|
if (mode == AudioManager.MODE_NORMAL) {
|
||||||
|
am.removeOnModeChangedListener(this)
|
||||||
|
if (!am.setCommunicationDevice(speakerDevice))
|
||||||
|
Log.e(TAG, "Could not turn on speaker device")
|
||||||
|
Log.d(TAG, "Type of current device is ${am.communicationDevice!!.type}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
am.addOnModeChangedListener(executor, normalListener)
|
||||||
|
am.mode = AudioManager.MODE_NORMAL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
am.isSpeakerphoneOn = true
|
am.isSpeakerphoneOn = true
|
||||||
@@ -925,17 +940,10 @@ object Utils {
|
|||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= 31) {
|
||||||
Log.d(TAG, "Setting current device from type ${am.communicationDevice!!.type} to " +
|
Log.d(TAG, "Setting current device from type ${am.communicationDevice!!.type} to " +
|
||||||
"${AudioDeviceInfo.TYPE_BUILTIN_EARPIECE} in mode ${am.mode}")
|
"${AudioDeviceInfo.TYPE_BUILTIN_EARPIECE} in mode ${am.mode}")
|
||||||
var earDevice: AudioDeviceInfo? = null
|
am.clearCommunicationDevice()
|
||||||
for (device in am.availableCommunicationDevices)
|
// Restore communication mode
|
||||||
if (device.type == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) {
|
if (Call.connectedCall() != null && am.mode == AudioManager.MODE_NORMAL)
|
||||||
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
|
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||||
}
|
|
||||||
Log.d(TAG, "Type of current device is ${am.communicationDevice!!.type}")
|
Log.d(TAG, "Type of current device is ${am.communicationDevice!!.type}")
|
||||||
} else {
|
} else {
|
||||||
am.isSpeakerphoneOn = false
|
am.isSpeakerphoneOn = false
|
||||||
@@ -944,11 +952,11 @@ object Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleSpeakerPhone(am: AudioManager) {
|
fun toggleSpeakerPhone(executor: Executor, am: AudioManager) {
|
||||||
if (Build.VERSION.SDK_INT >= 31)
|
if (Build.VERSION.SDK_INT >= 31)
|
||||||
setSpeakerPhone(am,
|
setSpeakerPhone(executor, am,
|
||||||
am.communicationDevice!!.type == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE)
|
am.communicationDevice!!.type == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE)
|
||||||
else
|
else
|
||||||
setSpeakerPhone(am, !am.isSpeakerphoneOn)
|
setSpeakerPhone(executor, am, !am.isSpeakerphoneOn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user