Made it possible to use baresip as a phone app when calling from other apps
with tel: or sip: URIs
This commit is contained in:
@@ -13,22 +13,21 @@
|
|||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
||||||
|
<uses-permission android:name="android.permission.CALL_PHONE" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
|
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.telephony"
|
android:name="android.hardware.telephony"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.camera"
|
android:name="android.hardware.camera"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
|
||||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:installLocation="internalOnly"
|
android:installLocation="internalOnly"
|
||||||
@@ -48,6 +47,14 @@
|
|||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.DIAL" />
|
||||||
|
<action android:name="android.intent.action.CALL" />
|
||||||
|
<action android:name="android.intent.action.CALL_PRIVILEGED" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:scheme="tel" />
|
||||||
|
<data android:scheme="sip" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".AccountsActivity"
|
android:name=".AccountsActivity"
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class Account(val accp: String) {
|
|||||||
var missedCalls = false
|
var missedCalls = false
|
||||||
var unreadMessages = false
|
var unreadMessages = false
|
||||||
var callHistory = true
|
var callHistory = true
|
||||||
|
var resumeUri = ""
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import android.app.Activity
|
|||||||
import android.app.KeyguardManager
|
import android.app.KeyguardManager
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.*
|
import android.content.*
|
||||||
|
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.AudioManager
|
import android.media.AudioManager
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.CountDownTimer
|
import android.os.CountDownTimer
|
||||||
@@ -26,6 +28,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
|||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import com.tutpro.baresip.databinding.ActivityMainBinding
|
import com.tutpro.baresip.databinding.ActivityMainBinding
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.URLDecoder
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@@ -177,6 +180,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
startActivityForResult(i, ACCOUNT_CODE)
|
startActivityForResult(i, ACCOUNT_CODE)
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
UserAgent.uas()[aorSpinner.selectedItemPosition].account.resumeUri =
|
||||||
|
callUri.text.toString()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -490,9 +495,44 @@ class MainActivity : AppCompatActivity() {
|
|||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
// Called when MainActivity already exists at the top of current task
|
// Called when MainActivity already exists at the top of current task
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
val action = intent.getStringExtra("action")
|
resumeAction = ""
|
||||||
Log.d("Baresip", "onNewIntent action '$action'")
|
resumeUri = ""
|
||||||
if (action != null) handleIntent(intent)
|
Log.i("Baresip", "onNewIntent ${intent.action} ${intent.data}")
|
||||||
|
if (intent.action == ACTION_CALL) {
|
||||||
|
if (Call.calls().isNotEmpty() || UserAgent.uas().isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val uri: Uri? = intent.data
|
||||||
|
if (uri != null) {
|
||||||
|
val uriStr = URLDecoder.decode(uri.toString(), "UTF-8")
|
||||||
|
when (uri.scheme) {
|
||||||
|
"sip" -> {
|
||||||
|
Log.d("Baresip", "Got sip URI $uriStr")
|
||||||
|
var ua = UserAgent.ofDomain(Utils.uriHostPart(uriStr))
|
||||||
|
if (ua == null)
|
||||||
|
ua = BaresipService.uas[0]
|
||||||
|
spinToAor(ua.account.aor)
|
||||||
|
resumeAction = "call"
|
||||||
|
ua.account.resumeUri = uriStr
|
||||||
|
}
|
||||||
|
"tel" -> {
|
||||||
|
Log.d("Baresip", "Got tel URI $uriStr")
|
||||||
|
val acc = BaresipService.uas[0].account
|
||||||
|
spinToAor(acc.aor)
|
||||||
|
resumeAction = "call"
|
||||||
|
acc.resumeUri = uriStr.replace("tel", "sip") + "@" + acc.aor
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Toast.makeText(applicationContext, getString(R.string.invalid_sip_uri),
|
||||||
|
Toast.LENGTH_SHORT).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (intent.getStringExtra("action") != null)
|
||||||
|
handleIntent(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleIntent(intent: Intent) {
|
private fun handleIntent(intent: Intent) {
|
||||||
@@ -517,7 +557,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
if (ua.account.aor != aorSpinner.tag)
|
if (ua.account.aor != aorSpinner.tag)
|
||||||
spinToAor(ua.account.aor)
|
spinToAor(ua.account.aor)
|
||||||
resumeAction = action
|
resumeAction = action
|
||||||
resumeUri = intent.getStringExtra("peer")!!
|
ua.account.resumeUri = intent.getStringExtra("peer")!!
|
||||||
}
|
}
|
||||||
"call show", "call answer" -> {
|
"call show", "call answer" -> {
|
||||||
val callp = intent.getStringExtra("callp")!!
|
val callp = intent.getStringExtra("callp")!!
|
||||||
@@ -594,7 +634,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
"call reject" ->
|
"call reject" ->
|
||||||
rejectButton.performClick()
|
rejectButton.performClick()
|
||||||
"call" -> {
|
"call" -> {
|
||||||
callUri.setText(resumeUri)
|
callUri.setText(UserAgent.uas()[aorSpinner.selectedItemPosition].account.resumeUri)
|
||||||
callButton.performClick()
|
callButton.performClick()
|
||||||
}
|
}
|
||||||
"transfer show", "transfer accept" ->
|
"transfer show", "transfer accept" ->
|
||||||
@@ -628,13 +668,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
resumeAction = ""
|
resumeAction = ""
|
||||||
resumeUri = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
Log.d("Baresip", "Main onPause")
|
Log.d("Baresip", "Main onPause")
|
||||||
Utils.addActivity("main")
|
Utils.addActivity("main")
|
||||||
visible = false
|
visible = false
|
||||||
|
if (UserAgent.uas().isNotEmpty() && aorSpinner.selectedItemPosition >= 0)
|
||||||
|
UserAgent.uas()[aorSpinner.selectedItemPosition].account.resumeUri = callUri.text.toString()
|
||||||
super.onPause()
|
super.onPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -870,6 +911,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||||
dialpadButton.setImageResource(R.drawable.dialpad_off)
|
dialpadButton.setImageResource(R.drawable.dialpad_off)
|
||||||
dialpadButton.tag = "off"
|
dialpadButton.tag = "off"
|
||||||
|
ua.account.resumeUri = ""
|
||||||
showCall(ua)
|
showCall(ua)
|
||||||
if (acc.missedCalls)
|
if (acc.missedCalls)
|
||||||
callsButton.setImageResource(R.drawable.calls_missed)
|
callsButton.setImageResource(R.drawable.calls_missed)
|
||||||
@@ -1195,7 +1237,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
val context = this
|
val context = this
|
||||||
val builder = AlertDialog.Builder(this, R.style.AlertDialog)
|
val builder = AlertDialog.Builder(this, R.style.AlertDialog)
|
||||||
with (builder) {
|
with(builder) {
|
||||||
setView(layout)
|
setView(layout)
|
||||||
setPositiveButton(android.R.string.ok) { dialog, _ ->
|
setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||||
imm.hideSoftInputFromWindow(input.windowToken, 0)
|
imm.hideSoftInputFromWindow(input.windowToken, 0)
|
||||||
@@ -1251,7 +1293,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
val context = this
|
val context = this
|
||||||
val builder = AlertDialog.Builder(this, R.style.AlertDialog)
|
val builder = AlertDialog.Builder(this, R.style.AlertDialog)
|
||||||
with (builder) {
|
with(builder) {
|
||||||
setView(layout)
|
setView(layout)
|
||||||
setPositiveButton(android.R.string.ok) { dialog, _ ->
|
setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||||
imm.hideSoftInputFromWindow(input.windowToken, 0)
|
imm.hideSoftInputFromWindow(input.windowToken, 0)
|
||||||
@@ -1444,7 +1486,10 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private fun showCall(ua: UserAgent) {
|
private fun showCall(ua: UserAgent) {
|
||||||
if (Call.uaCalls(ua, "").size == 0) {
|
if (Call.uaCalls(ua, "").size == 0) {
|
||||||
callTitle.text = getString(R.string.outgoing_call_to_dots)
|
callTitle.text = getString(R.string.outgoing_call_to_dots)
|
||||||
callUri.text.clear()
|
if (ua.account.resumeUri != "")
|
||||||
|
callUri.setText(ua.account.resumeUri)
|
||||||
|
else
|
||||||
|
callUri.text.clear()
|
||||||
callUri.hint = getString(R.string.callee)
|
callUri.hint = getString(R.string.callee)
|
||||||
callUri.isFocusable = true
|
callUri.isFocusable = true
|
||||||
callUri.isFocusableInTouchMode = true
|
callUri.isFocusableInTouchMode = true
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ class UserAgent(val uap: String) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ofDomain(domain: String): UserAgent? {
|
||||||
|
for (ua in BaresipService.uas)
|
||||||
|
if (Utils.aorDomain(ua.account.aor) == domain) return ua
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
fun ofUap(uap: String): UserAgent? {
|
fun ofUap(uap: String): UserAgent? {
|
||||||
for (ua in BaresipService.uas)
|
for (ua in BaresipService.uas)
|
||||||
if (ua.uap == uap) return ua
|
if (ua.uap == uap) return ua
|
||||||
|
|||||||
Reference in New Issue
Block a user