Finalized USSD implementation

This commit is contained in:
Juha Heinanen
2026-06-28 17:26:10 +03:00
parent b8b5dc816a
commit a5985e2cf6
5 changed files with 59 additions and 42 deletions

View File

@ -2321,41 +2321,37 @@ class BaresipService: Service() {
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
private fun sendUssd(ussdCode: String) { private fun sendUssd(ussdCode: String) {
val uap = uas.value.find { it.account.isMobile }?.uap ?: 0L val uap = uas.value.find { it.account.isMobile }?.uap ?: 0L
if (VERSION.SDK_INT >= 26) { val tm = getSystemService(TELEPHONY_SERVICE) as TelephonyManager
val tm = getSystemService(TELEPHONY_SERVICE) as TelephonyManager try {
try { tm.sendUssdRequest(ussdCode, object : TelephonyManager.UssdResponseCallback() {
tm.sendUssdRequest(ussdCode, object : TelephonyManager.UssdResponseCallback() { override fun onReceiveUssdResponse(
override fun onReceiveUssdResponse( telephonyManager: TelephonyManager,
telephonyManager: TelephonyManager, request: String,
request: String, response: CharSequence
response: CharSequence ) {
) { super.onReceiveUssdResponse(telephonyManager, request, response)
super.onReceiveUssdResponse(telephonyManager, request, response) Log.d(TAG, "USSD response for $request: $response")
Log.d(TAG, "USSD response for $request: $response") postServiceEvent(ServiceEvent("ussd response", arrayListOf(uap, request, response.toString()), System.nanoTime()))
postServiceEvent(ServiceEvent("ussd response", arrayListOf(uap, request, response.toString()), System.nanoTime())) }
}
override fun onReceiveUssdResponseFailed( override fun onReceiveUssdResponseFailed(
telephonyManager: TelephonyManager, telephonyManager: TelephonyManager,
request: String, request: String,
failureCode: Int failureCode: Int
) { ) {
super.onReceiveUssdResponseFailed(telephonyManager, request, failureCode) super.onReceiveUssdResponseFailed(telephonyManager, request, failureCode)
Log.d(TAG, "USSD response for $request failed with code $failureCode") Log.d(TAG, "USSD response for $request failed with code $failureCode")
val error = when (failureCode) { val error = when (failureCode) {
TelephonyManager.USSD_RETURN_FAILURE -> getString(R.string.ussd_failed) TelephonyManager.USSD_RETURN_FAILURE -> getString(R.string.ussd_failed)
TelephonyManager.USSD_ERROR_SERVICE_UNAVAIL -> getString(R.string.ussd_service_unavailable) TelephonyManager.USSD_ERROR_SERVICE_UNAVAIL -> getString(R.string.ussd_service_unavailable)
else -> getString(R.string.ussd_unknown_error) else -> getString(R.string.ussd_unknown_error)
}
postServiceEvent(ServiceEvent("ussd fail", arrayListOf(uap, request, error), System.nanoTime()))
} }
}, Handler(Looper.getMainLooper())) postServiceEvent(ServiceEvent("ussd fail", arrayListOf(uap, request, error), System.nanoTime()))
} catch (e: Exception) { }
Log.e(TAG, "Exception sending USSD request: ${e.message}") }, Handler(Looper.getMainLooper()))
toast(getString(R.string.ussd_failed)) } catch (e: Exception) {
} Log.e(TAG, "Exception sending USSD request: ${e.message}")
} else { toast(getString(R.string.ussd_failed))
toast(getString(R.string.ussd_not_supported))
} }
} }
@ -3128,7 +3124,8 @@ class BaresipService: Service() {
if (serviceEvents.size == 1) { if (serviceEvents.size == 1) {
Log.d(TAG, "Posted service event ${event.event} at ${event.timeStamp}") Log.d(TAG, "Posted service event ${event.event} at ${event.timeStamp}")
serviceEvent.postValue(Event(event.timeStamp)) serviceEvent.postValue(Event(event.timeStamp))
} else }
else
Log.d(TAG, "Added service event ${event.event}") Log.d(TAG, "Added service event ${event.event}")
} }
} }

View File

