Always use Android Telecom Framework
Automatically add/remove Mobile account when Default Phone App setting is turned on/off
This commit is contained in:
@ -285,7 +285,7 @@ class Account(val accp: Long, virtualAor: String? = null) {
|
|||||||
BaresipService.filesPath + "/accounts",
|
BaresipService.filesPath + "/accounts",
|
||||||
accounts.toByteArray(Charsets.UTF_8)
|
accounts.toByteArray(Charsets.UTF_8)
|
||||||
)
|
)
|
||||||
Log.d(TAG, "Saved accounts '${accounts}' to '${BaresipService.filesPath}/accounts'")
|
// Log.d(TAG, "Saved accounts '${accounts}' to '${BaresipService.filesPath}/accounts'")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ofAor(aor: String): Account? {
|
fun ofAor(aor: String): Account? {
|
||||||
|
|||||||
@ -1677,7 +1677,7 @@ private fun checkOnClick(ctx: Context, viewModel: AccountViewModel, ua: UserAgen
|
|||||||
|
|
||||||
if (viewModel.defaultAccount.value) ua.makeDefault()
|
if (viewModel.defaultAccount.value) ua.makeDefault()
|
||||||
|
|
||||||
Api.account_debug(acc.accp)
|
// Api.account_debug(acc.accp)
|
||||||
|
|
||||||
Account.saveAccounts()
|
Account.saveAccounts()
|
||||||
|
|
||||||
|
|||||||
@ -164,8 +164,6 @@ private var newOpusPacketLoss = oldOpusPacketLoss
|
|||||||
private var newAudioDelay = BaresipService.audioDelay.toString()
|
private var newAudioDelay = BaresipService.audioDelay.toString()
|
||||||
private var newToneCountry = BaresipService.toneCountry
|
private var newToneCountry = BaresipService.toneCountry
|
||||||
private var newRingtoneUri = ""
|
private var newRingtoneUri = ""
|
||||||
private var oldTelecom = BaresipService.telecom
|
|
||||||
private var newTelecom = oldTelecom
|
|
||||||
|
|
||||||
private var save = false
|
private var save = false
|
||||||
|
|
||||||
@ -178,8 +176,6 @@ private fun AudioContent(contentPadding: PaddingValues) {
|
|||||||
|
|
||||||
oldSpeakerPhone = Config.variable("speaker_phone") == "yes"
|
oldSpeakerPhone = Config.variable("speaker_phone") == "yes"
|
||||||
newSpeakerPhone = oldSpeakerPhone
|
newSpeakerPhone = oldSpeakerPhone
|
||||||
oldTelecom = Config.variable("telecom") == "yes"
|
|
||||||
newTelecom = oldTelecom
|
|
||||||
oldAudioModules = Config.variables("module")
|
oldAudioModules = Config.variables("module")
|
||||||
oldOpusBitrate = Config.variable("opus_bitrate")
|
oldOpusBitrate = Config.variable("opus_bitrate")
|
||||||
oldOpusPacketLoss = Config.variable("opus_packet_loss")
|
oldOpusPacketLoss = Config.variable("opus_packet_loss")
|
||||||
@ -206,7 +202,6 @@ private fun AudioContent(contentPadding: PaddingValues) {
|
|||||||
.verticalScroll(state = scrollState),
|
.verticalScroll(state = scrollState),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
Telecom()
|
|
||||||
Ringtone()
|
Ringtone()
|
||||||
ToneCountry()
|
ToneCountry()
|
||||||
SpeakerPhone()
|
SpeakerPhone()
|
||||||
@ -219,37 +214,6 @@ private fun AudioContent(contentPadding: PaddingValues) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun Telecom() {
|
|
||||||
Row(
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(end = 10.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.Start
|
|
||||||
) {
|
|
||||||
val telecomTitle = stringResource(R.string.telecom)
|
|
||||||
val telecomHelp = stringResource(R.string.telecom_help)
|
|
||||||
Text(text = telecomTitle,
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.clickable {
|
|
||||||
alertTitle.value = telecomTitle
|
|
||||||
alertMessage.value = telecomHelp
|
|
||||||
showAlert.value = true
|
|
||||||
},
|
|
||||||
fontSize = 18.sp)
|
|
||||||
var telecom by remember { mutableStateOf(oldTelecom) }
|
|
||||||
Switch(
|
|
||||||
checked = telecom,
|
|
||||||
onCheckedChange = {
|
|
||||||
telecom = it
|
|
||||||
newTelecom = telecom
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Ringtone() {
|
private fun Ringtone() {
|
||||||
val ringToneTitle = stringResource(R.string.ringtone)
|
val ringToneTitle = stringResource(R.string.ringtone)
|
||||||
@ -629,13 +593,6 @@ private fun checkOnClick(ctx: Context): Result {
|
|||||||
|
|
||||||
var restart = false
|
var restart = false
|
||||||
|
|
||||||
if (newTelecom != oldTelecom) {
|
|
||||||
Config.replaceVariable("telecom", if (newTelecom) "yes" else "no")
|
|
||||||
BaresipService.telecom = newTelecom
|
|
||||||
restart = true
|
|
||||||
save = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Preferences(ctx).ringtoneUri != newRingtoneUri) {
|
if (Preferences(ctx).ringtoneUri != newRingtoneUri) {
|
||||||
Preferences(ctx).ringtoneUri = newRingtoneUri
|
Preferences(ctx).ringtoneUri = newRingtoneUri
|
||||||
BaresipService.rt = RingtoneManager.getRingtone(ctx, newRingtoneUri.toUri())
|
BaresipService.rt = RingtoneManager.getRingtone(ctx, newRingtoneUri.toUri())
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package com.tutpro.baresip
|
package com.tutpro.baresip
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.Manifest.permission.RECORD_AUDIO
|
import android.Manifest.permission.RECORD_AUDIO
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
@ -61,7 +60,6 @@ import androidx.appcompat.app.AppCompatDelegate
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationCompat.MessagingStyle
|
import androidx.core.app.NotificationCompat.MessagingStyle
|
||||||
import androidx.core.app.Person
|
import androidx.core.app.Person
|
||||||
@ -491,18 +489,7 @@ class BaresipService: Service() {
|
|||||||
activeNetwork = cm.activeNetwork
|
activeNetwork = cm.activeNetwork
|
||||||
Log.i(TAG, "Active network: $activeNetwork")
|
Log.i(TAG, "Active network: $activeNetwork")
|
||||||
|
|
||||||
if (telecom)
|
registerPhoneAccount()
|
||||||
registerPhoneAccount()
|
|
||||||
else
|
|
||||||
if (btAdapter != null) {
|
|
||||||
Log.i(TAG, "Registering bluetooth receiver")
|
|
||||||
val filter = IntentFilter()
|
|
||||||
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)
|
|
||||||
filter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)
|
|
||||||
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)
|
|
||||||
this.registerReceiver(bluetoothReceiver, filter)
|
|
||||||
bluetoothReceiverRegistered = true
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "AEC/AGC/NS available = $aecAvailable/$agcAvailable/$nsAvailable")
|
Log.i(TAG, "AEC/AGC/NS available = $aecAvailable/$agcAvailable/$nsAvailable")
|
||||||
|
|
||||||
@ -551,8 +538,6 @@ class BaresipService: Service() {
|
|||||||
setCallVolume()
|
setCallVolume()
|
||||||
proximitySensing(proximitySensing)
|
proximitySensing(proximitySensing)
|
||||||
call?.answer()
|
call?.answer()
|
||||||
if (!telecom)
|
|
||||||
ensureCommunicationMode()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"Call Reject" -> {
|
"Call Reject" -> {
|
||||||
@ -877,12 +862,10 @@ class BaresipService: Service() {
|
|||||||
proximitySensing(proximitySensing)
|
proximitySensing(proximitySensing)
|
||||||
}
|
}
|
||||||
"call ringing" -> {
|
"call ringing" -> {
|
||||||
if (!telecom) ensureCommunicationMode()
|
|
||||||
playRingBack()
|
playRingBack()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
"call progress" -> {
|
"call progress" -> {
|
||||||
if (!telecom) ensureCommunicationMode()
|
|
||||||
if ((ev[1].toInt() and Api.SDP_RECVONLY) != 0)
|
if ((ev[1].toInt() and Api.SDP_RECVONLY) != 0)
|
||||||
stopMediaPlayer()
|
stopMediaPlayer()
|
||||||
else {
|
else {
|
||||||
@ -926,7 +909,6 @@ class BaresipService: Service() {
|
|||||||
)
|
)
|
||||||
if (resourceId != 0) {
|
if (resourceId != 0) {
|
||||||
ensureCommunicationMode()
|
ensureCommunicationMode()
|
||||||
if (!telecom) playUnInterrupted(resourceId, 1)
|
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Callwaiting tone $name.wav not found")
|
Log.e(TAG, "Callwaiting tone $name.wav not found")
|
||||||
}
|
}
|
||||||
@ -946,23 +928,14 @@ class BaresipService: Service() {
|
|||||||
Log.d(TAG, "Incoming call $uap/$callp/$peerUri")
|
Log.d(TAG, "Incoming call $uap/$callp/$peerUri")
|
||||||
if (Call.ofCallp(callp) == null)
|
if (Call.ofCallp(callp) == null)
|
||||||
Call(callp, ua, peerUri, "in", "incoming").add()
|
Call(callp, ua, peerUri, "in", "incoming").add()
|
||||||
if (telecom) {
|
val extras = android.os.Bundle()
|
||||||
val extras = android.os.Bundle()
|
extras.putLong("uap", uap)
|
||||||
extras.putLong("uap", uap)
|
extras.putLong("callp", callp)
|
||||||
extras.putLong("callp", callp)
|
extras.putString("peerUri", peerUri)
|
||||||
extras.putString("peerUri", peerUri)
|
try {
|
||||||
try {
|
tm.addNewIncomingCall(getPhoneAccountHandle(this), extras)
|
||||||
tm.addNewIncomingCall(getPhoneAccountHandle(this), extras)
|
} catch (e: Exception) {
|
||||||
} catch (e: Exception) {
|
Log.e(TAG, "Telecom addNewIncomingCall failed: ${e.message}")
|
||||||
Log.e(TAG, "Telecom addNewIncomingCall failed: ${e.message}")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!requestAudioFocus(applicationContext)) {
|
|
||||||
Log.w(TAG, "Audio focus denied for incoming call")
|
|
||||||
Api.ua_hangup(uap, callp, 486, "Busy Here")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
handleIncomingCall(Call.ofCallp(callp)!!)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1023,12 +996,6 @@ class BaresipService: Service() {
|
|||||||
if (call.state() == Api.CALL_STATE_EARLY) {
|
if (call.state() == Api.CALL_STATE_EARLY) {
|
||||||
if ((ev[1].toInt() and Api.SDP_RECVONLY) != 0)
|
if ((ev[1].toInt() and Api.SDP_RECVONLY) != 0)
|
||||||
stopMediaPlayer()
|
stopMediaPlayer()
|
||||||
else {
|
|
||||||
if (!telecom) {
|
|
||||||
ConnectionService.connections[callp]?.setRinging()
|
|
||||||
playRingBack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (call.status.value == "connected" && !call.held && !call.onhold) {
|
if (call.status.value == "connected" && !call.held && !call.onhold) {
|
||||||
if (call.callOnHold.value || call.showOnHoldNotice.value) {
|
if (call.callOnHold.value || call.showOnHoldNotice.value) {
|
||||||
@ -1160,13 +1127,8 @@ class BaresipService: Service() {
|
|||||||
val tone = ev[2]
|
val tone = ev[2]
|
||||||
if (tone == "busy")
|
if (tone == "busy")
|
||||||
playBusy()
|
playBusy()
|
||||||
else {
|
else
|
||||||
if (!telecom && !Call.inCall())
|
|
||||||
abandonAudioFocus(applicationContext)
|
|
||||||
ensureCommunicationMode()
|
ensureCommunicationMode()
|
||||||
}
|
|
||||||
if (!telecom && !Call.inCall())
|
|
||||||
abandonAudioFocus(applicationContext)
|
|
||||||
if (call.dir == "out")
|
if (call.dir == "out")
|
||||||
call.rejected = call.startTime == null &&
|
call.rejected = call.startTime == null &&
|
||||||
!reason.startsWith("408") &&
|
!reason.startsWith("408") &&
|
||||||
@ -1500,7 +1462,7 @@ class BaresipService: Service() {
|
|||||||
fun started() {
|
fun started() {
|
||||||
Log.d(TAG, "Received 'started' from baresip")
|
Log.d(TAG, "Received 'started' from baresip")
|
||||||
isNativeReady = true
|
isNativeReady = true
|
||||||
if (telecom) addMobileUserAgent()
|
addMobileUserAgent()
|
||||||
Api.net_debug()
|
Api.net_debug()
|
||||||
postServiceEvent(ServiceEvent("started", arrayListOf(callActionUri), System.nanoTime()))
|
postServiceEvent(ServiceEvent("started", arrayListOf(callActionUri), System.nanoTime()))
|
||||||
callActionUri = ""
|
callActionUri = ""
|
||||||
@ -1849,23 +1811,41 @@ class BaresipService: Service() {
|
|||||||
messageUpdate.postValue(System.currentTimeMillis())
|
messageUpdate.postValue(System.currentTimeMillis())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addMobileUserAgent() {
|
fun addMobileUserAgent() {
|
||||||
if (!telecom || Utils.pstnAccountHandle(this) == null) return
|
if (VERSION.SDK_INT < 29) return
|
||||||
|
|
||||||
|
val mobileAccountHandle = Utils.pstnAccountHandle(this)
|
||||||
|
val existingMobileUa = uas.value.find { it.account.isMobile }
|
||||||
|
|
||||||
|
// If mobile account should not exist (role lost or no SIM), remove it if it exists
|
||||||
|
if (mobileAccountHandle == null) {
|
||||||
|
if (existingMobileUa != null) {
|
||||||
|
Log.d(TAG, "Removing Mobile account (role lost or SIM missing)")
|
||||||
|
existingMobileUa.remove()
|
||||||
|
Account.saveAccounts()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val userPart = Utils.getLine1Number(this) ?: "mobile"
|
val userPart = Utils.getLine1Number(this) ?: "mobile"
|
||||||
val mobileAor = "sip:$userPart@pstn"
|
val mobileAor = "sip:$userPart@pstn"
|
||||||
|
|
||||||
val existingMobileUa = uas.value.find { it.account.isMobile }
|
|
||||||
if (existingMobileUa != null) {
|
if (existingMobileUa != null) {
|
||||||
// Replace previous sip:mobile@pstn with real number if available
|
// Update AOR if it previously was sip:mobile@pstn but now a real number
|
||||||
if (existingMobileUa.account.aor == "sip:mobile@pstn" && mobileAor != "sip:mobile@pstn") {
|
if (existingMobileUa.account.aor == "sip:mobile@pstn" && mobileAor != "sip:mobile@pstn") {
|
||||||
val updatedUas = uas.value.toMutableList()
|
Log.d(TAG, "Updating existing Mobile account AOR to $mobileAor")
|
||||||
updatedUas.remove(existingMobileUa)
|
val aorField = Account::class.java.getDeclaredField("aor")
|
||||||
uas.value = updatedUas.toList()
|
aorField.isAccessible = true
|
||||||
} else
|
aorField.set(existingMobileUa.account, mobileAor)
|
||||||
return
|
val luriField = Account::class.java.getDeclaredField("luri")
|
||||||
|
luriField.isAccessible = true
|
||||||
|
luriField.set(existingMobileUa.account, mobileAor)
|
||||||
|
Account.saveAccounts()
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Injecting new virtual Mobile account: $mobileAor")
|
||||||
val account = Account(0L, mobileAor)
|
val account = Account(0L, mobileAor)
|
||||||
account.isMobile = true
|
account.isMobile = true
|
||||||
account.nickName = "Mobile"
|
account.nickName = "Mobile"
|
||||||
@ -2515,7 +2495,6 @@ class BaresipService: Service() {
|
|||||||
var isRecOn = false
|
var isRecOn = false
|
||||||
var toneCountry = "us"
|
var toneCountry = "us"
|
||||||
var proximitySensing = true
|
var proximitySensing = true
|
||||||
var telecom = true
|
|
||||||
|
|
||||||
val uas = mutableStateOf(emptyList<UserAgent>())
|
val uas = mutableStateOf(emptyList<UserAgent>())
|
||||||
val uasStatus = mutableStateOf(emptyMap<String, Int>())
|
val uasStatus = mutableStateOf(emptyMap<String, Int>())
|
||||||
@ -2609,8 +2588,6 @@ class BaresipService: Service() {
|
|||||||
) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
||||||
) {
|
) {
|
||||||
Log.d(TAG, "requestAudioFocus granted")
|
Log.d(TAG, "requestAudioFocus granted")
|
||||||
if (!telecom && isBluetoothHeadsetConnected(ctx))
|
|
||||||
startBluetoothSco(ctx, 250L, 3)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log.w(TAG, "requestAudioFocus denied")
|
Log.w(TAG, "requestAudioFocus denied")
|
||||||
@ -2619,39 +2596,6 @@ class BaresipService: Service() {
|
|||||||
return audioFocusRequest != null
|
return audioFocusRequest != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun abandonAudioFocus(ctx: Context) {
|
|
||||||
val am = ctx.getSystemService(AUDIO_SERVICE) as AudioManager
|
|
||||||
if (audioFocusRequest != null) {
|
|
||||||
Log.d(TAG, "Abandoning audio focus")
|
|
||||||
if (androidx.media.AudioManagerCompat.abandonAudioFocusRequest(
|
|
||||||
am,
|
|
||||||
audioFocusRequest!!
|
|
||||||
) ==
|
|
||||||
AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
|
||||||
) {
|
|
||||||
audioFocusRequest = null
|
|
||||||
if (!telecom && isBluetoothHeadsetConnected(ctx))
|
|
||||||
stopBluetoothSco(ctx)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Log.e(TAG, "Failed to abandon audio focus")
|
|
||||||
}
|
|
||||||
am.mode = MODE_NORMAL
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isBluetoothHeadsetConnected(ctx: Context): Boolean {
|
|
||||||
if (VERSION.SDK_INT >= 31 &&
|
|
||||||
ActivityCompat.checkSelfPermission(
|
|
||||||
ctx,
|
|
||||||
Manifest.permission.BLUETOOTH_CONNECT
|
|
||||||
) == PackageManager.PERMISSION_DENIED
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
return btAdapter != null && btAdapter!!.isEnabled &&
|
|
||||||
btAdapter!!.getProfileConnectionState(BluetoothHeadset.HEADSET) ==
|
|
||||||
BluetoothAdapter.STATE_CONNECTED
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isBluetoothScoOn(am: AudioManager): Boolean {
|
private fun isBluetoothScoOn(am: AudioManager): Boolean {
|
||||||
return if (VERSION.SDK_INT < 31)
|
return if (VERSION.SDK_INT < 31)
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
|||||||
@ -151,15 +151,11 @@ open class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun hangup(code: Int, reason: String) {
|
open fun hangup(code: Int, reason: String) {
|
||||||
if (BaresipService.telecom) {
|
val connection = ConnectionService.connections[callp]
|
||||||
val connection = ConnectionService.connections[callp]
|
if (connection != null)
|
||||||
if (connection != null)
|
connection.onDisconnect()
|
||||||
connection.onDisconnect()
|
else
|
||||||
else
|
|
||||||
Api.ua_hangup(ua.uap, callp, code, reason)
|
|
||||||
} else {
|
|
||||||
Api.ua_hangup(ua.uap, callp, code, reason)
|
Api.ua_hangup(ua.uap, callp, code, reason)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun answer() {
|
open fun answer() {
|
||||||
|
|||||||
@ -226,13 +226,6 @@ object Config {
|
|||||||
BaresipService.toneCountry = toneCountry
|
BaresipService.toneCountry = toneCountry
|
||||||
config = "${config}tone_country ${BaresipService.toneCountry}\n"
|
config = "${config}tone_country ${BaresipService.toneCountry}\n"
|
||||||
|
|
||||||
val telecom = previousVariable("telecom")
|
|
||||||
if (telecom != "")
|
|
||||||
BaresipService.telecom = telecom == "yes"
|
|
||||||
else
|
|
||||||
BaresipService.telecom = true
|
|
||||||
config = "${config}telecom ${if (BaresipService.telecom) "yes" else "no"}\n"
|
|
||||||
|
|
||||||
save()
|
save()
|
||||||
BaresipService.isConfigInitialized = true
|
BaresipService.isConfigInitialized = true
|
||||||
|
|
||||||
|
|||||||
@ -2116,60 +2116,49 @@ private fun makeCall(ctx: Context, viewModel: ViewModel, uriText: String,
|
|||||||
else {
|
else {
|
||||||
viewModel.dialerState.callButtonsEnabled.value = false
|
viewModel.dialerState.callButtonsEnabled.value = false
|
||||||
var error = ""
|
var error = ""
|
||||||
if (BaresipService.telecom) {
|
val tm = ctx.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
|
||||||
val tm = ctx.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
|
if (ua.account.isMobile) {
|
||||||
if (ua.account.isMobile) {
|
val phoneAccountHandle = Utils.pstnAccountHandle(ctx)
|
||||||
val phoneAccountHandle = Utils.pstnAccountHandle(ctx)
|
if (phoneAccountHandle != null) {
|
||||||
if (phoneAccountHandle != null) {
|
val extras = Bundle().apply {
|
||||||
val extras = Bundle().apply {
|
putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle)
|
||||||
putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle)
|
|
||||||
}
|
|
||||||
val callExtras = Bundle()
|
|
||||||
callExtras.putBoolean("pstnCall", true)
|
|
||||||
callExtras.putString("aor", aor)
|
|
||||||
extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, callExtras)
|
|
||||||
try {
|
|
||||||
Log.i(TAG, "Placing Telecom PSTN call to $uri with uap=${ua.uap}")
|
|
||||||
tm.placeCall(uri.toUri(), extras)
|
|
||||||
} catch (e: SecurityException) {
|
|
||||||
error = "placeCall failed: ${e.message}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
error = "no phone account"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val extras = Bundle()
|
|
||||||
extras.putParcelable(
|
|
||||||
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
|
|
||||||
BaresipService.getPhoneAccountHandle(ctx)
|
|
||||||
)
|
|
||||||
val callExtras = Bundle()
|
val callExtras = Bundle()
|
||||||
callExtras.putBoolean("conferenceCall", dialerState.showCallConferenceButton.value)
|
callExtras.putBoolean("pstnCall", true)
|
||||||
callExtras.putLong("uap", ua.uap)
|
callExtras.putString("aor", aor)
|
||||||
if (onHoldCallp != 0L)
|
|
||||||
callExtras.putLong("onHoldCallp", onHoldCallp)
|
|
||||||
extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, callExtras)
|
extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, callExtras)
|
||||||
try {
|
try {
|
||||||
Log.d(TAG, "Placing Telecom SIP call to $uri with uap=${ua.uap}")
|
Log.i(TAG, "Placing Telecom PSTN call to $uri with uap=${ua.uap}")
|
||||||
tm.placeCall(uri.toUri(), extras)
|
tm.placeCall(uri.toUri(), extras)
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
error = "placeCall failed: ${e.message}"
|
error = "placeCall failed: ${e.message}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error != "") {
|
else
|
||||||
Log.e(TAG, error)
|
error = "no phone account"
|
||||||
viewModel.dialerState.callButtonsEnabled.value = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val intent = Intent(ctx, BaresipService::class.java)
|
val extras = Bundle()
|
||||||
intent.action = "Start Call"
|
extras.putParcelable(
|
||||||
intent.putExtra("uap", ua.uap)
|
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
|
||||||
intent.putExtra("uri", uri)
|
BaresipService.getPhoneAccountHandle(ctx)
|
||||||
intent.putExtra("conferenceCall", dialerState.showCallConferenceButton.value)
|
)
|
||||||
intent.putExtra("onHoldCallp", onHoldCallp)
|
val callExtras = Bundle()
|
||||||
ctx.startService(intent)
|
callExtras.putBoolean("conferenceCall", dialerState.showCallConferenceButton.value)
|
||||||
|
callExtras.putLong("uap", ua.uap)
|
||||||
|
if (onHoldCallp != 0L)
|
||||||
|
callExtras.putLong("onHoldCallp", onHoldCallp)
|
||||||
|
extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, callExtras)
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "Placing Telecom SIP call to $uri with uap=${ua.uap}")
|
||||||
|
tm.placeCall(uri.toUri(), extras)
|
||||||
|
} catch (e: SecurityException) {
|
||||||
|
error = "placeCall failed: ${e.message}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (error != "") {
|
||||||
|
Log.e(TAG, error)
|
||||||
|
viewModel.dialerState.callButtonsEnabled.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2392,8 +2381,6 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
|
|||||||
|
|
||||||
when (ev[0]) {
|
when (ev[0]) {
|
||||||
"call rejected" -> {
|
"call rejected" -> {
|
||||||
if (!BaresipService.telecom)
|
|
||||||
BaresipService.abandonAudioFocus(ctx)
|
|
||||||
if (aor == viewModel.selectedAor.value)
|
if (aor == viewModel.selectedAor.value)
|
||||||
viewModel.triggerAccountUpdate()
|
viewModel.triggerAccountUpdate()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,6 +80,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
|
import com.tutpro.baresip.BaresipService.Companion.uas
|
||||||
import com.tutpro.baresip.CustomElements.AlertDialog
|
import com.tutpro.baresip.CustomElements.AlertDialog
|
||||||
import com.tutpro.baresip.CustomElements.verticalScrollbar
|
import com.tutpro.baresip.CustomElements.verticalScrollbar
|
||||||
import com.tutpro.baresip.Utils.copyInputStreamToFile
|
import com.tutpro.baresip.Utils.copyInputStreamToFile
|
||||||
@ -1031,6 +1032,7 @@ private fun SettingsContent(
|
|||||||
) { result ->
|
) { result ->
|
||||||
Log.d(TAG, "dialerRoleRequest result: $result")
|
Log.d(TAG, "dialerRoleRequest result: $result")
|
||||||
viewModel.defaultDialer.value = roleManager.isRoleHeld(RoleManager.ROLE_DIALER)
|
viewModel.defaultDialer.value = roleManager.isRoleHeld(RoleManager.ROLE_DIALER)
|
||||||
|
BaresipService.instance?.addMobileUserAgent()
|
||||||
}
|
}
|
||||||
Switch(
|
Switch(
|
||||||
checked = defaultDialer,
|
checked = defaultDialer,
|
||||||
@ -1181,14 +1183,14 @@ private fun SettingsContent(
|
|||||||
UserAgent()
|
UserAgent()
|
||||||
UniqueContactUri()
|
UniqueContactUri()
|
||||||
AudioSettings(navController)
|
AudioSettings(navController)
|
||||||
|
if (VERSION.SDK_INT >= 29)
|
||||||
|
DefaultDialer()
|
||||||
BatteryOptimizations()
|
BatteryOptimizations()
|
||||||
DarkTheme()
|
DarkTheme()
|
||||||
if (VERSION.SDK_INT >= 31)
|
if (VERSION.SDK_INT >= 31)
|
||||||
DynamicColors()
|
DynamicColors()
|
||||||
ColorBlind()
|
ColorBlind()
|
||||||
ProximitySensing()
|
ProximitySensing()
|
||||||
if (VERSION.SDK_INT >= 29)
|
|
||||||
DefaultDialer()
|
|
||||||
Debug()
|
Debug()
|
||||||
SipTrace()
|
SipTrace()
|
||||||
Reset(onRestartApp)
|
Reset(onRestartApp)
|
||||||
|
|||||||
@ -4,8 +4,10 @@ import android.Manifest
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.KeyguardManager
|
import android.app.KeyguardManager
|
||||||
|
import android.app.role.RoleManager
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Context.ROLE_SERVICE
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
@ -1335,15 +1337,16 @@ object Utils {
|
|||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(29)
|
||||||
fun pstnAccountHandle(ctx: Context): PhoneAccountHandle? {
|
fun pstnAccountHandle(ctx: Context): PhoneAccountHandle? {
|
||||||
|
val roleManager = ctx.getSystemService(ROLE_SERVICE) as RoleManager
|
||||||
if (ctx.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) ==
|
if (ctx.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) ==
|
||||||
PackageManager.PERMISSION_GRANTED) {
|
PackageManager.PERMISSION_GRANTED &&
|
||||||
|
roleManager.isRoleHeld(RoleManager.ROLE_DIALER)) {
|
||||||
val tm = ctx.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
|
val tm = ctx.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
|
||||||
if (Build.VERSION.SDK_INT >= 29) {
|
val preferredHandle: PhoneAccountHandle? = tm.userSelectedOutgoingPhoneAccount
|
||||||
val preferredHandle: PhoneAccountHandle? = tm.userSelectedOutgoingPhoneAccount
|
if (preferredHandle != null)
|
||||||
if (preferredHandle != null)
|
return preferredHandle
|
||||||
return preferredHandle
|
|
||||||
}
|
|
||||||
val baresipHandle = BaresipService.getPhoneAccountHandle(ctx)
|
val baresipHandle = BaresipService.getPhoneAccountHandle(ctx)
|
||||||
val phoneAccounts = tm.callCapablePhoneAccounts.filter { it != baresipHandle }
|
val phoneAccounts = tm.callCapablePhoneAccounts.filter { it != baresipHandle }
|
||||||
return if (phoneAccounts.isNotEmpty())
|
return if (phoneAccounts.isNotEmpty())
|
||||||
|
|||||||
@ -321,8 +321,7 @@
|
|||||||
to standby state.</string>
|
to standby state.</string>
|
||||||
<string name="default_phone_app">Default Phone App</string>
|
<string name="default_phone_app">Default Phone App</string>
|
||||||
<string name="dialer_role_not_available">Dialer role is not available</string>
|
<string name="dialer_role_not_available">Dialer role is not available</string>
|
||||||
<string name="default_phone_app_help">If checked, baresip is the default phone app. Do not check
|
<string name="default_phone_app_help">If checked, baresip is the default phone app.</string>
|
||||||
if your device may need to handle also other than SIP calls or messages.</string>
|
|
||||||
<string name="listen_address">Listen Address</string>
|
<string name="listen_address">Listen Address</string>
|
||||||
<string name="listen_address_help">IP address and port of form \'address:port\' at which baresip listens
|
<string name="listen_address_help">IP address and port of form \'address:port\' at which baresip listens
|
||||||
for incoming SIP requests. If IP address is an IPv6 address, it must be written inside
|
for incoming SIP requests. If IP address is an IPv6 address, it must be written inside
|
||||||
@ -408,9 +407,6 @@
|
|||||||
<string name="colorblind_help">Use colorblind friendly registration status icons</string>
|
<string name="colorblind_help">Use colorblind friendly registration status icons</string>
|
||||||
<string name="proximity_sensing">Proximity Sensing</string>
|
<string name="proximity_sensing">Proximity Sensing</string>
|
||||||
<string name="proximity_sensing_help">If checked, proximity sensing is active during calls.</string>
|
<string name="proximity_sensing_help">If checked, proximity sensing is active during calls.</string>
|
||||||
<string name="telecom">Telecom Framework</string>
|
|
||||||
<string name="telecom_help">Use Android Telecom framework for calls. If you experience audio
|
|
||||||
related issues, try if it helps when you turn Telecom Framework off.</string>
|
|
||||||
<string name="video_size">Video Frame Size</string>
|
<string name="video_size">Video Frame Size</string>
|
||||||
<string name="video_size_help">Size of transmitted video frames (width x height)</string>
|
<string name="video_size_help">Size of transmitted video frames (width x height)</string>
|
||||||
<string name="video_fps">Video Frames Per Second</string>
|
<string name="video_fps">Video Frames Per Second</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user