diff --git a/app/src/main/kotlin/com/tutpro/baresip/Account.kt b/app/src/main/kotlin/com/tutpro/baresip/Account.kt index c04263f9..d01bb091 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Account.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Account.kt @@ -65,12 +65,10 @@ class Account(val accp: String) { fun print() : String { - var res: String - - if (displayName != "") - res = "\"${displayName}\" " + var res = if (displayName != "") + "\"${displayName}\" " else - res = "" + "" res = "$res<$luri>" @@ -112,10 +110,10 @@ class Account(val accp: String) { if (preferIPv6Media) res += ";mediaaf=ipv6" - if (vmUri == "") - res = "$res;mwi=no" + res = if (vmUri == "") + "$res;mwi=no" else - res = "$res;mwi=yes;vm_uri=\"$vmUri\"" + "$res;mwi=yes;vm_uri=\"$vmUri\"" if (answerMode == Api.ANSWERMODE_AUTO) res += ";answermode=auto" @@ -134,29 +132,35 @@ class Account(val accp: String) { } fun vmMessages(cxt: Context) : String { - var new = "" - var old = "" - if (vmNew > 0) + + val new = if (vmNew > 0) { if (vmNew == 1) - new = cxt.getString(R.string.one_new_message) + cxt.getString(R.string.one_new_message) else - new = "$vmNew ${cxt.getString(R.string.new_messages)}" - if (vmOld > 0) + "$vmNew ${cxt.getString(R.string.new_messages)}" + } else + "" + + val old = if (vmOld > 0) { if (vmOld == 1) - old = cxt.getString(R.string.one_old_message) + cxt.getString(R.string.one_old_message) 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) if (new != "") { msg = "$msg $new" if (old != "") msg = "$msg ${cxt.getString(R.string.and)} $old" } else { - if (old != "") - msg = "$msg $old" + msg = if (old != "") + "$msg $old" else - msg = cxt.getString(R.string.no_messages) + cxt.getString(R.string.no_messages) } - return "$msg." + + return "$msg." } fun host() : String { @@ -166,7 +170,7 @@ class Account(val accp: String) { private fun removeAudioCodecsStartingWith(prefix: String) { val newCodecs = ArrayList() 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 } diff --git a/app/src/main/kotlin/com/tutpro/baresip/AccountsActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/AccountsActivity.kt index 3d7161af..72452521 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/AccountsActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/AccountsActivity.kt @@ -185,10 +185,8 @@ class AccountsActivity : AppCompatActivity() { fun saveAccounts() { var accounts = "" - var count = 0 for (a in Account.accounts()) { accounts = accounts + a.print() + "\n" - count++ } Utils.putFileContents(BaresipService.filesPath + "/accounts", accounts.toByteArray()) // Log.d(TAG, "Saved accounts '${accounts}' to '${BaresipService.filesPath}/accounts'") @@ -196,7 +194,7 @@ class AccountsActivity : AppCompatActivity() { fun noAccounts(): Boolean { val contents = Utils.getFileContents(BaresipService.filesPath + "/accounts") - return contents == null || contents.size == 0 + return contents == null || contents.isEmpty() } fun setAuthPass(ua: UserAgent, ap: String) { diff --git a/app/src/main/kotlin/com/tutpro/baresip/AudioActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/AudioActivity.kt index 04445e08..a422a241 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/AudioActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/AudioActivity.kt @@ -66,7 +66,7 @@ class AudioActivity : AppCompatActivity() { cb.layoutParams = cbParams cb.gravity = Gravity.END cb.isChecked = Config.variable("module $module.so").size > 0 - oldAudioModules.put(module, cb.isChecked) + oldAudioModules[module] = cb.isChecked rl.addView(cb) audioModulesList.addView(rl) } diff --git a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt index 8beb75e2..fa8ed434 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt @@ -63,7 +63,6 @@ class BaresipService: Service() { intent.setPackage("com.tutpro.baresip") filesPath = filesDir.absolutePath - downloadsPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path am = getSystemService(Context.AUDIO_SERVICE) as AudioManager @@ -1193,7 +1192,6 @@ class BaresipService: Service() { var dynDns = false var netInterface = "" var filesPath = "" - var downloadsPath = "" var logLevel = 2 var sipTrace = false var callActionUri = "" diff --git a/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt index 58d6ffcc..aef89552 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt @@ -1,23 +1,33 @@ package com.tutpro.baresip +import android.Manifest import android.app.Activity import android.content.Intent -import android.content.pm.PackageManager import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import android.content.pm.PackageManager +import android.os.Build import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.* import android.widget.AdapterView +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDelegate +import com.tutpro.baresip.Utils.copyInputStreamToFile import com.tutpro.baresip.databinding.ActivityConfigBinding +import java.io.File +import java.io.FileInputStream +import java.util.* class ConfigActivity : AppCompatActivity() { private val READ_CERT_PERMISSION_CODE = 1 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 autoStart: CheckBox private lateinit var listenAddr: EditText @@ -78,6 +88,39 @@ class ConfigActivity : AppCompatActivity() { oldCertificateFile = Config.variable("sip_certificate").isNotEmpty() 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 val vsCv = Config.variable("sip_verify_server") oldVerifyServer = if (vsCv.size == 0) "no" else vsCv[0] @@ -87,6 +130,39 @@ class ConfigActivity : AppCompatActivity() { oldCAFile = Config.variable("sip_cafile").isNotEmpty() 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 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) @@ -114,10 +190,10 @@ class ConfigActivity : AppCompatActivity() { debug = binding.Debug val dbCv = Config.variable("log_level") - if (dbCv.size == 0) - oldLogLevel = "2" + oldLogLevel = if (dbCv.size == 0) + "2" else - oldLogLevel = dbCv[0] + dbCv[0] debug.isChecked = oldLogLevel == "0" sipTrace = binding.SipTrace @@ -126,6 +202,29 @@ class ConfigActivity : AppCompatActivity() { reset = binding.Reset 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 { @@ -170,7 +269,8 @@ class ConfigActivity : AppCompatActivity() { restart = true } - val dnsServers = addMissingPorts(dnsServers.text.toString().trim().toLowerCase()) + val dnsServers = addMissingPorts( + dnsServers.text.toString().trim().lowercase(Locale.ROOT)) if (dnsServers != oldDnsServers) { if (!checkDnsServers(dnsServers)) { Utils.alertView(this, getString(R.string.notice), @@ -196,56 +296,6 @@ class ConfigActivity : AppCompatActivity() { 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) { Utils.alertView(this, getString(R.string.error), getString(R.string.verify_server_error)) @@ -285,19 +335,7 @@ class ConfigActivity : AppCompatActivity() { BaresipService.sipTrace = sipTrace.isChecked Api.uag_enable_sip_trace(sipTrace.isChecked) - if (reset.isChecked) { - 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() + done() } @@ -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, grantResults: IntArray) { @@ -322,15 +428,15 @@ class ConfigActivity : AppCompatActivity() { when (requestCode) { READ_CERT_PERMISSION_CODE -> - if (grantResults.isNotEmpty() && (grantResults[0] == - PackageManager.PERMISSION_GRANTED)) - menu!!.performIdentifierAction(R.id.checkIcon, 0) + if (grantResults.isNotEmpty() && + (grantResults[0] == PackageManager.PERMISSION_GRANTED)) + menu!!.performIdentifierAction(R.id.checkIcon, 0) else certificateFile.isChecked = false READ_CA_PERMISSION_CODE -> - if ((grantResults.size > 0) && (grantResults[0] == - PackageManager.PERMISSION_GRANTED)) - menu!!.performIdentifierAction(R.id.checkIcon, 0) + if (grantResults.isNotEmpty() && + (grantResults[0] == PackageManager.PERMISSION_GRANTED)) + menu!!.performIdentifierAction(R.id.checkIcon, 0) else caFile.isChecked = false } @@ -400,7 +506,7 @@ class ConfigActivity : AppCompatActivity() { } private fun checkDnsServers(dnsServers: String): Boolean { - if (dnsServers.length == 0) return true + if (dnsServers.isEmpty()) return true for (server in dnsServers.split(",")) if (!Utils.checkIpPort(server.trim())) return false return true @@ -410,13 +516,13 @@ class ConfigActivity : AppCompatActivity() { if (addressList == "") return "" var result = "" for (addr in addressList.split(",")) - if (Utils.checkIpPort(addr)) { - result = "$result,$addr" + result = if (Utils.checkIpPort(addr)) { + "$result,$addr" } else { if (Utils.checkIpV4(addr)) - result = "$result,$addr:53" + "$result,$addr:53" else - result = "$result,[$addr]:53" + "$result,[$addr]:53" } return result.substring(1) } diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index c8522d58..89a1b4f1 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -14,7 +14,6 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.os.CountDownTimer -import android.os.Environment import android.provider.DocumentsContract import android.provider.MediaStore import android.text.InputType @@ -1086,11 +1085,14 @@ class MainActivity : AppCompatActivity() { if (Build.VERSION.SDK_INT >= 29) { pickupFileFromDownloads(BACKUP_CODE) } else { - if (Utils.requestPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE, - BACKUP_PERMISSION_REQUEST_CODE)) { - val filePath = Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_DOWNLOADS).path + "/baresip/bs" - downloadsOutputStream = FileOutputStream(File(filePath)) + if (Utils.requestPermission( + this, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + BACKUP_PERMISSION_REQUEST_CODE + ) + ) { + val path = Utils.downloadsPath("baresip.bs") + downloadsOutputStream = FileOutputStream(File(path)) askPassword(getString(R.string.encrypt_password)) } } @@ -1240,7 +1242,7 @@ class MainActivity : AppCompatActivity() { if (Build.VERSION.SDK_INT >= 29) { pickupFileFromDownloads(RESTORE_CODE) } else { - val path = BaresipService.downloadsPath + "/baresip.bs" + val path = Utils.downloadsPath("baresip.bs") downloadsInputStream = FileInputStream(File(path)) askPassword(getString(R.string.decrypt_password)) } diff --git a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt index 3ab20e2c..71287141 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt @@ -13,14 +13,18 @@ import android.net.LinkAddress import android.net.LinkProperties import android.net.Uri import android.os.Bundle +import android.os.Environment +import android.provider.DocumentsContract +import android.provider.MediaStore import android.provider.OpenableColumns import android.text.Editable import android.text.TextWatcher import android.view.View import android.widget.TextView +import androidx.annotation.RequiresApi import androidx.appcompat.app.AlertDialog import androidx.core.app.ActivityCompat -import androidx.core.content.ContentResolverCompat.query +import androidx.core.app.ActivityCompat.startActivityForResult import androidx.core.content.ContextCompat import java.io.* @@ -54,7 +58,7 @@ object Utils { fun removeLinesStartingWithString(lines: String, string: String): String { var result = "" 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 } @@ -445,6 +449,44 @@ object Utils { 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 { val cursor = ctx.contentResolver.query(uri, null, null, null, null) var name = "" diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 3aa6a307..6e739699 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -353,6 +353,8 @@ Jos merkitty, oletusasetukset palautetaan, kun baresip seuraavan kerran käynnistetään. + Oletko varma, että haluat palauttaa oletusasetukset? + Palauta Tiedoston \'cert.pem\' luku epäonnistui. Tiedoston \'ca_certs.crt\' epäonnistui. baresip täytyy käynnistää uudelleen, jotta saat uudet asetukset diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c733af23..d100f0b9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -315,6 +315,9 @@ request and response trace to Logcat. Unchecked automatically at baresip start. Reset to Factory Defaults If checked, settings are reset to factory default values. + Are you sure you want to reset settings to factory + default values? + Reset Failed to read file \'cert.pem\'. Failed to read file \'ca_certs.crt\'. You need to restart baresip in order to activate the new