diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatsActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatsActivity.kt index 3c3c41e8..11380fec 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ChatsActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ChatsActivity.kt @@ -8,6 +8,7 @@ import android.view.Menu import android.view.MenuItem import android.widget.* import androidx.activity.OnBackPressedCallback +import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -23,6 +24,7 @@ class ChatsActivity: AppCompatActivity() { private lateinit var plusButton: ImageButton internal lateinit var aor: String internal lateinit var account: Account + private lateinit var chatRequest: ActivityResultLauncher private var scrollPosition = -1 private val onBackPressedCallback = object : OnBackPressedCallback(true) { @@ -57,7 +59,7 @@ class ChatsActivity: AppCompatActivity() { listView.adapter = clAdapter listView.isLongClickable = true - val chatRequest = + chatRequest = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) { clAdapter.clear() @@ -135,34 +137,62 @@ class ChatsActivity: AppCompatActivity() { Contact.contactNames())) plusButton.setOnClickListener { - val uriText = peerUri.text.toString().trim() - if (uriText.isNotEmpty()) { - var uri = Contact.contactUri(uriText, null) - if (uri == null) - uri = if (Utils.isTelNumber(uriText)) - "tel:$uriText" - else - Utils.uriComplete(uriText, aor) - if (!Utils.checkUri(uri)) { - Utils.alertView(this, getString(R.string.notice), - String.format(getString(R.string.invalid_sip_or_tel_uri), uri)) - } else { - peerUri.text.clear() - peerUri.isCursorVisible = false - val i = Intent(this@ChatsActivity, ChatActivity::class.java) - val b = Bundle() - b.putString("aor", aor) - b.putString("peer", uri) - i.putExtras(b) - chatRequest.launch(i) - } - } + makeChat(true) } onBackPressedDispatcher.addCallback(this, onBackPressedCallback) } + private fun makeChat(lookForContact: Boolean = true) { + var uriText = peerUri.text.toString().trim() + if (uriText.isNotEmpty()) { + if (lookForContact) { + val uris = Contact.contactUris(uriText) + if (uris.size == 1) + uriText = uris[0] + else if (uris.size > 1) { + val builder = MaterialAlertDialogBuilder(this, R.style.AlertDialogTheme) + with(builder) { + setTitle("Choose Destination") + setItems(uris.toTypedArray()) { _, which -> + peerUri.setText(uris[which]) + makeChat(false) + } + setNeutralButton(getString(R.string.cancel)) { _: DialogInterface, _: Int -> } + show() + } + return + } + } + if (Utils.isTelNumber(uriText)) + uriText = "tel:$uriText" + val uri = if (Utils.isTelUri(uriText)) { + if (account.telProvider == "") { + Utils.alertView(this, getString(R.string.notice), + String.format(getString(R.string.no_telephony_provider), account.aor)) + return + } + Utils.telToSip(uriText, account) + } else { + Utils.uriComplete(uriText, aor) + } + if (!Utils.checkUri(uri)) { + Utils.alertView(this, getString(R.string.notice), + String.format(getString(R.string.invalid_sip_or_tel_uri), uri)) + } else { + peerUri.text.clear() + peerUri.isCursorVisible = false + val i = Intent(this@ChatsActivity, ChatActivity::class.java) + val b = Bundle() + b.putString("aor", aor) + b.putString("peer", uri) + i.putExtras(b) + chatRequest.launch(i) + } + } + } + override fun onPause() { MainActivity.activityAor = aor super.onPause() diff --git a/app/src/main/kotlin/com/tutpro/baresip/Contact.kt b/app/src/main/kotlin/com/tutpro/baresip/Contact.kt index e35b73e5..d46ee67b 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Contact.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Contact.kt @@ -51,36 +51,28 @@ sealed class Contact { return uri } - // Return uri of contact name or null if contact is not found - // If Android contact has more than one uri, return latest if given and found - fun contactUri(name: String, latest: String?): String? { + // Return URIs of contact name + fun contactUris(name: String): ArrayList { + val uris = ArrayList() for (c in contacts()) when (c) { is BaresipContact -> { - if (c.name.equals(name, ignoreCase = true)) - return c.uri.removePrefix("<") - .replaceAfter(">", "") - .replace(">", "") + if (c.name.equals(name, ignoreCase = true)) { + uris.add(c.uri.removePrefix("<") + .replaceAfter(">", "") + .replace(">", "")) + return uris + } } is AndroidContact -> { if (c.name == name) { - return if (c.uris.isNotEmpty()) { - var uri = c.uris.first() - if (c.uris.size > 1 && latest != null) { - for (u in c.uris) - if (u == latest) { - uri = latest - break - } - } - uri - } else { - null - } + for (u in c.uris) + uris.add(u) + return uris } } } - return null + return uris } fun findContact(uri: String): Contact? { @@ -127,7 +119,7 @@ sealed class Contact { // cursor using getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, - ContactsContract.Data.PHOTO_THUMBNAIL_URI) + /* ContactsContract.Data.DATA2 ,*/ ContactsContract.Data.PHOTO_THUMBNAIL_URI) val selection = ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' OR " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'" @@ -149,8 +141,10 @@ sealed class Contact { contact.name = name if (contact.thumbnailUri == null && thumb != null) contact.thumbnailUri = thumb - if (mime == ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) - contact.uris.add("tel:${data.filterNot{setOf('-', ' ', '(', ')').contains(it)}}") + if (mime == ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) { + contact.uris.add("tel:${data.filterNot { setOf('-', ' ', '(', ')').contains(it) }}") + // contact.types.add(typeToString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE))) + } else if (mime == ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE) contact.uris.add("sip:$data") else @@ -164,6 +158,16 @@ sealed class Contact { BaresipService.androidContacts.add(value) } + @Suppress("unused") + private fun typeToString(type: Int): String { + return when(type) { + ContactsContract.CommonDataKinds.Phone.TYPE_HOME -> "Home" + ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE -> "Mobile" + ContactsContract.CommonDataKinds.Phone.TYPE_WORK -> "Work" + else -> "Unknown" + } + } + fun restoreBaresipContacts(): Boolean { val content = Utils.getFileContents(BaresipService.filesPath + "/contacts") ?: return false @@ -235,8 +239,7 @@ sealed class Contact { is BaresipContact -> BaresipService.contactNames.add(c.name) is AndroidContact -> - if (c.uris.size == 1) - BaresipService.contactNames.add(c.name) + BaresipService.contactNames.add(c.name) } } diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index 6c494f10..152a0d90 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -1448,33 +1448,31 @@ class MainActivity : AppCompatActivity() { dialog.dismiss() var uriText = transferUri.text.toString().trim() if (uriText.isNotEmpty()) { - uriText = Contact.contactUri(uriText, null) ?: uriText - if (Utils.isTelNumber(uriText)) - uriText = "tel:$uriText" - val uri = if (Utils.isTelUri(uriText)) - Utils.telToSip(uriText, ua.account) - else - Utils.uriComplete(uriText, ua.account.aor) - if (!Utils.checkUri(uri)) { - Utils.alertView(this@MainActivity, getString(R.string.notice), - String.format(getString(R.string.invalid_sip_or_tel_uri), uri)) - } else { - val call = ua.currentCall() - if (call != null) { - if (attended.isChecked) { - if (call.hold()) { - call.referTo = uri - call(ua, uri, call) - } - } else { - if (!call.transfer(uri)) { - Utils.alertView(this@MainActivity, getString(R.string.notice), - String.format(getString(R.string.transfer_failed))) - } + val uris = Contact.contactUris(uriText) + if (uris.size > 1) { + val destinationBuilder = MaterialAlertDialogBuilder( + this@MainActivity, + R.style.AlertDialogTheme + ) + with(destinationBuilder) { + setTitle(R.string.choose_destination_uri) + setItems(uris.toTypedArray()) { _, which -> + uriText = uris[which] + transfer( + ua, + if (Utils.isTelNumber(uriText)) "tel:$uriText" else uriText, + attended.isChecked + ) } - showCall(ua) + setNeutralButton(getString(R.string.cancel)) { _: DialogInterface, _: Int -> } + show() } + } else { + if (uris.size == 1) + uriText = uris[0] } + transfer(ua, if (Utils.isTelNumber(uriText)) "tel:$uriText" else uriText, + attended.isChecked) } } setNeutralButton(android.R.string.cancel) { dialog, _ -> @@ -1509,6 +1507,32 @@ class MainActivity : AppCompatActivity() { alertDialog.show() } + private fun transfer(ua: UserAgent, uriText: String, attended: Boolean) { + val uri = if (Utils.isTelUri(uriText)) + Utils.telToSip(uriText, ua.account) + else + Utils.uriComplete(uriText, ua.account.aor) + if (!Utils.checkUri(uri)) { + Utils.alertView(this@MainActivity, getString(R.string.notice), + String.format(getString(R.string.invalid_sip_or_tel_uri), uri)) + } else { + val call = ua.currentCall() + if (call != null) { + if (attended) { + if (call.hold()) { + call.referTo = uri + call(ua, uri, call) + } + } else { + if (!call.transfer(uri)) { + Utils.alertView(this@MainActivity, getString(R.string.notice), + String.format(getString(R.string.transfer_failed))) + } + } + showCall(ua) + } + } + } private fun askPassword(title: String, ua: UserAgent? = null) { val layout = LayoutInflater.from(this) .inflate(R.layout.password_dialog, findViewById(android.R.id.content), @@ -1751,34 +1775,37 @@ class MainActivity : AppCompatActivity() { } } - private fun makeCall() { + private fun makeCall(lookForContact: Boolean = true) { callUri.setAdapter(null) val ua = BaresipService.uas[aorSpinner.selectedItemPosition] val aor = ua.account.aor if (Call.calls().isEmpty()) { var uriText = callUri.text.toString().trim() if (uriText.isNotEmpty()) { - uriText = Contact.contactUri(uriText, NewCallHistory.aorLatestPeerUri(aor)) ?: uriText + if (lookForContact) { + val uris = Contact.contactUris(uriText) + if (uris.size == 1) + uriText = uris[0] + else if (uris.size > 1) { + val builder = MaterialAlertDialogBuilder(this, R.style.AlertDialogTheme) + with(builder) { + setTitle(R.string.choose_destination_uri) + setItems(uris.toTypedArray()) { _, which -> + callUri.setText(uris[which]) + makeCall(false) + } + setNeutralButton(getString(R.string.cancel)) { _: DialogInterface, _: Int -> } + show() + } + return + } + } if (Utils.isTelNumber(uriText)) uriText = "tel:$uriText" val uri = if (Utils.isTelUri(uriText)) { if (ua.account.telProvider == "") { - val telAccounts = Account.telProviderAccounts() - if (telAccounts.isEmpty()) { - Utils.alertView(this, getString(R.string.notice), - getString(R.string.no_telephony_providers)) - } else { - val builder = MaterialAlertDialogBuilder(this, R.style.AlertDialogTheme) - with(builder) { - setTitle(getString(R.string.choose_telephony_provider_account)) - setItems(telAccounts) { _, which -> - spinToAor("sip:${telAccounts[which]}") - makeCall() - } - setNeutralButton("Cancel") { _: DialogInterface, _: Int -> } - show() - } - } + Utils.alertView(this, getString(R.string.notice), + String.format(getString(R.string.no_telephony_provider), aor)) return } Utils.telToSip(uriText, ua.account) @@ -1787,8 +1814,7 @@ class MainActivity : AppCompatActivity() { } if (!Utils.checkUri(uri)) { Utils.alertView(this, getString(R.string.notice), - String.format(getString(R.string.invalid_sip_or_tel_uri), uri) - ) + String.format(getString(R.string.invalid_sip_or_tel_uri), uri)) } else { callUri.isFocusable = false uaAdapter.notifyDataSetChanged() diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 9ff27e8c..63b1efb7 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -479,6 +479,7 @@ Sokeasti Osallistu Siirron kohde + Valitse kohteen URI Siirto Siirto epäonnistui DTMF diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7ca04b1f..32ed7baf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -452,6 +452,7 @@ Blind Attended Transfer destination + Choose destination URI Transfer Transfer failed DTMF