From 91b04ef221bed2e3c0696a0efe7b06a4606449e8 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sun, 7 May 2023 14:17:23 +0300 Subject: [PATCH 1/7] Allow selecting baresip as the default Phone app --- app/src/main/AndroidManifest.xml | 48 +++++++++-- .../com/tutpro/baresip/ConfigActivity.kt | 49 +++++++++-- .../kotlin/com/tutpro/baresip/MainActivity.kt | 19 +++-- app/src/main/res/layout/activity_config.xml | 81 ++++++++++++------- app/src/main/res/values/strings.xml | 4 + 5 files changed, 156 insertions(+), 45 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 176bd86c..f62d3ba9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + xmlns:tools="http://schemas.android.com/tools" > @@ -15,8 +15,7 @@ - @@ -44,6 +43,7 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:remove="android:appComponentFactory" > + + + + + + @@ -63,26 +68,29 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + tools:ignore="ExportedReceiver" > @@ -173,4 +209,4 @@ - + \ No newline at end of file diff --git a/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt index 8176cfb7..af2e345f 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt @@ -2,6 +2,7 @@ package com.tutpro.baresip import android.Manifest import android.app.Activity +import android.app.role.RoleManager import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent @@ -21,6 +22,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat +import androidx.transition.Visibility import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.tutpro.baresip.Utils.copyInputStreamToFile @@ -36,7 +38,6 @@ class ConfigActivity : AppCompatActivity() { private lateinit var layout: ScrollView private lateinit var baresipService: Intent private lateinit var autoStart: CheckBox - private lateinit var batteryOptimizations: CheckBox private lateinit var listenAddr: EditText private lateinit var netAfSpinner: Spinner private lateinit var netAf: String @@ -49,6 +50,8 @@ class ConfigActivity : AppCompatActivity() { private lateinit var contactsSpinner: Spinner private lateinit var contactsMode: String private lateinit var contactsModeKeys: ArrayList + private lateinit var batteryOptimizations: CheckBox + private lateinit var defaultDialer: CheckBox private lateinit var debug: CheckBox private lateinit var sipTrace: CheckBox private lateinit var reset: CheckBox @@ -74,6 +77,7 @@ class ConfigActivity : AppCompatActivity() { goBack() } } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -109,6 +113,37 @@ class ConfigActivity : AppCompatActivity() { } } + if (Build.VERSION.SDK_INT >= 29) { + val roleManager = getSystemService(ROLE_SERVICE) as RoleManager + defaultDialer = binding.DefaultPhoneApp + defaultDialer.isChecked = roleManager.isRoleHeld(RoleManager.ROLE_DIALER) + val dialerRoleRequest = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { + Log.d(TAG, "dialerRoleRequest succeeded: ${it.resultCode == Activity.RESULT_OK}") + defaultDialer.isChecked = roleManager.isRoleHeld(RoleManager.ROLE_DIALER) + } + defaultDialer.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + if (!roleManager.isRoleAvailable(RoleManager.ROLE_DIALER)) + Utils.alertView(this, getString(R.string.notice), + getString(R.string.dialer_role_not_available)) + else + if (!roleManager.isRoleHeld(RoleManager.ROLE_DIALER)) + dialerRoleRequest.launch(roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER)) + } else { + try { + dialerRoleRequest.launch(Intent("android.settings.MANAGE_DEFAULT_APPS_SETTINGS")) + } catch (e: ActivityNotFoundException) { + Log.e(TAG, "ActivityNotFound exception: $e") + + } + } + } + } else { + binding.PhoneApp.visibility = View.GONE + } + listenAddr = binding.ListenAddress val laCv = Config.variable("sip_listen") oldListenAddr = if (laCv.size == 0) "" else laCv[0] @@ -642,10 +677,6 @@ class ConfigActivity : AppCompatActivity() { Utils.alertView(this, getString(R.string.start_automatically), getString(R.string.start_automatically_help)) } - binding.BatteryOptimizationsTitle.setOnClickListener { - Utils.alertView(this, getString(R.string.battery_optimizations), - getString(R.string.battery_optimizations_help)) - } binding.ListenAddressTitle.setOnClickListener { Utils.alertView(this, getString(R.string.listen_address), getString(R.string.listen_address_help)) @@ -681,6 +712,14 @@ class ConfigActivity : AppCompatActivity() { Utils.alertView(this, getString(R.string.contacts), getString(R.string.contacts_help)) } + binding.BatteryOptimizationsTitle.setOnClickListener { + Utils.alertView(this, getString(R.string.battery_optimizations), + getString(R.string.battery_optimizations_help)) + } + binding.DefaultPhoneAppTitle.setOnClickListener { + Utils.alertView(this, getString(R.string.default_phone_app), + getString(R.string.default_phone_app_help)) + } binding.DebugTitle.setOnClickListener { Utils.alertView(this, getString(R.string.debug), getString(R.string.debug_help)) } diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index 3658fdf9..cc7759cb 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -9,6 +9,7 @@ import android.app.NotificationManager import android.content.* import android.content.Intent.ACTION_CALL import android.content.Intent.ACTION_DIAL +import android.content.Intent.ACTION_VIEW import android.content.pm.PackageManager import android.content.res.Configuration.ORIENTATION_PORTRAIT import android.media.AudioManager @@ -40,6 +41,7 @@ import java.io.File import java.net.URLDecoder import kotlin.system.exitProcess + class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding @@ -653,11 +655,14 @@ class MainActivity : AppCompatActivity() { atStartup = intent.hasExtra("onStartup") - if (intent?.action == ACTION_CALL || intent?.action == ACTION_DIAL) { - if (BaresipService.isServiceRunning) - callAction(intent) - else - BaresipService.callActionUri = URLDecoder.decode(intent.data.toString(), "UTF-8") + when (intent?.action) { + ACTION_DIAL, ACTION_CALL, ACTION_VIEW -> + if (BaresipService.isServiceRunning) + callAction(intent) + else + BaresipService.callActionUri = URLDecoder.decode(intent.data.toString(), "UTF-8") + else -> + Log.d(TAG, "Unknown startup action ${intent?.action}") } permissions = if (Build.VERSION.SDK_INT >= 33) @@ -824,10 +829,10 @@ class MainActivity : AppCompatActivity() { resumeAction = "" resumeUri = "" - Log.d(TAG, "onNewIntent with intent.action '${intent.action}'") + Log.d(TAG, "onNewIntent with action/data '${intent.action}/${intent.data}'") when (intent.action) { - ACTION_DIAL, ACTION_CALL -> { + ACTION_DIAL, ACTION_CALL, ACTION_VIEW -> { callAction(intent) } else -> { diff --git a/app/src/main/res/layout/activity_config.xml b/app/src/main/res/layout/activity_config.xml index 5e40dc1c..85c2ffd1 100644 --- a/app/src/main/res/layout/activity_config.xml +++ b/app/src/main/res/layout/activity_config.xml @@ -41,33 +41,6 @@ - - - - - - - + + + + + + + + + + + + + + Disable battery optimizations (recommended) if you want to reduce likelihood that Android restricts baresip\'s access to network or enters baresip to standby state. + Default Phone App + Dialer role is not available + If checked, baresip is the default phone app. Only choose + if your device never makes or receives calls or messages from telecom (cellular) network. Listen Address 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 From 2edbddb16ea7ab86ef51649da899e8c9888fdf3a Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sun, 7 May 2023 14:19:53 +0300 Subject: [PATCH 2/7] Added InCallService --- .../main/java/com/tutpro/baresip/InCallService.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/src/main/java/com/tutpro/baresip/InCallService.kt diff --git a/app/src/main/java/com/tutpro/baresip/InCallService.kt b/app/src/main/java/com/tutpro/baresip/InCallService.kt new file mode 100644 index 00000000..fd31969e --- /dev/null +++ b/app/src/main/java/com/tutpro/baresip/InCallService.kt @@ -0,0 +1,14 @@ +package com.tutpro.baresip + +import android.app.Service +import android.content.Intent +import android.os.IBinder + +// This is needed in order to allow choosing baresip as default Phone app + +class InCallService : Service() { + + override fun onBind(intent: Intent): IBinder { + TODO("Return the communication channel to the service.") + } +} \ No newline at end of file From bf2ba08b3797fb893b2862edf6a3c89e8b46d5e7 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sun, 7 May 2023 17:21:45 +0300 Subject: [PATCH 3/7] Include tel_provider to account extra even if it is empty --- app/src/main/kotlin/com/tutpro/baresip/Account.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/Account.kt b/app/src/main/kotlin/com/tutpro/baresip/Account.kt index 1eb29d98..ee8c08b0 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Account.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Account.kt @@ -142,8 +142,7 @@ class Account(val accp: Long) { if (!callHistory) extra += ";call_history=no" - if (telProvider != "") - extra += ";tel_provider=${URLEncoder.encode(telProvider, "UTF-8")}" + extra += ";tel_provider=${URLEncoder.encode(telProvider, "UTF-8")}" if (countryCode != "") extra += ";country_code=$countryCode" From a7ebbb30b2a5796b55859a037d531db3f6b2b7b9 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sun, 7 May 2023 17:23:47 +0300 Subject: [PATCH 4/7] Separate CALL and DIAL actions Do not decode CALL or DIAL URI (decode raplaces + with space) --- .../kotlin/com/tutpro/baresip/MainActivity.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index cc7759cb..d1a7a114 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -658,11 +658,9 @@ class MainActivity : AppCompatActivity() { when (intent?.action) { ACTION_DIAL, ACTION_CALL, ACTION_VIEW -> if (BaresipService.isServiceRunning) - callAction(intent) + callAction(intent, if (intent?.action == ACTION_CALL) "call" else "dial") else BaresipService.callActionUri = URLDecoder.decode(intent.data.toString(), "UTF-8") - else -> - Log.d(TAG, "Unknown startup action ${intent?.action}") } permissions = if (Build.VERSION.SDK_INT >= 33) @@ -761,6 +759,9 @@ class MainActivity : AppCompatActivity() { callUri.setText(BaresipService.uas[aorSpinner.selectedItemPosition].account.resumeUri) callButton.performClick() } + "dial" -> { + callUri.setText(BaresipService.uas[aorSpinner.selectedItemPosition].account.resumeUri) + } "call transfer", "transfer show", "transfer accept" -> handleServiceEvent("$resumeAction,$resumeUri", arrayListOf(resumeCall!!.ua.uap, resumeCall!!.callp)) @@ -833,7 +834,7 @@ class MainActivity : AppCompatActivity() { when (intent.action) { ACTION_DIAL, ACTION_CALL, ACTION_VIEW -> { - callAction(intent) + callAction(intent, if (intent.action == ACTION_CALL) "call" else "dial") } else -> { val action = intent.getStringExtra("action") @@ -845,15 +846,15 @@ class MainActivity : AppCompatActivity() { } } - private fun callAction(intent: Intent) { + private fun callAction(intent: Intent, action: String) { if (Call.inCall() || BaresipService.uas.size == 0) return val uri: Uri? = intent.data - Log.d(TAG, "callAction to $uri") + Log.d(TAG, "Action $action to $uri") if (uri != null) { when (uri.scheme) { "sip" -> { - val uriStr = URLDecoder.decode(uri.toString(), "UTF-8") + val uriStr = uri.toString() var ua = UserAgent.ofDomain(Utils.uriHostPart(uriStr)) if (ua == null && BaresipService.uas.size > 0) ua = BaresipService.uas[0] @@ -862,12 +863,11 @@ class MainActivity : AppCompatActivity() { return } spinToAor(ua.account.aor) - resumeAction = "call" + resumeAction = action ua.account.resumeUri = uriStr } "tel" -> { - val uriStr = URLDecoder.decode(uri.toString(), "UTF-8") - .filterNot{setOf('-', ' ', '(', ')').contains(it)} + val uriStr = uri.toString().filterNot{setOf('-', ' ', '(', ')').contains(it)} var account: Account? = null for (a in Account.accounts()) if (a.telProvider != "") { @@ -879,7 +879,7 @@ class MainActivity : AppCompatActivity() { return } spinToAor(account.aor) - resumeAction = "call" + resumeAction = action account.resumeUri = uriStr } else -> { @@ -902,7 +902,7 @@ class MainActivity : AppCompatActivity() { getString(R.string.no_network)) return } - "call" -> { + "call", "dial" -> { if (Call.inCall()) { Toast.makeText(applicationContext, getString(R.string.call_already_active), Toast.LENGTH_SHORT).show() From 5bae9c2c84cbe4223ec35c1101b84978334f3962 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sun, 7 May 2023 18:13:58 +0300 Subject: [PATCH 5/7] In call/dial action URI decode "tel:%2B" to "tel:+" --- app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index d1a7a114..1bcf0be6 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -38,10 +38,8 @@ import com.google.android.material.snackbar.Snackbar import com.tutpro.baresip.Utils.showSnackBar import com.tutpro.baresip.databinding.ActivityMainBinding import java.io.File -import java.net.URLDecoder import kotlin.system.exitProcess - class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding @@ -660,7 +658,8 @@ class MainActivity : AppCompatActivity() { if (BaresipService.isServiceRunning) callAction(intent, if (intent?.action == ACTION_CALL) "call" else "dial") else - BaresipService.callActionUri = URLDecoder.decode(intent.data.toString(), "UTF-8") + BaresipService.callActionUri = intent.data.toString() + .replace("tel:%2B", "tel:+") } permissions = if (Build.VERSION.SDK_INT >= 33) @@ -867,7 +866,8 @@ class MainActivity : AppCompatActivity() { ua.account.resumeUri = uriStr } "tel" -> { - val uriStr = uri.toString().filterNot{setOf('-', ' ', '(', ')').contains(it)} + val uriStr = uri.toString().replace("%2B", "+") + .filterNot{setOf('-', ' ', '(', ')').contains(it)} var account: Account? = null for (a in Account.accounts()) if (a.telProvider != "") { @@ -962,7 +962,7 @@ class MainActivity : AppCompatActivity() { val uap = intent.getLongExtra("uap", 0L) val ua = UserAgent.ofUap(uap) if (ua == null) { - Log.w(TAG, "onNewIntent did not find ua $uap") + Log.w(TAG, "handleIntent did not find ua $uap") return } if (ua.account.aor != aorSpinner.tag) From b6b39ae40b602a0a70a76c4e31a36563890b305e Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sun, 7 May 2023 19:27:43 +0300 Subject: [PATCH 6/7] Impoved starting of baresip due to DIAL action --- .../kotlin/com/tutpro/baresip/MainActivity.kt | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index 1bcf0be6..cba2e54b 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -656,7 +656,7 @@ class MainActivity : AppCompatActivity() { when (intent?.action) { ACTION_DIAL, ACTION_CALL, ACTION_VIEW -> if (BaresipService.isServiceRunning) - callAction(intent, if (intent?.action == ACTION_CALL) "call" else "dial") + callAction(intent.data, if (intent?.action == ACTION_CALL) "call" else "dial") else BaresipService.callActionUri = intent.data.toString() .replace("tel:%2B", "tel:+") @@ -833,7 +833,7 @@ class MainActivity : AppCompatActivity() { when (intent.action) { ACTION_DIAL, ACTION_CALL, ACTION_VIEW -> { - callAction(intent, if (intent.action == ACTION_CALL) "call" else "dial") + callAction(intent.data, if (intent.action == ACTION_CALL) "call" else "dial") } else -> { val action = intent.getStringExtra("action") @@ -845,10 +845,9 @@ class MainActivity : AppCompatActivity() { } } - private fun callAction(intent: Intent, action: String) { + private fun callAction(uri: Uri?, action: String) { if (Call.inCall() || BaresipService.uas.size == 0) return - val uri: Uri? = intent.data Log.d(TAG, "Action $action to $uri") if (uri != null) { when (uri.scheme) { @@ -1010,27 +1009,16 @@ class MainActivity : AppCompatActivity() { } if (event == "started") { - val callActionUri = params[0] as String - Log.d(TAG, "Handling service event 'started' with '$callActionUri'") + val uriString = params[0] as String + Log.d(TAG, "Handling service event 'started' with URI '$uriString'") if (!this::uaAdapter.isInitialized) { // Android has restarted baresip when permission has been denied in app settings recreate() return } uaAdapter.notifyDataSetChanged() - if (callActionUri != "") { - var ua = UserAgent.ofDomain(Utils.uriHostPart(callActionUri)) - if (ua == null) - if (BaresipService.uas.size > 0) { - ua = BaresipService.uas[0] - } else { - handleNextEvent("No UAs to make the call to '$callActionUri'") - return - } - spinToAor(ua.account.aor) - ua.account.resumeUri = callActionUri - callUri.setText(callActionUri) - callButton.performClick() + if (uriString != "") { + callAction(uriString.toUri(), "dial") } else { if ((aorSpinner.selectedItemPosition == -1) && (BaresipService.uas.size > 0)) { aorSpinner.setSelection(0) From 988240fb92e13a581d02da22872062cb8139094f Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Mon, 8 May 2023 08:35:57 +0300 Subject: [PATCH 7/7] Tried to improve default phone app related strings --- .../main/{java => kotlin}/com/tutpro/baresip/InCallService.kt | 0 app/src/main/res/values-fi/strings.xml | 4 ++++ app/src/main/res/values/strings.xml | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) rename app/src/main/{java => kotlin}/com/tutpro/baresip/InCallService.kt (100%) diff --git a/app/src/main/java/com/tutpro/baresip/InCallService.kt b/app/src/main/kotlin/com/tutpro/baresip/InCallService.kt similarity index 100% rename from app/src/main/java/com/tutpro/baresip/InCallService.kt rename to app/src/main/kotlin/com/tutpro/baresip/InCallService.kt diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 6bfe5005..63c89876 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -310,6 +310,10 @@ Ota akun käytön optimointi pois päältä (suositeltu), jos haluat vähentää todennäköisyyttä, että Android rajoittaa baresip-sovelluksen toimintaa ja pääsyä verkkoon. + Oletuspuhelinsovellus + Puhelinrooli ei ole saatavana + Jos merkity, baresip on oletuspuhelinsovellus. Älä + merkitse, jos laitteesi täytyy hallita myös muita kuin SIP-puheluita tai -viestejä. Kuunteluosoite IP-osoite ja portti muotoa \'osoite:portti\', missä baresip kuuntelee sisään tulevia diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9301cb9f..7cf0501c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -299,8 +299,8 @@ to standby state. Default Phone App Dialer role is not available - If checked, baresip is the default phone app. Only choose - if your device never makes or receives calls or messages from telecom (cellular) network. + If checked, baresip is the default phone app. Do not check + if your device may need to handle also other that SIP calls or messages. Listen Address 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