@ -165,6 +165,7 @@ import kotlinx.coroutines.delay
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.GregorianCalendar
import java.util.Locale import java.util.Locale
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
@ -1533,7 +1534,8 @@ private fun CallRow(
if (call.callOnHold.value) { if (call.callOnHold.value) {
Log.d(TAG, "User requested resume for ${call.callp}") Log.d(TAG, "User requested resume for ${call.callp}")
call.resume() // This now automatically holds other calls call.resume() // This now automatically holds other calls
} else { }
else {
Log.d(TAG, "User requested hold for ${call.callp}") Log.d(TAG, "User requested hold for ${call.callp}")
call.hold() call.hold()
} }
@ -2249,11 +2251,13 @@ private fun showCall(ctx: Context, viewModel: ViewModel, ua: UserAgent?, showCal
call.callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots) call.callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots)
call.callUri.value = Utils.friendlyUri(ctx, call.referTo, ua.account) call.callUri.value = Utils.friendlyUri(ctx, call.referTo, ua.account)
call.transferButtonEnabled.value = false call.transferButtonEnabled.value = false
} else { }
else {
if (call.dir == "out") { if (call.dir == "out") {
call.callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots) call.callUriLabel.value = ctx.getString(R.string.outgoing_call_to_dots)
call.callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account) call.callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
} else { }
else {
call.callUriLabel.value = ctx.getString(R.string.incoming_call_from_dots) call.callUriLabel.value = ctx.getString(R.string.incoming_call_from_dots)
call.callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account) call.callUri.value = Utils.friendlyUri(ctx, call.peerUri, ua.account)
} }
@ -2339,15 +2343,29 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
when (ev[0]) { when (ev[0]) {
"ussd response" -> { "ussd response" -> {
if (aor == viewModel.selectedAor.value) if (aor == viewModel.selectedAor.value) {
viewModel.dialerState.callButtonsEnabled.value = true viewModel.dialerState.callButtonsEnabled.value = true
viewModel.dialerState.callUri.value = ""
}
if (acc.callHistory) {
val history = CallHistoryNew(aor, "tel:" + (params[1] as String), "out")
history.startTime = GregorianCalendar()
history.add()
}
handleDialog(ctx, ctx.getString(R.string.info), params[2] as String) handleDialog(ctx, ctx.getString(R.string.info), params[2] as String)
handleNextEvent() handleNextEvent()
return return
} }
"ussd fail" -> { "ussd fail" -> {
if (aor == viewModel.selectedAor.value) if (aor == viewModel.selectedAor.value) {
viewModel.dialerState.callButtonsEnabled.value = true viewModel.dialerState.callButtonsEnabled.value = true
viewModel.dialerState.callUri.value = ""
}
if (acc.callHistory) {
val history = CallHistoryNew(aor, "tel:" + (params[1] as String), "out")
history.rejected = true
history.add()
}
handleDialog(ctx, ctx.getString(R.string.error), params[2] as String) handleDialog(ctx, ctx.getString(R.string.error), params[2] as String)
handleNextEvent() handleNextEvent()
return return

View File

@ -198,7 +198,7 @@ object Utils {
fun e164Uri(uri: String, countryCode: String): String { fun e164Uri(uri: String, countryCode: String): String {
val scheme = uri.take(4) val scheme = uri.take(4)
val userPart = uriUserPart(uri) val userPart = uriUserPart(uri)
return if (userPart.isDigitsOnly()) { return if (userPart.isNotEmpty() && userPart.isDigitsOnly()) {
when { when {
userPart.startsWith("00") -> uri.replace("$scheme$userPart", userPart.startsWith("00") -> uri.replace("$scheme$userPart",
scheme + "+" + userPart.substring(2)) scheme + "+" + userPart.substring(2))

View File

@ -647,6 +647,9 @@
<string name="call_details">Puhelutiedot</string> <string name="call_details">Puhelutiedot</string>
<string name="no_android_contacts">Et voi käyttää Androidin yhteystietoja ilman Yhteystiedot-lupaa.</string> <string name="no_android_contacts">Et voi käyttää Androidin yhteystietoja ilman Yhteystiedot-lupaa.</string>
<string name="audio_focus_denied">Audiofokus on evätty!</string> <string name="audio_focus_denied">Audiofokus on evätty!</string>
<string name="ussd_failed">USSD-pyyntö epäonnistui</string>
<string name="ussd_service_unavailable">USSD-palvelu ei ole käytettävissä</string>
<string name="ussd_unknown_error">Tuntematon USSD-virhe</string>
<string name="permissions_rationale">Tarvittavat luvat</string> <string name="permissions_rationale">Tarvittavat luvat</string>
<string name="audio_permissions">baresip tarvitsee Mikrofoni-luvan puheluita varten, Lähellä olevat laitteet -luvan <string name="audio_permissions">baresip tarvitsee Mikrofoni-luvan puheluita varten, Lähellä olevat laitteet -luvan
Bluetooth-mikrofonin/kaiuttimen havaitsemista varten, Ilmoitukset-luvan ilmoitusten lähettämistä varten Bluetooth-mikrofonin/kaiuttimen havaitsemista varten, Ilmoitukset-luvan ilmoitusten lähettämistä varten

View File

@ -633,10 +633,9 @@
<string name="no_network">No network connection!</string> <string name="no_network">No network connection!</string>
<string name="no_aec">No hardware Acoustic Echo Cancellation!</string> <string name="no_aec">No hardware Acoustic Echo Cancellation!</string>
<string name="audio_focus_denied">Audio focus denied!</string> <string name="audio_focus_denied">Audio focus denied!</string>
<string name="ussd_failed">USSD failed</string> <string name="ussd_failed">USSD request failed</string>
<string name="ussd_service_unavailable">USSD service unavailable</string> <string name="ussd_service_unavailable">USSD service unavailable</string>
<string name="ussd_unknown_error">USSD unknown error</string> <string name="ussd_unknown_error">USSD unknown error</string>
<string name="ussd_not_supported">USSD not supported</string>
<string name="permissions_rationale">Permissions rationale</string> <string name="permissions_rationale">Permissions rationale</string>
<string name="audio_permissions">baresip needs \"Microphone\" permission for voice calls, <string name="audio_permissions">baresip needs \"Microphone\" permission for voice calls,
\"Nearby devices\" permission for Bluetooth microphone/speaker detection, \"Nearby devices\" permission for Bluetooth microphone/speaker detection,