- In Android 10+ use picker to choose TLS Certificate and TLS CA Files

- Ask confirmation to reset settings to factory defaults
- Replaced downloadsPath companion variable with Utils function call
- Fixed several Kotlin lint warnings
This commit is contained in:
Juha Heinanen
2021-05-16 11:45:56 +03:00
parent 1177618d42
commit 6e8190ba01
9 changed files with 270 additions and 115 deletions
@@ -65,12 +65,10 @@ class Account(val accp: String) {
fun print() : String { fun print() : String {
var res: String var res = if (displayName != "")
"\"${displayName}\" "
if (displayName != "")
res = "\"${displayName}\" "
else else
res = "" ""
res = "$res<$luri>" res = "$res<$luri>"
@@ -112,10 +110,10 @@ class Account(val accp: String) {
if (preferIPv6Media) res += ";mediaaf=ipv6" if (preferIPv6Media) res += ";mediaaf=ipv6"
if (vmUri == "") res = if (vmUri == "")
res = "$res;mwi=no" "$res;mwi=no"
else else
res = "$res;mwi=yes;vm_uri=\"$vmUri\"" "$res;mwi=yes;vm_uri=\"$vmUri\""
if (answerMode == Api.ANSWERMODE_AUTO) if (answerMode == Api.ANSWERMODE_AUTO)
res += ";answermode=auto" res += ";answermode=auto"
@@ -134,29 +132,35 @@ class Account(val accp: String) {
} }
fun vmMessages(cxt: Context) : String { fun vmMessages(cxt: Context) : String {
var new = ""
var old = "" val new = if (vmNew > 0) {
if (vmNew > 0)
if (vmNew == 1) if (vmNew == 1)
new = cxt.getString(R.string.one_new_message) cxt.getString(R.string.one_new_message)
else else
new = "$vmNew ${cxt.getString(R.string.new_messages)}" "$vmNew ${cxt.getString(R.string.new_messages)}"
if (vmOld > 0) } else
""
val old = if (vmOld > 0) {
if (vmOld == 1) if (vmOld == 1)
old = cxt.getString(R.string.one_old_message) cxt.getString(R.string.one_old_message)
else else
old = "$vmOld ${cxt.getString(R.string.old_messages)}" "$vmOld ${cxt.getString(R.string.old_messages)}"
} else
""
var msg = cxt.getString(R.string.you_have) var msg = cxt.getString(R.string.you_have)
if (new != "") { if (new != "") {
msg = "$msg $new" msg = "$msg $new"
if (old != "") msg = "$msg ${cxt.getString(R.string.and)} $old" if (old != "") msg = "$msg ${cxt.getString(R.string.and)} $old"
} else { } else {
if (old != "") msg = if (old != "")
msg = "$msg $old" "$msg $old"
else else
msg = cxt.getString(R.string.no_messages) cxt.getString(R.string.no_messages)
} }
return "$msg."
return "$msg."
} }
fun host() : String { fun host() : String {
@@ -166,7 +170,7 @@ class Account(val accp: String) {
private fun removeAudioCodecsStartingWith(prefix: String) { private fun removeAudioCodecsStartingWith(prefix: String) {
val newCodecs = ArrayList<String>() val newCodecs = ArrayList<String>()
for (acSpec in audioCodec) for (acSpec in audioCodec)
if (!acSpec.toLowerCase(Locale.ROOT).startsWith(prefix)) newCodecs.add(acSpec) if (!acSpec.lowercase(Locale.ROOT).startsWith(prefix)) newCodecs.add(acSpec)
audioCodec = newCodecs audioCodec = newCodecs
} }
@@ -185,10 +185,8 @@ class AccountsActivity : AppCompatActivity() {
fun saveAccounts() { fun saveAccounts() {
var accounts = "" var accounts = ""
var count = 0
for (a in Account.accounts()) { for (a in Account.accounts()) {
accounts = accounts + a.print() + "\n" accounts = accounts + a.print() + "\n"
count++
} }
Utils.putFileContents(BaresipService.filesPath + "/accounts", accounts.toByteArray()) Utils.putFileContents(BaresipService.filesPath + "/accounts", accounts.toByteArray())
// Log.d(TAG, "Saved accounts '${accounts}' to '${BaresipService.filesPath}/accounts'") // Log.d(TAG, "Saved accounts '${accounts}' to '${BaresipService.filesPath}/accounts'")
@@ -196,7 +194,7 @@ class AccountsActivity : AppCompatActivity() {
fun noAccounts(): Boolean { fun noAccounts(): Boolean {
val contents = Utils.getFileContents(BaresipService.filesPath + "/accounts") val contents = Utils.getFileContents(BaresipService.filesPath + "/accounts")
return contents == null || contents.size == 0 return contents == null || contents.isEmpty()
} }
fun setAuthPass(ua: UserAgent, ap: String) { fun setAuthPass(ua: UserAgent, ap: String) {
@@ -66,7 +66,7 @@ class AudioActivity : AppCompatActivity() {
cb.layoutParams = cbParams cb.layoutParams = cbParams
cb.gravity = Gravity.END cb.gravity = Gravity.END
cb.isChecked = Config.variable("module $module.so").size > 0 cb.isChecked = Config.variable("module $module.so").size > 0
oldAudioModules.put(module, cb.isChecked) oldAudioModules[module] = cb.isChecked
rl.addView(cb) rl.addView(cb)
audioModulesList.addView(rl) audioModulesList.addView(rl)
} }
@@ -63,7 +63,6 @@ class BaresipService: Service() {
intent.setPackage("com.tutpro.baresip") intent.setPackage("com.tutpro.baresip")
filesPath = filesDir.absolutePath filesPath = filesDir.absolutePath
downloadsPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
@@ -1193,7 +1192,6 @@ class BaresipService: Service() {
var dynDns = false var dynDns = false
var netInterface = "" var netInterface = ""
var filesPath = "" var filesPath = ""
var downloadsPath = ""
var logLevel = 2 var logLevel = 2
var sipTrace = false var sipTrace = false
var callActionUri = "" var callActionUri = ""
@@ -1,23 +1,33 @@
package com.tutpro.baresip package com.tutpro.baresip
import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.content.pm.PackageManager
import android.os.Build
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.* import android.widget.*
import android.widget.AdapterView import android.widget.AdapterView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import com.tutpro.baresip.Utils.copyInputStreamToFile
import com.tutpro.baresip.databinding.ActivityConfigBinding import com.tutpro.baresip.databinding.ActivityConfigBinding
import java.io.File
import java.io.FileInputStream
import java.util.*
class ConfigActivity : AppCompatActivity() { class ConfigActivity : AppCompatActivity() {
private val READ_CERT_PERMISSION_CODE = 1 private val READ_CERT_PERMISSION_CODE = 1
private val READ_CA_PERMISSION_CODE = 2 private val READ_CA_PERMISSION_CODE = 2
private val CERTIFICATE_CODE = 1
private val CA_CERTIFICATES_CODE = 2
private lateinit var binding: ActivityConfigBinding private lateinit var binding: ActivityConfigBinding
private lateinit var autoStart: CheckBox private lateinit var autoStart: CheckBox
private lateinit var listenAddr: EditText private lateinit var listenAddr: EditText
@@ -78,6 +88,39 @@ class ConfigActivity : AppCompatActivity() {
oldCertificateFile = Config.variable("sip_certificate").isNotEmpty() oldCertificateFile = Config.variable("sip_certificate").isNotEmpty()
certificateFile.isChecked = oldCertificateFile certificateFile.isChecked = oldCertificateFile
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
}
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(this, CERTIFICATE_CODE)
}
} else {
Config.removeVariable("sip_certificate")
save = true
restart = true
}
}
verifyServer = binding.VerifyServer verifyServer = binding.VerifyServer
val vsCv = Config.variable("sip_verify_server") val vsCv = Config.variable("sip_verify_server")
oldVerifyServer = if (vsCv.size == 0) "no" else vsCv[0] oldVerifyServer = if (vsCv.size == 0) "no" else vsCv[0]
@@ -87,6 +130,39 @@ class ConfigActivity : AppCompatActivity() {
oldCAFile = Config.variable("sip_cafile").isNotEmpty() oldCAFile = Config.variable("sip_cafile").isNotEmpty()
caFile.isChecked = oldCAFile caFile.isChecked = oldCAFile
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
}
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(this, CA_CERTIFICATES_CODE)
}
} else {
Config.removeVariable("sip_cafile")
save = true
restart = true
}
}
val callVolSpinner = binding.VolumeSpinner val callVolSpinner = binding.VolumeSpinner
val volKeys = arrayListOf("None", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10") val volKeys = arrayListOf("None", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10")
val volVals = arrayListOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) val volVals = arrayListOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
@@ -114,10 +190,10 @@ class ConfigActivity : AppCompatActivity() {
debug = binding.Debug debug = binding.Debug
val dbCv = Config.variable("log_level") val dbCv = Config.variable("log_level")
if (dbCv.size == 0) oldLogLevel = if (dbCv.size == 0)
oldLogLevel = "2" "2"
else else
oldLogLevel = dbCv[0] dbCv[0]
debug.isChecked = oldLogLevel == "0" debug.isChecked = oldLogLevel == "0"
sipTrace = binding.SipTrace sipTrace = binding.SipTrace
@@ -126,6 +202,29 @@ class ConfigActivity : AppCompatActivity() {
reset = binding.Reset reset = binding.Reset
reset.isChecked = false reset.isChecked = false
reset.setOnCheckedChangeListener { _, isChecked ->
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)) {
setCustomTitle(titleView)
setMessage(getString(R.string.reset_config_alert))
setPositiveButton(getText(R.string.reset)) { dialog, _ ->
Config.reset(this@ConfigActivity)
save = false
restart = true
done()
dialog.dismiss()
}
setNegativeButton(getText(R.string.cancel)) { dialog, _ ->
reset.isChecked = false
dialog.dismiss()
}
show()
}
}
}
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -170,7 +269,8 @@ class ConfigActivity : AppCompatActivity() {
restart = true restart = true
} }
val dnsServers = addMissingPorts(dnsServers.text.toString().trim().toLowerCase()) val dnsServers = addMissingPorts(
dnsServers.text.toString().trim().lowercase(Locale.ROOT))
if (dnsServers != oldDnsServers) { if (dnsServers != oldDnsServers) {
if (!checkDnsServers(dnsServers)) { if (!checkDnsServers(dnsServers)) {
Utils.alertView(this, getString(R.string.notice), Utils.alertView(this, getString(R.string.notice),
@@ -196,56 +296,6 @@ class ConfigActivity : AppCompatActivity() {
save = true save = true
} }
if (certificateFile.isChecked != oldCertificateFile) {
if (certificateFile.isChecked) {
if (!Utils.requestPermission(this,
android.Manifest.permission.READ_EXTERNAL_STORAGE,
READ_CERT_PERMISSION_CODE))
return false
val content = Utils.getFileContents(BaresipService.downloadsPath + "/cert.pem")
if (content == null) {
Utils.alertView(this, getString(R.string.error),
getString(R.string.read_cert_error))
certificateFile.isChecked = false
return false
}
Utils.putFileContents(BaresipService.filesPath + "/cert.pem", content)
Config.removeVariable("sip_certificate")
Config.addLine("sip_certificate ${BaresipService.filesPath}/cert.pem")
} else {
Config.removeVariable("sip_certificate")
}
save = true
restart = true
}
if (caFile.isChecked != oldCAFile) {
if (caFile.isChecked) {
if (!Utils.requestPermission(this,
android.Manifest.permission.READ_EXTERNAL_STORAGE,
READ_CA_PERMISSION_CODE)) {
caFile.isChecked = false
return false
}
val content = Utils.getFileContents(BaresipService.downloadsPath +
"/ca_certs.crt")
if (content == null) {
Utils.alertView(this, getString(R.string.error),
getString(R.string.read_ca_certs_error))
caFile.isChecked = false
return false
}
Utils.putFileContents(BaresipService.filesPath + "/ca_certs.crt",
content)
Config.removeVariable("sip_cafile")
Config.addLine("sip_cafile ${BaresipService.filesPath}/ca_certs.crt")
} else {
Config.removeVariable("sip_cafile")
}
save = true
restart = true
}
if (verifyServer.isChecked && !caFile.isChecked) { if (verifyServer.isChecked && !caFile.isChecked) {
Utils.alertView(this, getString(R.string.error), Utils.alertView(this, getString(R.string.error),
getString(R.string.verify_server_error)) getString(R.string.verify_server_error))
@@ -285,19 +335,7 @@ class ConfigActivity : AppCompatActivity() {
BaresipService.sipTrace = sipTrace.isChecked BaresipService.sipTrace = sipTrace.isChecked
Api.uag_enable_sip_trace(sipTrace.isChecked) Api.uag_enable_sip_trace(sipTrace.isChecked)
if (reset.isChecked) { done()
Config.reset(this)
save = false
restart = true
}
if (save) Config.save()
BaresipService.activities.remove("config")
val intent = Intent(this, MainActivity::class.java)
if (restart) intent.putExtra("restart", true)
setResult(RESULT_OK, intent)
finish()
} }
@@ -315,6 +353,74 @@ class ConfigActivity : AppCompatActivity() {
} }
private fun done() {
if (save)
Config.save()
BaresipService.activities.remove("config")
val intent = Intent(this, MainActivity::class.java)
if (restart)
intent.putExtra("restart", true)
setResult(RESULT_OK, intent)
finish()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
CERTIFICATE_CODE -> {
if (resultCode == Activity.RESULT_OK)
data?.data?.also {
try {
val inputStream = applicationContext.contentResolver.openInputStream(it)
as FileInputStream
File(BaresipService.filesPath + "/cert.pem")
.copyInputStreamToFile(inputStream)
inputStream.close()
Config.removeVariable("sip_certificate")
Config.addLine("sip_certificate ${BaresipService.filesPath}/cert.pem")
save = true
restart = true
} catch (e: Error) {
Utils.alertView(this, getString(R.string.error),
getString(R.string.read_cert_error))
certificateFile.isChecked = false
}
}
else
certificateFile.isChecked = false
}
CA_CERTIFICATES_CODE -> {
if (resultCode == Activity.RESULT_OK)
data?.data?.also {
try {
val inputStream = applicationContext.contentResolver.openInputStream(it)
as FileInputStream
File(BaresipService.filesPath + "/ca_certs.crt")
.copyInputStreamToFile(inputStream)
inputStream.close()
Config.removeVariable("sip_cafile")
Config.addLine("sip_cafile ${BaresipService.filesPath}/ca_certs.crt")
save = true
restart = true
} catch (e: Error) {
Utils.alertView(this, getString(R.string.error),
getString(R.string.read_ca_certs_error))
caFile.isChecked = false
}
}
else
caFile.isChecked = false
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
grantResults: IntArray) { grantResults: IntArray) {
@@ -322,15 +428,15 @@ class ConfigActivity : AppCompatActivity() {
when (requestCode) { when (requestCode) {
READ_CERT_PERMISSION_CODE -> READ_CERT_PERMISSION_CODE ->
if (grantResults.isNotEmpty() && (grantResults[0] == if (grantResults.isNotEmpty() &&
PackageManager.PERMISSION_GRANTED)) (grantResults[0] == PackageManager.PERMISSION_GRANTED))
menu!!.performIdentifierAction(R.id.checkIcon, 0) menu!!.performIdentifierAction(R.id.checkIcon, 0)
else else
certificateFile.isChecked = false certificateFile.isChecked = false
READ_CA_PERMISSION_CODE -> READ_CA_PERMISSION_CODE ->
if ((grantResults.size > 0) && (grantResults[0] == if (grantResults.isNotEmpty() &&
PackageManager.PERMISSION_GRANTED)) (grantResults[0] == PackageManager.PERMISSION_GRANTED))
menu!!.performIdentifierAction(R.id.checkIcon, 0) menu!!.performIdentifierAction(R.id.checkIcon, 0)
else else
caFile.isChecked = false caFile.isChecked = false
} }
@@ -400,7 +506,7 @@ class ConfigActivity : AppCompatActivity() {
} }
private fun checkDnsServers(dnsServers: String): Boolean { private fun checkDnsServers(dnsServers: String): Boolean {
if (dnsServers.length == 0) return true if (dnsServers.isEmpty()) return true
for (server in dnsServers.split(",")) for (server in dnsServers.split(","))
if (!Utils.checkIpPort(server.trim())) return false if (!Utils.checkIpPort(server.trim())) return false
return true return true
@@ -410,13 +516,13 @@ class ConfigActivity : AppCompatActivity() {
if (addressList == "") return "" if (addressList == "") return ""
var result = "" var result = ""
for (addr in addressList.split(",")) for (addr in addressList.split(","))
if (Utils.checkIpPort(addr)) { result = if (Utils.checkIpPort(addr)) {
result = "$result,$addr" "$result,$addr"
} else { } else {
if (Utils.checkIpV4(addr)) if (Utils.checkIpV4(addr))
result = "$result,$addr:53" "$result,$addr:53"
else else
result = "$result,[$addr]:53" "$result,[$addr]:53"
} }
return result.substring(1) return result.substring(1)
} }
@@ -14,7 +14,6 @@ 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
import android.os.Environment
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.provider.MediaStore import android.provider.MediaStore
import android.text.InputType import android.text.InputType
@@ -1086,11 +1085,14 @@ class MainActivity : AppCompatActivity() {
if (Build.VERSION.SDK_INT >= 29) { if (Build.VERSION.SDK_INT >= 29) {
pickupFileFromDownloads(BACKUP_CODE) pickupFileFromDownloads(BACKUP_CODE)
} else { } else {
if (Utils.requestPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE, if (Utils.requestPermission(
BACKUP_PERMISSION_REQUEST_CODE)) { this,
val filePath = Environment.getExternalStoragePublicDirectory( Manifest.permission.WRITE_EXTERNAL_STORAGE,
Environment.DIRECTORY_DOWNLOADS).path + "/baresip/bs" BACKUP_PERMISSION_REQUEST_CODE
downloadsOutputStream = FileOutputStream(File(filePath)) )
) {
val path = Utils.downloadsPath("baresip.bs")
downloadsOutputStream = FileOutputStream(File(path))
askPassword(getString(R.string.encrypt_password)) askPassword(getString(R.string.encrypt_password))
} }
} }
@@ -1240,7 +1242,7 @@ class MainActivity : AppCompatActivity() {
if (Build.VERSION.SDK_INT >= 29) { if (Build.VERSION.SDK_INT >= 29) {
pickupFileFromDownloads(RESTORE_CODE) pickupFileFromDownloads(RESTORE_CODE)
} else { } else {
val path = BaresipService.downloadsPath + "/baresip.bs" val path = Utils.downloadsPath("baresip.bs")
downloadsInputStream = FileInputStream(File(path)) downloadsInputStream = FileInputStream(File(path))
askPassword(getString(R.string.decrypt_password)) askPassword(getString(R.string.decrypt_password))
} }
@@ -13,14 +13,18 @@ import android.net.LinkAddress
import android.net.LinkProperties import android.net.LinkProperties
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns import android.provider.OpenableColumns
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContentResolverCompat.query import androidx.core.app.ActivityCompat.startActivityForResult
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import java.io.* import java.io.*
@@ -54,7 +58,7 @@ object Utils {
fun removeLinesStartingWithString(lines: String, string: String): String { fun removeLinesStartingWithString(lines: String, string: String): String {
var result = "" var result = ""
for (line in lines.split("\n")) for (line in lines.split("\n"))
if (!line.startsWith(string) && (line.length > 0)) result += line + "\n" if (!line.startsWith(string) && (line.isNotEmpty())) result += line + "\n"
return result return result
} }
@@ -445,6 +449,44 @@ object Utils {
return true return true
} }
fun File.copyInputStreamToFile(inputStream: InputStream): Boolean {
try {
this.outputStream().use { fileOut ->
inputStream.copyTo(fileOut)
}
return true
}
catch (e: IOException) {
Log.e(TAG, "Failed to write file '${this.absolutePath}': $e")
}
return false
}
@RequiresApi(29)
fun selectInputFile(activity: Activity, activityCode: Int) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(DocumentsContract.EXTRA_INITIAL_URI, MediaStore.Downloads.EXTERNAL_CONTENT_URI)
}
startActivityForResult(activity, intent, activityCode, null)
}
@RequiresApi(29)
fun selectOutputFile(title: String) {
Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/octet-stream"
putExtra(Intent.EXTRA_TITLE, title)
putExtra(DocumentsContract.EXTRA_INITIAL_URI, MediaStore.Downloads.EXTERNAL_CONTENT_URI)
}
}
fun downloadsPath(fileName: String): String {
return Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).path + "/$fileName"
}
fun fileNameOfUri(ctx: Context, uri: Uri): String { fun fileNameOfUri(ctx: Context, uri: Uri): String {
val cursor = ctx.contentResolver.query(uri, null, null, null, null) val cursor = ctx.contentResolver.query(uri, null, null, null, null)
var name = "" var name = ""
+2
View File
@@ -353,6 +353,8 @@
<string name="reset_config_help">Jos merkitty, oletusasetukset palautetaan, kun <string name="reset_config_help">Jos merkitty, oletusasetukset palautetaan, kun
baresip seuraavan kerran käynnistetään. baresip seuraavan kerran käynnistetään.
</string> </string>
<string name="reset_config_alert">Oletko varma, että haluat palauttaa oletusasetukset?</string>
<string name="reset">Palauta</string>
<string name="read_cert_error">Tiedoston \'cert.pem\' luku epäonnistui.</string> <string name="read_cert_error">Tiedoston \'cert.pem\' luku epäonnistui.</string>
<string name="read_ca_certs_error">Tiedoston \'ca_certs.crt\' epäonnistui.</string> <string name="read_ca_certs_error">Tiedoston \'ca_certs.crt\' epäonnistui.</string>
<string name="config_restart">baresip täytyy käynnistää uudelleen, jotta saat uudet asetukset <string name="config_restart">baresip täytyy käynnistää uudelleen, jotta saat uudet asetukset
+3
View File
@@ -315,6 +315,9 @@
request and response trace to Logcat. Unchecked automatically at baresip start.</string> request and response trace to Logcat. Unchecked automatically at baresip start.</string>
<string name="reset_config">Reset to Factory Defaults</string> <string name="reset_config">Reset to Factory Defaults</string>
<string name="reset_config_help">If checked, settings are reset to factory default values.</string> <string name="reset_config_help">If checked, settings are reset to factory default values.</string>
<string name="reset_config_alert">Are you sure you want to reset settings to factory
default values?</string>
<string name="reset">Reset</string>
<string name="read_cert_error">Failed to read file \'cert.pem\'.</string> <string name="read_cert_error">Failed to read file \'cert.pem\'.</string>
<string name="read_ca_certs_error">Failed to read file \'ca_certs.crt\'.</string> <string name="read_ca_certs_error">Failed to read file \'ca_certs.crt\'.</string>
<string name="config_restart">You need to restart baresip in order to activate the new <string name="config_restart">You need to restart baresip in order to activate the new