Added cancel button for canceling outgoing call

Fixed showing of call transfer target suggestions
This commit is contained in:
Juha Heinanen
2025-05-03 12:46:16 +03:00
parent 700eec8dbc
commit cdeb19d1c3
2 changed files with 129 additions and 89 deletions
@@ -783,7 +783,6 @@ class BaresipService: Service() {
if (speakerPhone && !Utils.isSpeakerPhoneOn(am)) if (speakerPhone && !Utils.isSpeakerPhoneOn(am))
Utils.toggleSpeakerPhone(ContextCompat.getMainExecutor(this), am) Utils.toggleSpeakerPhone(ContextCompat.getMainExecutor(this), am)
proximitySensing(true) proximitySensing(true)
return
} }
"call ringing" -> { "call ringing" -> {
playRingBack() playRingBack()
@@ -203,6 +203,7 @@ class MainActivity : ComponentActivity() {
private var showCallTimer = mutableStateOf(false) private var showCallTimer = mutableStateOf(false)
private var showSuggestions = mutableStateOf(false) private var showSuggestions = mutableStateOf(false)
private var showCallButton = mutableStateOf(true) private var showCallButton = mutableStateOf(true)
private var showCancelButton = mutableStateOf(false)
private var showAnswerRejectButtons = mutableStateOf(false) private var showAnswerRejectButtons = mutableStateOf(false)
private var showHangupButton = mutableStateOf(false) private var showHangupButton = mutableStateOf(false)
private var showOnHoldNotice = mutableStateOf(false) private var showOnHoldNotice = mutableStateOf(false)
@@ -692,7 +693,8 @@ class MainActivity : ComponentActivity() {
recOffImage recOffImage
} }
} else } else
Toast.makeText(ctx, R.string.rec_in_call, Toast.LENGTH_SHORT).show() Toast.makeText(ctx, R.string.rec_in_call, Toast.LENGTH_SHORT)
.show()
}, },
onLongClick = { onLongClick = {
alertTitle.value = getString(R.string.call_recording_title) alertTitle.value = getString(R.string.call_recording_title)
@@ -708,7 +710,9 @@ class MainActivity : ComponentActivity() {
Icon( Icon(
imageVector = ImageVector.vectorResource(micIcon), imageVector = ImageVector.vectorResource(micIcon),
modifier = Modifier.size(40.dp).combinedClickable( modifier = Modifier
.size(40.dp)
.combinedClickable(
onClick = { onClick = {
if (Call.call("connected") != null) { if (Call.call("connected") != null) {
BaresipService.isMicMuted = !BaresipService.isMicMuted BaresipService.isMicMuted = !BaresipService.isMicMuted
@@ -735,10 +739,13 @@ class MainActivity : ComponentActivity() {
Icon( Icon(
imageVector = ImageVector.vectorResource(speakerIcon), imageVector = ImageVector.vectorResource(speakerIcon),
modifier = Modifier.size(40.dp).combinedClickable( modifier = Modifier
.size(40.dp)
.combinedClickable(
onClick = { onClick = {
if (Build.VERSION.SDK_INT >= 31) if (Build.VERSION.SDK_INT >= 31)
Log.d(TAG, "Toggling speakerphone when dev/mode is " + Log.d(
TAG, "Toggling speakerphone when dev/mode is " +
"${am.communicationDevice!!.type}/${am.mode}" "${am.communicationDevice!!.type}/${am.mode}"
) )
Utils.toggleSpeakerPhone(ContextCompat.getMainExecutor(ctx), am) Utils.toggleSpeakerPhone(ContextCompat.getMainExecutor(ctx), am)
@@ -1054,13 +1061,12 @@ class MainActivity : ComponentActivity() {
colors = OutlinedTextFieldDefaults.colors( colors = OutlinedTextFieldDefaults.colors(
disabledBorderColor = OutlinedTextFieldDefaults.colors().unfocusedIndicatorColor), disabledBorderColor = OutlinedTextFieldDefaults.colors().unfocusedIndicatorColor),
onValueChange = { onValueChange = {
val newValue = it
if (it != callUri.value) { if (it != callUri.value) {
callUri.value = newValue callUri.value = it
showSuggestions.value = newValue.length > 2
filteredSuggestions = suggestions.filter { suggestion -> filteredSuggestions = suggestions.filter { suggestion ->
newValue.length > 2 && suggestion.startsWith(newValue, ignoreCase = true) it.length > 2 && suggestion.startsWith(it, ignoreCase = true)
} }
showSuggestions.value = it.length > 2
} }
}, },
trailingIcon = { trailingIcon = {
@@ -1240,6 +1246,35 @@ class MainActivity : ComponentActivity() {
) )
} }
if (showCancelButton.value) {
Spacer(modifier = Modifier.weight(1f))
IconButton(
modifier = Modifier.size(48.dp),
onClick = {
showSuggestions.value = false
abandonAudioFocus()
var ua: UserAgent = userAgentOfSelectedAor()
val call = ua.currentCall()
if (call != null) {
val callp = call.callp
Log.d(
TAG,
"AoR ${ua.account.aor} hanging up call $callp with ${callUri.value}"
)
Api.ua_hangup(ua.uap, callp, 0, "")
}
},
) {
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.hangup),
modifier = Modifier.size(48.dp),
tint = Color.Unspecified,
contentDescription = null,
)
}
Spacer(modifier = Modifier.width(12.dp))
}
if (showHangupButton.value) { if (showHangupButton.value) {
var ua: UserAgent = userAgentOfSelectedAor() var ua: UserAgent = userAgentOfSelectedAor()
@@ -1248,31 +1283,15 @@ class MainActivity : ComponentActivity() {
IconButton( IconButton(
modifier = Modifier.size(48.dp), modifier = Modifier.size(48.dp),
onClick = { onClick = {
if (Build.VERSION.SDK_INT < 31) { abandonAudioFocus()
if (callRunnable != null) {
callHandler.removeCallbacks(callRunnable!!)
callRunnable = null
BaresipService.abandonAudioFocus(applicationContext)
showCall(ua)
}
} else {
if (audioModeChangedListener != null) {
am.removeOnModeChangedListener(audioModeChangedListener!!)
audioModeChangedListener = null
BaresipService.abandonAudioFocus(applicationContext)
showCall(ua)
}
}
val aor = ua.account.aor
val uaCalls = ua.calls() val uaCalls = ua.calls()
if (uaCalls.isNotEmpty()) { if (uaCalls.isNotEmpty()) {
val call = uaCalls[uaCalls.size - 1] val call = uaCalls.last()
val callp = call.callp val callp = call.callp
Log.d(TAG, "AoR $aor hanging up call $callp with ${callUri.value}") Log.d(TAG, "AoR ${ua.account.aor} hanging up call $callp with ${callUri.value}")
showHangupButton.value = false
Api.ua_hangup(ua.uap, callp, 0, "") Api.ua_hangup(ua.uap, callp, 0, "")
} }
}, }
) { ) {
Icon( Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.hangup), imageVector = ImageVector.vectorResource(id = R.drawable.hangup),
@@ -1360,21 +1379,23 @@ class MainActivity : ComponentActivity() {
var transferUri by remember { mutableStateOf("") } var transferUri by remember { mutableStateOf("") }
val suggestions by remember { contactNames } val suggestions by remember { contactNames }
var filteredSuggestions by remember { mutableStateOf(suggestions) } var filteredSuggestions by remember { mutableStateOf(suggestions) }
var showSuggestions by remember { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
OutlinedTextField( OutlinedTextField(
value = transferUri, value = transferUri,
singleLine = true, singleLine = true,
onValueChange = { onValueChange = {
if (it != transferUri) {
transferUri = it transferUri = it
showSuggestions = transferUri.isNotEmpty() filteredSuggestions =
filteredSuggestions = if (transferUri.isEmpty())
suggestions
else
suggestions.filter { suggestion -> suggestions.filter { suggestion ->
transferUri.length > 2 && transferUri.length > 2 &&
suggestion.startsWith(transferUri, ignoreCase = true) suggestion.startsWith(
transferUri,
ignoreCase = true
)
}
showSuggestions.value = transferUri.length > 2
} }
}, },
trailingIcon = { trailingIcon = {
@@ -1383,8 +1404,10 @@ class MainActivity : ComponentActivity() {
Icons.Outlined.Clear, Icons.Outlined.Clear,
contentDescription = null, contentDescription = null,
modifier = Modifier.clickable { modifier = Modifier.clickable {
if (showSuggestions.value)
showSuggestions.value = false
else
transferUri = "" transferUri = ""
showSuggestions = false
} }
) )
}, },
@@ -1418,10 +1441,10 @@ class MainActivity : ComponentActivity() {
) )
.animateContentSize() .animateContentSize()
) { ) {
if (showSuggestions && filteredSuggestions.isNotEmpty()) { if (showSuggestions.value && filteredSuggestions.isNotEmpty()) {
Box(modifier = Modifier Box(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.heightIn(150.dp)) { .heightIn(max = 150.dp)) {
LazyColumn( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -1441,14 +1464,14 @@ class MainActivity : ComponentActivity() {
.fillMaxWidth() .fillMaxWidth()
.clickable { .clickable {
transferUri = suggestion transferUri = suggestion
showSuggestions = false showSuggestions.value = false
} }
.padding(12.dp) .padding(12.dp)
) { ) {
Text( Text(
text = suggestion, text = suggestion,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
color = LocalCustomColors.current.itemText, color = LocalCustomColors.current.grayDark,
fontSize = 18.sp fontSize = 18.sp
) )
} }
@@ -1459,8 +1482,7 @@ class MainActivity : ComponentActivity() {
} }
if (call.replaces()) if (call.replaces())
Row( Row(
modifier = Modifier modifier = Modifier.fillMaxWidth(),
.fillMaxWidth(),
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
) { ) {
Text( Text(
@@ -1504,7 +1526,7 @@ class MainActivity : ComponentActivity() {
} }
TextButton( TextButton(
onClick = { onClick = {
showSuggestions = false showSuggestions.value = false
var uriText = transferUri.trim() var uriText = transferUri.trim()
if (uriText.isNotEmpty()) { if (uriText.isNotEmpty()) {
val uris = Contact.contactUris(uriText) val uris = Contact.contactUris(uriText)
@@ -1522,14 +1544,13 @@ class MainActivity : ComponentActivity() {
showSelectItemDialog.value = true showSelectItemDialog.value = true
} }
else { else {
if (uris.size == 1) if (uris.size == 1) uriText = uris[0]
uriText = uris[0]
}
transfer( transfer(
ua, ua,
if (Utils.isTelNumber(uriText)) "tel:$uriText" else uriText, if (Utils.isTelNumber(uriText)) "tel:$uriText" else uriText,
!blindChecked.value !blindChecked.value
) )
}
keyboardController?.hide() keyboardController?.hide()
showDialog.value = false showDialog.value = false
showTransferDialog = false showTransferDialog = false
@@ -1757,6 +1778,22 @@ class MainActivity : ComponentActivity() {
} }
} }
private fun runCall(ua: UserAgent, uri: String) {
callRunnable = Runnable {
callRunnable = null
if (!call(ua, uri)) {
BaresipService.abandonAudioFocus(applicationContext)
showCallButton.value = true
showCancelButton.value = false
}
else {
showCallButton.value = false
showCancelButton.value = true
}
}
callHandler.postDelayed(callRunnable!!, BaresipService.audioDelay)
}
private fun answer(ctx: Context) { private fun answer(ctx: Context) {
val ua = UserAgent.ofAor(viewModel.selectedAor.value)!! val ua = UserAgent.ofAor(viewModel.selectedAor.value)!!
val call = ua.currentCall() val call = ua.currentCall()
@@ -2816,22 +2853,6 @@ class MainActivity : ComponentActivity() {
} }
} }
private fun runCall(ua: UserAgent, uri: String) {
callRunnable = Runnable {
callRunnable = null
if (!call(ua, uri)) {
BaresipService.abandonAudioFocus(applicationContext)
showCallButton.value = true
showHangupButton.value = false
}
else {
showCallButton.value = false
showHangupButton.value = true
}
}
callHandler.postDelayed(callRunnable!!, BaresipService.audioDelay)
}
private fun showCall(ua: UserAgent?, showCall: Call? = null) { private fun showCall(ua: UserAgent?, showCall: Call? = null) {
if (ua == null) if (ua == null)
return return
@@ -2852,6 +2873,7 @@ class MainActivity : ComponentActivity() {
dtmfEnabled.value = false dtmfEnabled.value = false
focusDtmf.value = false focusDtmf.value = false
showCallButton.value = true showCallButton.value = true
showCancelButton.value = false
showAnswerRejectButtons.value = false showAnswerRejectButtons.value = false
showOnHoldNotice.value = false showOnHoldNotice.value = false
dialpadButtonEnabled = true dialpadButtonEnabled = true
@@ -2872,7 +2894,8 @@ class MainActivity : ComponentActivity() {
showCallTimer.value = false showCallTimer.value = false
securityIcon.intValue = -1 securityIcon.intValue = -1
showCallButton.value = false showCallButton.value = false
showHangupButton.value = true showCancelButton.value = call.status == "outgoing"
showHangupButton.value = !showCancelButton.value
showAnswerRejectButtons.value = false showAnswerRejectButtons.value = false
showOnHoldNotice.value = false showOnHoldNotice.value = false
dialpadButtonEnabled = false dialpadButtonEnabled = false
@@ -2890,6 +2913,7 @@ class MainActivity : ComponentActivity() {
callUri.value = Utils.friendlyUri(this, call.peerUri, ua.account) callUri.value = Utils.friendlyUri(this, call.peerUri, ua.account)
} }
showCallButton.value = false showCallButton.value = false
showCancelButton.value = false
showHangupButton.value = false showHangupButton.value = false
showAnswerRejectButtons.value = true showAnswerRejectButtons.value = true
showOnHoldNotice.value = false showOnHoldNotice.value = false
@@ -2921,6 +2945,7 @@ class MainActivity : ComponentActivity() {
else else
securityIcon.intValue = call.security securityIcon.intValue = call.security
showCallButton.value = false showCallButton.value = false
showCancelButton.value = false
showHangupButton.value = true showHangupButton.value = true
showAnswerRejectButtons.value = false showAnswerRejectButtons.value = false
if (call.onhold) if (call.onhold)
@@ -3060,6 +3085,22 @@ class MainActivity : ComponentActivity() {
}, 100) }, 100)
} }
private fun abandonAudioFocus() {
if (Build.VERSION.SDK_INT < 31) {
if (callRunnable != null) {
callHandler.removeCallbacks(callRunnable!!)
callRunnable = null
BaresipService.abandonAudioFocus(applicationContext)
}
} else {
if (audioModeChangedListener != null) {
am.removeOnModeChangedListener(audioModeChangedListener!!)
audioModeChangedListener = null
BaresipService.abandonAudioFocus(applicationContext)
}
}
}
companion object { companion object {
var activityAor = "" var activityAor = ""
} }