Started to work on better permissions handling
This commit is contained in:
@ -57,4 +57,6 @@ dependencies {
|
||||
implementation "androidx.core:core-ktx:1.7.0"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
||||
implementation "androidx.activity:activity-ktx:1.4.0"
|
||||
implementation "androidx.fragment:fragment-ktx:1.3.6"
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:remove="android:appComponentFactory"
|
||||
tools:targetApi="q">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
|
||||
@ -21,6 +21,7 @@ import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import android.content.Intent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.Keep
|
||||
import androidx.annotation.StringRes
|
||||
@ -36,6 +37,7 @@ import kotlin.concurrent.schedule
|
||||
import kotlin.math.roundToInt
|
||||
import android.media.MediaPlayer
|
||||
import android.telecom.TelecomManager
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
||||
class BaresipService: Service() {
|
||||
|
||||
@ -576,20 +578,23 @@ class BaresipService: Service() {
|
||||
"call incoming" -> {
|
||||
val peerUri = Api.call_peeruri(callp)
|
||||
if (Call.calls().size > 0 ||
|
||||
(Utils.checkPermission(this, Manifest.permission.READ_PHONE_STATE) &&
|
||||
tm.isInCall) ||
|
||||
!Utils.checkPermission(applicationContext, Manifest.permission.RECORD_AUDIO)) {
|
||||
Log.d(TAG, "Auto-rejecting incoming call $uap/$callp/$peerUri")
|
||||
Api.ua_hangup(uap, callp, 486, "Busy Here")
|
||||
if (ua.account.callHistory) {
|
||||
CallHistory.add(CallHistory(aor, peerUri, "in", false))
|
||||
CallHistory.save()
|
||||
ua.account.missedCalls = true
|
||||
}
|
||||
playUnInterrupted(R.raw.callwaiting, 1)
|
||||
if (!Utils.isVisible())
|
||||
return
|
||||
newEvent = "call rejected"
|
||||
!Utils.checkPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO)) ||
|
||||
ActivityCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_PHONE_STATE
|
||||
) != PackageManager.PERMISSION_GRANTED ||
|
||||
tm.isInCall) {
|
||||
Log.d(TAG, "Auto-rejecting incoming call $uap/$callp/$peerUri")
|
||||
Api.ua_hangup(uap, callp, 486, "Busy Here")
|
||||
if (ua.account.callHistory) {
|
||||
CallHistory.add(CallHistory(aor, peerUri, "in", false))
|
||||
CallHistory.save()
|
||||
ua.account.missedCalls = true
|
||||
}
|
||||
playUnInterrupted(R.raw.callwaiting, 1)
|
||||
if (!Utils.isVisible())
|
||||
return
|
||||
newEvent = "call rejected"
|
||||
} else {
|
||||
Log.d(TAG, "Incoming call $uap/$callp/$peerUri")
|
||||
Call(callp, ua, peerUri, "in", "incoming",
|
||||
|
||||
@ -12,10 +12,15 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import android.widget.AdapterView
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tutpro.baresip.Utils.copyInputStreamToFile
|
||||
import com.tutpro.baresip.Utils.showSnackBar
|
||||
import com.tutpro.baresip.databinding.ActivityConfigBinding
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
@ -24,6 +29,7 @@ import java.util.*
|
||||
class ConfigActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityConfigBinding
|
||||
private lateinit var layout: ScrollView
|
||||
private lateinit var autoStart: CheckBox
|
||||
private lateinit var listenAddr: EditText
|
||||
private lateinit var dnsServers: EditText
|
||||
@ -34,6 +40,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
private lateinit var debug: CheckBox
|
||||
private lateinit var sipTrace: CheckBox
|
||||
private lateinit var reset: CheckBox
|
||||
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>
|
||||
|
||||
private var oldAutoStart = ""
|
||||
private var oldListenAddr = ""
|
||||
@ -54,6 +61,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
|
||||
binding = ActivityConfigBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
layout = binding.ConfigView
|
||||
|
||||
Utils.addActivity("config")
|
||||
|
||||
@ -88,8 +96,9 @@ class ConfigActivity : AppCompatActivity() {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
it.data?.data?.also { uri ->
|
||||
try {
|
||||
val inputStream = applicationContext.contentResolver.openInputStream(uri)
|
||||
as FileInputStream
|
||||
val inputStream =
|
||||
applicationContext.contentResolver.openInputStream(uri)
|
||||
as FileInputStream
|
||||
File(BaresipService.filesPath + "/cert.pem")
|
||||
.copyInputStreamToFile(inputStream)
|
||||
inputStream.close()
|
||||
@ -113,26 +122,45 @@ class ConfigActivity : AppCompatActivity() {
|
||||
certificateFile.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
if (Build.VERSION.SDK_INT < 29) {
|
||||
if (!Utils.requestPermission(this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
READ_CERT_PERMISSION_CODE)) {
|
||||
certificateFile.isChecked = false
|
||||
return@setOnCheckedChangeListener
|
||||
certificateFile.isChecked = false
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
Log.d(TAG, "Read External Storage permission granted")
|
||||
val downloadsPath = Utils.downloadsPath("cert.pem")
|
||||
val content = Utils.getFileContents(downloadsPath)
|
||||
if (content == null) {
|
||||
Utils.alertView(
|
||||
this, getString(R.string.error),
|
||||
getString(R.string.read_cert_error)
|
||||
)
|
||||
return@setOnCheckedChangeListener
|
||||
}
|
||||
val filesPath = BaresipService.filesPath + "/cert.pem"
|
||||
Utils.putFileContents(filesPath, content)
|
||||
Config.removeVariable("sip_certificate")
|
||||
Config.addLine("sip_certificate $filesPath")
|
||||
certificateFile.isChecked = true
|
||||
save = true
|
||||
restart = true
|
||||
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
) {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_restore),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
} else {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
val downloadsPath = Utils.downloadsPath("cert.pem")
|
||||
val content = Utils.getFileContents(downloadsPath)
|
||||
if (content == null) {
|
||||
Utils.alertView(this, getString(R.string.error),
|
||||
getString(R.string.read_cert_error))
|
||||
certificateFile.isChecked = false
|
||||
return@setOnCheckedChangeListener
|
||||
}
|
||||
val filesPath = BaresipService.filesPath + "/cert.pem"
|
||||
Utils.putFileContents(filesPath, content)
|
||||
Config.removeVariable("sip_certificate")
|
||||
Config.addLine("sip_certificate $filesPath")
|
||||
save = true
|
||||
restart = true
|
||||
} else {
|
||||
Utils.selectInputFile(certificateRequest)
|
||||
}
|
||||
@ -157,8 +185,9 @@ class ConfigActivity : AppCompatActivity() {
|
||||
if (it.resultCode == Activity.RESULT_OK)
|
||||
it.data?.data?.also { uri ->
|
||||
try {
|
||||
val inputStream = applicationContext.contentResolver.openInputStream(uri)
|
||||
as FileInputStream
|
||||
val inputStream =
|
||||
applicationContext.contentResolver.openInputStream(uri)
|
||||
as FileInputStream
|
||||
File(BaresipService.filesPath + "/ca_certs.crt")
|
||||
.copyInputStreamToFile(inputStream)
|
||||
inputStream.close()
|
||||
@ -167,8 +196,10 @@ class ConfigActivity : AppCompatActivity() {
|
||||
save = true
|
||||
restart = true
|
||||
} catch (e: Error) {
|
||||
Utils.alertView(this, getString(R.string.error),
|
||||
getString(R.string.read_ca_certs_error))
|
||||
Utils.alertView(
|
||||
this, getString(R.string.error),
|
||||
getString(R.string.read_ca_certs_error)
|
||||
)
|
||||
caFile.isChecked = false
|
||||
}
|
||||
}
|
||||
@ -179,26 +210,45 @@ class ConfigActivity : AppCompatActivity() {
|
||||
caFile.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
if (Build.VERSION.SDK_INT < 29) {
|
||||
if (!Utils.requestPermission(this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
READ_CERT_PERMISSION_CODE)) {
|
||||
caFile.isChecked = false
|
||||
return@setOnCheckedChangeListener
|
||||
caFile.isChecked = false
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
Log.d(TAG, "Read External Storage permission granted")
|
||||
val downloadsPath = Utils.downloadsPath("ca_certs.crt")
|
||||
val content = Utils.getFileContents(downloadsPath)
|
||||
if (content == null) {
|
||||
Utils.alertView(
|
||||
this, getString(R.string.error),
|
||||
getString(R.string.read_ca_certs_error)
|
||||
)
|
||||
return@setOnCheckedChangeListener
|
||||
}
|
||||
val filesPath = BaresipService.filesPath + "/ca_certs.crt"
|
||||
Utils.putFileContents(filesPath, content)
|
||||
Config.removeVariable("sip_cafile")
|
||||
Config.addLine("sip_cafile $filesPath")
|
||||
caFile.isChecked = true
|
||||
save = true
|
||||
restart = true
|
||||
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
) {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_restore),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
} else {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
val downloadsPath = Utils.downloadsPath("ca_certs.crt")
|
||||
val content = Utils.getFileContents(downloadsPath)
|
||||
if (content == null) {
|
||||
Utils.alertView(this, getString(R.string.error),
|
||||
getString(R.string.read_ca_certs_error))
|
||||
caFile.isChecked = false
|
||||
return@setOnCheckedChangeListener
|
||||
}
|
||||
val filesPath = BaresipService.filesPath + "/ca_certs.crt"
|
||||
Utils.putFileContents(filesPath, content)
|
||||
Config.removeVariable("sip_cafile")
|
||||
Config.addLine("sip_cafile $filesPath")
|
||||
save = true
|
||||
restart = true
|
||||
} else {
|
||||
Utils.selectInputFile(certificatesRequest)
|
||||
}
|
||||
@ -218,14 +268,22 @@ class ConfigActivity : AppCompatActivity() {
|
||||
volVals.removeAt(curVal)
|
||||
volKeys.add(0, curKey)
|
||||
volVals.add(0, curVal)
|
||||
val callVolAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item,
|
||||
volKeys)
|
||||
val callVolAdapter = ArrayAdapter(
|
||||
this, android.R.layout.simple_spinner_item,
|
||||
volKeys
|
||||
)
|
||||
callVolAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
callVolSpinner.adapter = callVolAdapter
|
||||
callVolSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
|
||||
override fun onItemSelected(
|
||||
parent: AdapterView<*>,
|
||||
view: View?,
|
||||
position: Int,
|
||||
id: Long
|
||||
) {
|
||||
callVolume = volVals[volKeys.indexOf(parent.selectedItem.toString())]
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {
|
||||
}
|
||||
}
|
||||
@ -240,7 +298,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
"2"
|
||||
else
|
||||
dbCv[0]
|
||||
debug.isChecked = oldLogLevel == "0"
|
||||
debug.isChecked = oldLogLevel == "0"
|
||||
|
||||
sipTrace = binding.SipTrace
|
||||
sipTrace.isChecked = BaresipService.sipTrace
|
||||
@ -252,7 +310,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
if (isChecked) {
|
||||
val titleView = View.inflate(this, R.layout.alert_title, null) as TextView
|
||||
titleView.text = getString(R.string.confirmation)
|
||||
with (AlertDialog.Builder(this@ConfigActivity)) {
|
||||
with(AlertDialog.Builder(this@ConfigActivity)) {
|
||||
setCustomTitle(titleView)
|
||||
setMessage(getString(R.string.reset_config_alert))
|
||||
setPositiveButton(getText(R.string.reset)) { dialog, _ ->
|
||||
@ -275,6 +333,12 @@ class ConfigActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
requestPermissionLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
|
||||
super.onCreateOptionsMenu(menu)
|
||||
@ -413,28 +477,6 @@ class ConfigActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
|
||||
grantResults: IntArray) {
|
||||
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
|
||||
when (requestCode) {
|
||||
READ_CERT_PERMISSION_CODE ->
|
||||
if (grantResults.isNotEmpty() &&
|
||||
(grantResults[0] == PackageManager.PERMISSION_GRANTED))
|
||||
menu!!.performIdentifierAction(R.id.checkIcon, 0)
|
||||
else
|
||||
certificateFile.isChecked = false
|
||||
READ_CA_PERMISSION_CODE ->
|
||||
if (grantResults.isNotEmpty() &&
|
||||
(grantResults[0] == PackageManager.PERMISSION_GRANTED))
|
||||
menu!!.performIdentifierAction(R.id.checkIcon, 0)
|
||||
else
|
||||
caFile.isChecked = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
||||
BaresipService.activities.remove("config")
|
||||
|
||||
@ -7,10 +7,11 @@ const val HIGH_CHANNEL_ID = "com.tutpro.baresip.high"
|
||||
|
||||
const val BACKUP_PERMISSION_REQUEST_CODE = 1
|
||||
const val RESTORE_PERMISSION_REQUEST_CODE = 2
|
||||
const val RECORD_PERMISSION_REQUEST_CODE = 3
|
||||
const val CONTACTS_PERMISSION_REQUEST_CODE = 4
|
||||
const val CALL_PERMISSION_REQUEST_CODE = 3
|
||||
const val CONTACT_PERMISSION_REQUEST_CODE = 4
|
||||
const val READ_CERT_PERMISSION_CODE = 5
|
||||
const val READ_CA_PERMISSION_CODE = 6
|
||||
const val REQUEST_PERMISSIONS_CODE = 7
|
||||
|
||||
const val STATUS_NOTIFICATION_ID = 101
|
||||
const val CALL_NOTIFICATION_ID = 102
|
||||
|
||||
@ -12,6 +12,7 @@ import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.ContactsContract
|
||||
import android.provider.ContactsContract.CommonDataKinds
|
||||
@ -20,10 +21,14 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tutpro.baresip.Utils.showSnackBar
|
||||
import com.tutpro.baresip.databinding.ActivityContactBinding
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
@ -31,6 +36,7 @@ import java.io.File
|
||||
class ContactActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityContactBinding
|
||||
private lateinit var layout: LinearLayout
|
||||
private lateinit var textAvatarView: TextView
|
||||
private lateinit var cardAvatarView: CardView
|
||||
private lateinit var cardImageAvatarView: ImageView
|
||||
@ -38,6 +44,7 @@ class ContactActivity : AppCompatActivity() {
|
||||
private lateinit var uriView: EditText
|
||||
private lateinit var androidCheck: CheckBox
|
||||
private lateinit var menu: Menu
|
||||
private lateinit var requestPermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||
|
||||
private var newContact = false
|
||||
private var newAvatar = ""
|
||||
@ -48,11 +55,15 @@ class ContactActivity : AppCompatActivity() {
|
||||
private var id: Long = 0
|
||||
private var oldAndroid = false
|
||||
|
||||
private val permissions =
|
||||
arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityContactBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
layout = binding.ContactView
|
||||
|
||||
textAvatarView = binding.TextAvatar
|
||||
cardAvatarView = binding.CardAvatar
|
||||
@ -166,10 +177,22 @@ class ContactActivity : AppCompatActivity() {
|
||||
getString(R.string.android_contact_help))
|
||||
}
|
||||
|
||||
androidCheck.setOnClickListener{
|
||||
if (Build.VERSION.SDK_INT >= 23)
|
||||
if (!Utils.checkPermissions(this, permissions))
|
||||
requestPermissions(permissions, CONTACT_PERMISSION_REQUEST_CODE)
|
||||
}
|
||||
|
||||
Utils.addActivity("contact,$newContact,$uOrI")
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
requestPermissionsLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(optionsMenu: Menu): Boolean {
|
||||
|
||||
super.onCreateOptionsMenu(optionsMenu)
|
||||
@ -181,6 +204,47 @@ class ContactActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
|
||||
grandResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grandResults)
|
||||
var allowed = true
|
||||
when (requestCode) {
|
||||
CONTACT_PERMISSION_REQUEST_CODE ->
|
||||
for (res in grandResults)
|
||||
allowed = allowed && res == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
if (!allowed) {
|
||||
androidCheck.isChecked = oldAndroid
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.READ_CONTACTS
|
||||
))
|
||||
{
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.WRITE_CONTACTS
|
||||
))
|
||||
{
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
||||
if (BaresipService.activities.indexOf("contact,$newContact,$uOrI") == -1) return true
|
||||
@ -260,20 +324,13 @@ class ContactActivity : AppCompatActivity() {
|
||||
|
||||
Contact.contacts().sortBy { Contact -> Contact.name }
|
||||
|
||||
if (Utils.checkPermission(this, Manifest.permission.READ_CONTACTS +
|
||||
"|" + Manifest.permission.WRITE_CONTACTS)) {
|
||||
if (Utils.checkPermissions(this, permissions)) {
|
||||
if (contact.androidContact)
|
||||
addOrUpdateAndroidContact(this, contact)
|
||||
else
|
||||
if (oldAndroid)
|
||||
deleteAndroidContact(this, contact)
|
||||
else if (oldAndroid)
|
||||
deleteAndroidContact(this, contact)
|
||||
} else {
|
||||
if (contact.androidContact) {
|
||||
Utils.requestPermission(this, Manifest.permission.READ_CONTACTS +
|
||||
"|" + Manifest.permission.WRITE_CONTACTS,
|
||||
CONTACTS_PERMISSION_REQUEST_CODE)
|
||||
return false
|
||||
}
|
||||
contact.androidContact = oldAndroid
|
||||
}
|
||||
|
||||
Contact.save()
|
||||
@ -298,23 +355,6 @@ class ContactActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
|
||||
grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
|
||||
when (requestCode) {
|
||||
|
||||
CONTACTS_PERMISSION_REQUEST_CODE ->
|
||||
if (grantResults.isNotEmpty() && permissions.size == grantResults.size) {
|
||||
for (res in grantResults)
|
||||
if (res != PackageManager.PERMISSION_GRANTED)
|
||||
return
|
||||
menu.performIdentifierAction(R.id.checkIcon, 0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
||||
BaresipService.activities.remove("contact,$newContact,$uOrI")
|
||||
|
||||
@ -128,7 +128,7 @@ class ContactListAdapter(private val ctx: Context, private val rows: ArrayList<C
|
||||
}
|
||||
}
|
||||
if (contact.androidContact &&
|
||||
Utils.checkPermission(ctx, Manifest.permission.WRITE_CONTACTS))
|
||||
Utils.checkPermissions(ctx, arrayOf(Manifest.permission.WRITE_CONTACTS)))
|
||||
ContactActivity.deleteAndroidContact(ctx, contact)
|
||||
Contact.contacts().removeAt(position)
|
||||
Contact.save()
|
||||
|
||||
@ -29,8 +29,12 @@ import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
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.io.FileInputStream
|
||||
@ -72,6 +76,8 @@ class MainActivity : AppCompatActivity() {
|
||||
private lateinit var stopState: String
|
||||
private var speakerIcon: MenuItem? = null
|
||||
private lateinit var swipeRefresh: SwipeRefreshLayout
|
||||
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>
|
||||
private lateinit var requestPermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||
|
||||
private lateinit var accountsRequest: ActivityResultLauncher<Intent>
|
||||
private lateinit var chatRequests: ActivityResultLauncher<Intent>
|
||||
@ -304,44 +310,10 @@ class MainActivity : AppCompatActivity() {
|
||||
callButton.setOnClickListener {
|
||||
if (aorSpinner.selectedItemPosition == -1)
|
||||
return@setOnClickListener
|
||||
callUri.setAdapter(null)
|
||||
val ua = UserAgent.uas()[aorSpinner.selectedItemPosition]
|
||||
val aor = ua.account.aor
|
||||
if (Call.calls().isEmpty()) {
|
||||
val uriText = callUri.text.toString().trim()
|
||||
if (uriText.isNotEmpty()) {
|
||||
val uri = Utils.uriComplete(
|
||||
ContactsActivity.findContactURI(uriText).filterNot { it.isWhitespace() },
|
||||
Utils.aorDomain(aor)
|
||||
)
|
||||
if (!Utils.checkSipUri(uri)) {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
String.format(getString(R.string.invalid_sip_uri), uri))
|
||||
} else {
|
||||
callUri.isFocusable = false
|
||||
if (!call(ua, uri)) {
|
||||
callButton.visibility = View.VISIBLE
|
||||
callButton.isEnabled = true
|
||||
hangupButton.visibility = View.INVISIBLE
|
||||
hangupButton.isEnabled = false
|
||||
} else {
|
||||
callButton.visibility = View.INVISIBLE
|
||||
callButton.isEnabled = false
|
||||
hangupButton.visibility = View.VISIBLE
|
||||
hangupButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val latest = CallHistory.aorLatestHistory(aor)
|
||||
if (latest != null)
|
||||
callUri.setText(
|
||||
Utils.friendlyUri(
|
||||
ContactsActivity.contactName(latest.peerUri),
|
||||
Utils.aorDomain(ua.account.aor)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
val permissions = arrayOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_PHONE_STATE)
|
||||
if (Build.VERSION.SDK_INT >= 23)
|
||||
if (!Utils.checkPermissions(this, permissions))
|
||||
requestPermissions(permissions, CALL_PERMISSION_REQUEST_CODE)
|
||||
}
|
||||
|
||||
hangupButton.setOnClickListener {
|
||||
@ -656,17 +628,182 @@ class MainActivity : AppCompatActivity() {
|
||||
delegate.applyDayNight()
|
||||
}
|
||||
|
||||
window.decorView.post {
|
||||
if (firstRun) {
|
||||
if (!Utils.checkPermission(this, Manifest.permission.RECORD_AUDIO))
|
||||
Utils.requestPermission(
|
||||
this, Manifest.permission.RECORD_AUDIO, RECORD_PERMISSION_REQUEST_CODE
|
||||
)
|
||||
firstRun = false
|
||||
} // OnCreate
|
||||
|
||||
override fun onStart() {
|
||||
Log.i(TAG, "Main onStart")
|
||||
super.onStart()
|
||||
requestPermissionLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
|
||||
requestPermissionsLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
|
||||
permissions ->
|
||||
permissions.entries.forEach {
|
||||
if (it.value)
|
||||
Log.i(TAG, "Permission ${it.key} granted")
|
||||
else
|
||||
Log.i(TAG, "Permission ${it.key} denied")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
Log.d(TAG, "Main onResume with action '$resumeAction'")
|
||||
nm.cancelAll()
|
||||
BaresipService.isMainVisible = true
|
||||
when (resumeAction) {
|
||||
"call show" ->
|
||||
handleServiceEvent("call incoming",
|
||||
arrayListOf(resumeCall!!.ua.uap, resumeCall!!.callp))
|
||||
"call answer" -> {
|
||||
answerButton.performClick()
|
||||
showCall(resumeCall!!.ua)
|
||||
}
|
||||
"call missed" -> {
|
||||
callsButton.performClick()
|
||||
}
|
||||
"call reject" ->
|
||||
rejectButton.performClick()
|
||||
"call" -> {
|
||||
callUri.setText(UserAgent.uas()[aorSpinner.selectedItemPosition].account.resumeUri)
|
||||
callButton.performClick()
|
||||
}
|
||||
"transfer show", "transfer accept" ->
|
||||
handleServiceEvent("$resumeAction,$resumeUri",
|
||||
arrayListOf(resumeCall!!.ua.uap, resumeCall!!.callp))
|
||||
"message", "message show", "message reply" ->
|
||||
handleServiceEvent(resumeAction, arrayListOf(resumeUap, resumeUri))
|
||||
else -> {
|
||||
val incomingCall = Call.call("incoming")
|
||||
if (incomingCall != null) {
|
||||
spinToAor(incomingCall.ua.account.aor)
|
||||
} else {
|
||||
restoreActivities()
|
||||
if (UserAgent.uas().size > 0) {
|
||||
if (aorSpinner.selectedItemPosition == -1) {
|
||||
if (Call.calls().size > 0)
|
||||
spinToAor(Call.calls()[0].ua.account.aor)
|
||||
else {
|
||||
aorSpinner.setSelection(0)
|
||||
aorSpinner.tag = UserAgent.uas()[0].account.aor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uaAdapter.notifyDataSetChanged()
|
||||
if (UserAgent.uas().size > 0) {
|
||||
val ua = UserAgent.uas()[aorSpinner.selectedItemPosition]
|
||||
showCall(ua)
|
||||
updateIcons(ua.account)
|
||||
}
|
||||
}
|
||||
}
|
||||
resumeAction = ""
|
||||
}
|
||||
|
||||
} // OnCreate
|
||||
override fun onPause() {
|
||||
Log.d(TAG, "Main onPause")
|
||||
Utils.addActivity("main")
|
||||
BaresipService.isMainVisible = false
|
||||
saveCallUri()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
Log.d(TAG, "Main onStop")
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Log.d(TAG, "Main onDestroy")
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceEventReceiver)
|
||||
BaresipService.activities.clear()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
|
||||
grandResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grandResults)
|
||||
var allowed = true
|
||||
when (requestCode) {
|
||||
CALL_PERMISSION_REQUEST_CODE -> {
|
||||
for (res in grandResults)
|
||||
allowed = allowed && res == PackageManager.PERMISSION_GRANTED
|
||||
if (allowed) {
|
||||
callUri.setAdapter(null)
|
||||
val ua = UserAgent.uas()[aorSpinner.selectedItemPosition]
|
||||
val aor = ua.account.aor
|
||||
if (Call.calls().isEmpty()) {
|
||||
val uriText = callUri.text.toString().trim()
|
||||
if (uriText.isNotEmpty()) {
|
||||
val uri = Utils.uriComplete(
|
||||
ContactsActivity.findContactURI(uriText)
|
||||
.filterNot { it.isWhitespace() },
|
||||
Utils.aorDomain(aor)
|
||||
)
|
||||
if (!Utils.checkSipUri(uri)) {
|
||||
Utils.alertView(
|
||||
this, getString(R.string.notice),
|
||||
String.format(getString(R.string.invalid_sip_uri), uri)
|
||||
)
|
||||
} else {
|
||||
callUri.isFocusable = false
|
||||
if (!call(ua, uri)) {
|
||||
callButton.visibility = View.VISIBLE
|
||||
callButton.isEnabled = true
|
||||
hangupButton.visibility = View.INVISIBLE
|
||||
hangupButton.isEnabled = false
|
||||
} else {
|
||||
callButton.visibility = View.INVISIBLE
|
||||
callButton.isEnabled = false
|
||||
hangupButton.visibility = View.VISIBLE
|
||||
hangupButton.isEnabled = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val latest = CallHistory.aorLatestHistory(aor)
|
||||
if (latest != null)
|
||||
callUri.setText(
|
||||
Utils.friendlyUri(
|
||||
ContactsActivity.contactName(latest.peerUri),
|
||||
Utils.aorDomain(ua.account.aor)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.RECORD_AUDIO
|
||||
)
|
||||
) {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.READ_PHONE_STATE
|
||||
)
|
||||
) {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
// Called when MainActivity already exists at the top of current task
|
||||
@ -790,84 +927,6 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
Log.d(TAG, "Main onStart")
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
Log.d(TAG, "Main onResume with action '$resumeAction'")
|
||||
nm.cancelAll()
|
||||
BaresipService.isMainVisible = true
|
||||
when (resumeAction) {
|
||||
"call show" ->
|
||||
handleServiceEvent("call incoming",
|
||||
arrayListOf(resumeCall!!.ua.uap, resumeCall!!.callp))
|
||||
"call answer" -> {
|
||||
answerButton.performClick()
|
||||
showCall(resumeCall!!.ua)
|
||||
}
|
||||
"call missed" -> {
|
||||
callsButton.performClick()
|
||||
}
|
||||
"call reject" ->
|
||||
rejectButton.performClick()
|
||||
"call" -> {
|
||||
callUri.setText(UserAgent.uas()[aorSpinner.selectedItemPosition].account.resumeUri)
|
||||
callButton.performClick()
|
||||
}
|
||||
"transfer show", "transfer accept" ->
|
||||
handleServiceEvent("$resumeAction,$resumeUri",
|
||||
arrayListOf(resumeCall!!.ua.uap, resumeCall!!.callp))
|
||||
"message", "message show", "message reply" ->
|
||||
handleServiceEvent(resumeAction, arrayListOf(resumeUap, resumeUri))
|
||||
else -> {
|
||||
val incomingCall = Call.call("incoming")
|
||||
if (incomingCall != null) {
|
||||
spinToAor(incomingCall.ua.account.aor)
|
||||
} else {
|
||||
restoreActivities()
|
||||
if (UserAgent.uas().size > 0) {
|
||||
if (aorSpinner.selectedItemPosition == -1) {
|
||||
if (Call.calls().size > 0)
|
||||
spinToAor(Call.calls()[0].ua.account.aor)
|
||||
else {
|
||||
aorSpinner.setSelection(0)
|
||||
aorSpinner.tag = UserAgent.uas()[0].account.aor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uaAdapter.notifyDataSetChanged()
|
||||
if (UserAgent.uas().size > 0) {
|
||||
val ua = UserAgent.uas()[aorSpinner.selectedItemPosition]
|
||||
showCall(ua)
|
||||
updateIcons(ua.account)
|
||||
}
|
||||
}
|
||||
}
|
||||
resumeAction = ""
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
Log.d(TAG, "Main onPause")
|
||||
Utils.addActivity("main")
|
||||
BaresipService.isMainVisible = false
|
||||
saveCallUri()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
Log.d(TAG, "Main onStop")
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun recreate() {
|
||||
Log.d(TAG, "Main onCreate")
|
||||
super.recreate()
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
val stream = if (am.mode == AudioManager.MODE_RINGTONE)
|
||||
AudioManager.STREAM_RING
|
||||
@ -971,10 +1030,6 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
"call incoming" -> {
|
||||
val callp = params[1]
|
||||
if (!Utils.checkPermission(this, Manifest.permission.RECORD_AUDIO)) {
|
||||
Api.ua_hangup(uap, callp, 486, "Busy Here")
|
||||
return
|
||||
}
|
||||
if (BaresipService.isMainVisible) {
|
||||
if (aor != aorSpinner.tag)
|
||||
spinToAor(aor)
|
||||
@ -1173,13 +1228,6 @@ class MainActivity : AppCompatActivity() {
|
||||
moveTaskToBack(true)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Log.d(TAG, "Main onDestroy")
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceEventReceiver)
|
||||
BaresipService.activities.clear()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.main_menu, menu)
|
||||
menuInflater.inflate(R.menu.speaker_icon, menu)
|
||||
@ -1219,24 +1267,59 @@ class MainActivity : AppCompatActivity() {
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
pickupFileFromDownloads("backup")
|
||||
} else {
|
||||
if (Utils.requestPermission(
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
BACKUP_PERMISSION_REQUEST_CODE
|
||||
)
|
||||
) {
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d(TAG, "Write External Storage permission granted")
|
||||
val path = Utils.downloadsPath("baresip.bs")
|
||||
downloadsOutputStream = FileOutputStream(File(path))
|
||||
askPassword(getString(R.string.encrypt_password))
|
||||
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_backup),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
}
|
||||
} else {
|
||||
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
R.id.restore -> {
|
||||
if (Build.VERSION.SDK_INT >= 29 ||
|
||||
Utils.requestPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
RESTORE_PERMISSION_REQUEST_CODE))
|
||||
startRestore()
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
pickupFileFromDownloads("restore")
|
||||
} else {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d(TAG, "Read External Storage permission granted")
|
||||
val path = Utils.downloadsPath("baresip.bs")
|
||||
downloadsInputStream = FileInputStream(File(path))
|
||||
askPassword(getString(R.string.decrypt_password))
|
||||
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_restore),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
} else {
|
||||
requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R.id.about -> {
|
||||
@ -1250,38 +1333,6 @@ class MainActivity : AppCompatActivity() {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
|
||||
grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
|
||||
when (requestCode) {
|
||||
|
||||
RECORD_PERMISSION_REQUEST_CODE ->
|
||||
if ((grantResults.isNotEmpty()) && (grantResults[0] != PackageManager.PERMISSION_GRANTED))
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
getString(R.string.no_calls))
|
||||
|
||||
BACKUP_PERMISSION_REQUEST_CODE ->
|
||||
if ((grantResults.isNotEmpty()) && (grantResults[0] == PackageManager.PERMISSION_GRANTED))
|
||||
askPassword(getString(R.string.encrypt_password))
|
||||
|
||||
RESTORE_PERMISSION_REQUEST_CODE ->
|
||||
if ((grantResults.isNotEmpty()) && (grantResults[0] == PackageManager.PERMISSION_GRANTED))
|
||||
startRestore()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun startRestore() {
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
pickupFileFromDownloads("restore")
|
||||
} else {
|
||||
val path = Utils.downloadsPath("baresip.bs")
|
||||
downloadsInputStream = FileInputStream(File(path))
|
||||
askPassword(getString(R.string.decrypt_password))
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(29)
|
||||
private fun pickupFileFromDownloads(action: String) {
|
||||
when (action) {
|
||||
@ -1559,11 +1610,6 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun call(ua: UserAgent, uri: String): Boolean {
|
||||
if (!Utils.checkPermission(this, Manifest.permission.RECORD_AUDIO)) {
|
||||
Toast.makeText(applicationContext, getString(R.string.no_calls),
|
||||
Toast.LENGTH_LONG).show()
|
||||
return false
|
||||
}
|
||||
if (ua.account.aor != aorSpinner.tag)
|
||||
spinToAor(ua.account.aor)
|
||||
val callp = Api.ua_connect(ua.uap, uri, Api.VIDMODE_OFF)
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
@ -22,10 +21,10 @@ import android.widget.TextView
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import java.io.*
|
||||
import java.lang.reflect.Method
|
||||
import java.security.SecureRandom
|
||||
@ -320,8 +319,9 @@ object Utils {
|
||||
val addresses: Enumeration<InetAddress> = iface.inetAddresses
|
||||
while (addresses.hasMoreElements()) {
|
||||
val inetAddress: InetAddress = addresses.nextElement()
|
||||
if (!inetAddress.isLoopbackAddress && !inetAddress.isLinkLocalAddress)
|
||||
result[inetAddress.hostAddress] = ifName
|
||||
if (inetAddress.hostAddress != null && !inetAddress.isLoopbackAddress &&
|
||||
!inetAddress.isLinkLocalAddress)
|
||||
result[inetAddress.hostAddress!!] = ifName
|
||||
}
|
||||
if (result.isNotEmpty()) return result
|
||||
}
|
||||
@ -356,22 +356,33 @@ object Utils {
|
||||
}
|
||||
}
|
||||
|
||||
fun checkPermission(ctx: Context, permissions: String) : Boolean {
|
||||
for (p in permissions.split("|")) {
|
||||
if (ContextCompat.checkSelfPermission(ctx, p) != PackageManager.PERMISSION_GRANTED)
|
||||
fun checkPermissions(ctx: Context, permissions: Array<String>) : Boolean {
|
||||
for (p in permissions) {
|
||||
if (ContextCompat.checkSelfPermission(ctx, p) != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d(TAG, "Permission $p is not granted")
|
||||
return false
|
||||
} else {
|
||||
Log.d(TAG, "Permission $p is granted")
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun requestPermission(ctx: Context, permissions: String, requestCode: Int) : Boolean {
|
||||
val pArray = permissions.split("|").toTypedArray()
|
||||
for (p in pArray)
|
||||
if (ContextCompat.checkSelfPermission(ctx, p) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(ctx as Activity, pArray, requestCode)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
fun View.showSnackBar(
|
||||
view: View,
|
||||
msg: String,
|
||||
length: Int,
|
||||
actionMessage: CharSequence?,
|
||||
action: (View) -> Unit
|
||||
) {
|
||||
val snackBar = Snackbar.make(view, msg, length)
|
||||
if (actionMessage != null) {
|
||||
snackBar.setAction(actionMessage) {
|
||||
action(this)
|
||||
}.show()
|
||||
} else {
|
||||
snackBar.show()
|
||||
}
|
||||
}
|
||||
|
||||
fun copyAssetToFile(context: Context, asset: String, path: String) {
|
||||
|
||||
@ -447,8 +447,13 @@
|
||||
<string name="restore_failed">Failed to restore application data. Check that you gave correct
|
||||
password. In Android versions 9 and below, also check Apps → baresip → Permissions → Storage
|
||||
and that file \'%1$s\' exists in Download folder.</string>
|
||||
<string name="no_calls">You are not able to place or answer calls without Microphone permission.</string>
|
||||
<string name="no_video_calls">Grant \"Camera\" permission to place or answer video calls.</string>
|
||||
<string name="no_calls">You are not able to make or answer calls without Microphone and
|
||||
Telephone permissions.</string>
|
||||
<string name="no_backup">You are not able create backup without Storage permission.</string>
|
||||
<string name="no_android_contacts">You are not able add or remove Android contacts without
|
||||
Contacts permission.</string>
|
||||
<string name="no_restore">You are not able restore backup without Storage permission.</string>
|
||||
<string name="no_video_calls">Grant \"Camera\" permission to make or answer video calls.</string>
|
||||
<string name="no_cameras">You don\'t have any supported video cameras.</string>
|
||||
<string name="show_password">Show Password</string>
|
||||
<string name="no_network">No network connection!</string>
|
||||
|
||||
Reference in New Issue
Block a user