diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 62fd92a1..82a2e3a1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -85,7 +85,7 @@
@@ -95,18 +95,11 @@
android:label="@string/contact"
android:parentActivityName=".ContactsActivity" >
-
-
+ android:parentActivityName=".ContactsActivity" >
()
-
- companion object {
-
- fun contacts(): ArrayList {
- return BaresipService.androidContacts
- }
- }
-
-}
diff --git a/app/src/main/kotlin/com/tutpro/baresip/AndroidContactActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/AndroidContactActivity.kt
index ae9ce1b4..f8cfeb10 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/AndroidContactActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/AndroidContactActivity.kt
@@ -26,7 +26,6 @@ class AndroidContactActivity : AppCompatActivity() {
private var index = 0
private var color = 0
- private var id: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
@@ -43,10 +42,9 @@ class AndroidContactActivity : AppCompatActivity() {
cardImageAvatarView = binding.ImageAvatar
nameView = binding.Name
- val contact = BaresipService.androidContacts[index]
+ val contact = Contact.contacts()[index] as Contact.AndroidContact
val name = contact.name
color = contact.color
- id = contact.id
val thumbnailUri = contact.thumbnailUri
if (thumbnailUri != null)
showImageAvatar(thumbnailUri)
@@ -105,5 +103,3 @@ class AndroidContactActivity : AppCompatActivity() {
}
}
-
-
diff --git a/app/src/main/kotlin/com/tutpro/baresip/AndroidContactListAdapter.kt b/app/src/main/kotlin/com/tutpro/baresip/AndroidContactListAdapter.kt
deleted file mode 100644
index ca0bd64d..00000000
--- a/app/src/main/kotlin/com/tutpro/baresip/AndroidContactListAdapter.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.tutpro.baresip
-
-import android.content.Context
-import android.content.Intent
-import android.os.Bundle
-import android.os.SystemClock
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ArrayAdapter
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.core.content.ContextCompat.startActivity
-
-class AndroidContactListAdapter(private val ctx: Context,
- private val rows: ArrayList,
- private val aor: String) :
- ArrayAdapter(ctx, R.layout.android_contact_row, rows) {
-
- private val layoutInflater = LayoutInflater.from(context)
- private var lastClick: Long = 0
-
- private class ViewHolder(view: View?) {
- val textAvatarView = view?.findViewById(R.id.TextAvatar) as TextView
- val imageAvatarView = view?.findViewById(R.id.ImageAvatar) as ImageView
- val nameView = view?.findViewById(R.id.contactName) as TextView
- }
-
- override fun getView(position: Int, view: View?, parent: ViewGroup): View {
-
- val viewHolder: ViewHolder
- val rowView: View
-
- if (view == null) {
- rowView = layoutInflater.inflate(R.layout.android_contact_row, parent, false)
- viewHolder = ViewHolder(rowView)
- rowView.tag = viewHolder
- } else {
- rowView = view
- viewHolder = rowView.tag as ViewHolder
- }
-
- val contact = rows[position]
-
- val thumbNailUri = contact.thumbnailUri
- if (thumbNailUri != null) {
- viewHolder.imageAvatarView.setImageURI(thumbNailUri)
- } else {
- viewHolder.textAvatarView.background.setTint(contact.color)
- if (contact.name.isNotEmpty())
- viewHolder.textAvatarView.text = "${contact.name[0]}"
- else
- viewHolder.textAvatarView.text = ""
- viewHolder.imageAvatarView.setImageBitmap(Utils.bitmapFromView(viewHolder.textAvatarView))
- }
-
- viewHolder.nameView.text = contact.name
- viewHolder.nameView.textSize = 20f
- viewHolder.nameView.setPadding(6, 6, 0, 6)
-
- viewHolder.nameView.setOnClickListener {
- if (SystemClock.elapsedRealtime() - lastClick > 1000) {
- lastClick = SystemClock.elapsedRealtime()
- val i = Intent(ctx, AndroidContactActivity::class.java)
- val b = Bundle()
- b.putString("aor", aor)
- b.putInt("index", position)
- i.putExtras(b)
- startActivity(ctx, i, null)
- }
- }
-
- return rowView
- }
-}
diff --git a/app/src/main/kotlin/com/tutpro/baresip/AndroidContactsActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/AndroidContactsActivity.kt
deleted file mode 100644
index 5b322597..00000000
--- a/app/src/main/kotlin/com/tutpro/baresip/AndroidContactsActivity.kt
+++ /dev/null
@@ -1,228 +0,0 @@
-package com.tutpro.baresip
-
-import android.Manifest
-import android.app.Activity
-import android.content.*
-import android.content.pm.PackageManager
-import android.database.Cursor
-import android.os.Build
-import android.os.Bundle
-import android.os.SystemClock
-import android.provider.ContactsContract
-import android.view.Menu
-import androidx.appcompat.app.AppCompatActivity
-import android.view.MenuItem
-import android.widget.RelativeLayout
-import androidx.activity.result.ActivityResultLauncher
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.core.app.ActivityCompat
-import androidx.core.net.toUri
-import com.google.android.material.snackbar.Snackbar
-import com.tutpro.baresip.Utils.showSnackBar
-import com.tutpro.baresip.databinding.ActivityAndroidContactsBinding
-
-class AndroidContactsActivity : AppCompatActivity() {
-
- private lateinit var binding: ActivityAndroidContactsBinding
- private lateinit var layout: RelativeLayout
- private lateinit var clAdapter: AndroidContactListAdapter
- private lateinit var aor: String
- private var lastSwap: Long = 0
- private lateinit var permissionsLauncher: ActivityResultLauncher>
- private val permissions = arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)
-
- public override fun onCreate(savedInstanceState: Bundle?) {
-
- super.onCreate(savedInstanceState)
- binding = ActivityAndroidContactsBinding.inflate(layoutInflater)
- setContentView(binding.root)
- layout = binding.AndroidContactsView
-
- aor = intent.getStringExtra("aor")!!
-
- val listView = binding.androidContacts
-
- permissionsLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
- var allowed = true
- permissions.entries.forEach {
- allowed = allowed && it.value
- }
- if (allowed) {
- fetchAndroidContacts(this)
- clAdapter.notifyDataSetChanged()
- }
- }
-
- if (Build.VERSION.SDK_INT >= 23 && !Utils.checkPermissions(this, permissions))
- requestPermissions(permissions, CONTACT_PERMISSION_REQUEST_CODE)
-
- clAdapter = AndroidContactListAdapter(this, BaresipService.androidContacts, aor)
- listView.adapter = clAdapter
-
- Utils.addActivity("android contacts,$aor")
-
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.swap_contacts_icon, menu)
- return super.onCreateOptionsMenu(menu)
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
-
- when (item.itemId) {
-
- R.id.swapIcon -> {
- if (SystemClock.elapsedRealtime() - lastSwap > 1000) {
- lastSwap = SystemClock.elapsedRealtime()
- BaresipService.activities.remove("android contacts,$aor")
- val intent = Intent(this, ContactsActivity::class.java)
- intent.putExtra("aor", aor)
- startActivity(intent)
- finish()
- return true
- }
- }
-
- android.R.id.home -> {
- BaresipService.activities.remove("android contacts,$aor")
- setResult(Activity.RESULT_OK, Intent())
- finish()
- }
- }
-
- return true
-
- }
-
- override fun onBackPressed() {
-
- BaresipService.activities.remove("android contacts,$aor")
- setResult(Activity.RESULT_OK, Intent())
- finish()
-
- }
-
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array,
- grandResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grandResults)
- when (requestCode) {
- CONTACT_PERMISSION_REQUEST_CODE -> {
- var allowed = true
- for (res in grandResults)
- allowed = allowed && res == PackageManager.PERMISSION_GRANTED
- if (allowed) {
- fetchAndroidContacts(this)
- clAdapter.notifyDataSetChanged()
- } else {
- when {
- ActivityCompat.shouldShowRequestPermissionRationale(this,
- Manifest.permission.READ_CONTACTS) -> {
- layout.showSnackBar(
- binding.root,
- getString(R.string.no_android_contacts),
- Snackbar.LENGTH_INDEFINITE,
- getString(R.string.ok)
- ) {
- permissionsLauncher.launch(permissions)
- }
- }
- ActivityCompat.shouldShowRequestPermissionRationale(this,
- Manifest.permission.WRITE_CONTACTS) -> {
- layout.showSnackBar(
- binding.root,
- getString(R.string.no_android_contacts),
- Snackbar.LENGTH_INDEFINITE,
- getString(R.string.ok)
- ) {
- permissionsLauncher.launch(permissions)
- }
- }
- else -> {
- permissionsLauncher.launch(permissions)
- }
- }
- }
- }
- }
- }
-
- companion object {
-
- fun fetchAndroidContacts(ctx: Context) {
- val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME,
- ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1,
- 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 + "'"
- val cur: Cursor? = ctx.contentResolver.query(ContactsContract.Data.CONTENT_URI, projection,
- selection, null, null)
- val contacts = HashMap()
- while (cur != null && cur.moveToNext()) {
- val id = cur.getLong(0)
- val name = cur.getString(1) ?: ""
- val mime = cur.getString(2)
- val data = cur.getString(3)
- val thumb = cur.getString(4)?.toUri()
- val contact = if (contacts.containsKey(id))
- contacts[id]!!
- else
- AndroidContact(id, name, Utils.randomColor(), thumb)
- if (contact.name == "" && name != "")
- 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)}}")
- else if (mime == ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
- contact.uris.add("sip:$data")
- else
- continue
- if (!contacts.containsKey(id))
- contacts[id] = contact
- }
- cur?.close()
- BaresipService.androidContacts.clear()
- for ((_, value) in contacts)
- if (value.name != "")
- BaresipService.androidContacts.add(value)
- Utils.reloadContactNames()
- return
- }
-
- fun findContact(uri: String): AndroidContact? {
- for (c in BaresipService.androidContacts)
- for (u in c.uris)
- if (Utils.uriMatch(u, uri))
- return c
- return null
- }
-
- // Return contact name of uri or uri itself if contact with uri is not found
- fun contactName(uri: String): String {
- val userPart = Utils.uriUserPart(uri)
- return if (Utils.isTelNumber(userPart))
- findContact("tel:$userPart")?.name ?: uri
- else
- findContact(uri)?.name ?: uri
- }
-
- // Return first sip (preferred) or tel uri of contact name or
- // null if contact is not found or if it has no uris
- fun contactUri(name: String): String? {
- for (c in BaresipService.androidContacts)
- if (c.name == name) {
- if (c.uris.isNotEmpty()) {
- for (u in c.uris)
- if (u.startsWith("sip:"))
- return u
- return c.uris.first()
- }
- }
- return null
- }
-
- }
-
-}
diff --git a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt
index 4e4ba9f6..332a02ec 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt
@@ -41,6 +41,7 @@ import java.io.File
import java.net.InetAddress
import java.nio.charset.StandardCharsets
import java.util.*
+import kotlin.collections.ArrayList
import kotlin.concurrent.schedule
import kotlin.math.roundToInt
@@ -74,6 +75,7 @@ class BaresipService: Service() {
private var hotSpotIsEnabled = false
private var hotSpotAddresses = mapOf()
private var mediaPlayer: MediaPlayer? = null
+ private var contentObserverRegistered = false
@SuppressLint("WakelockTimeout")
override fun onCreate() {
@@ -299,33 +301,28 @@ class BaresipService: Service() {
this.registerReceiver(bluetoothReceiver, filter)
}
- val contentObserver: ContentObserver = object : ContentObserver(null) {
+ contentObserver = object : ContentObserver(null) {
override fun onChange(self: Boolean) {
Log.d(TAG, "Contacts change")
- AndroidContactsActivity.fetchAndroidContacts(this@BaresipService.applicationContext)
+ if (contactsMode != "baresip") {
+ Contact.loadAndroidContacts(this@BaresipService.applicationContext)
+ Contact.contactsUpdate()
+ }
}
}
- try {
- AndroidContactsActivity.fetchAndroidContacts(this)
- contentResolver.registerContentObserver(
- ContactsContract.Contacts.CONTENT_URI, true, contentObserver)
- } catch(e: SecurityException) {
- Log.i(TAG, "No Contacts permission")
- }
-
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- val action: String
+ val action: String?
if (intent == null) {
action = "Start"
Log.d(TAG, "Received onStartCommand with null intent")
} else {
// Utils.dumpIntent(intent)
- action = intent.action!!
+ action = intent.action
Log.d(TAG, "Received onStartCommand action $action")
}
@@ -359,13 +356,21 @@ class BaresipService: Service() {
Log.i(TAG, "Asset '$a' already copied")
}
if (a == "config")
- Config.initialize()
+ Config.initialize(applicationContext)
}
if (File(filesDir, "history").exists())
File(filesDir, "history").renameTo(File(filesDir, "calls"))
- Contact.restore()
+
+ if (contactsMode != "Android")
+ Contact.restoreBaresipContacts()
+ if (contactsMode != "baresip") {
+ Contact.loadAndroidContacts(applicationContext)
+ registerContentObserver()
+ }
+ Contact.contactsUpdate()
+
val history = CallHistory.get()
if (history.isEmpty()) {
NewCallHistory.restore()
@@ -417,6 +422,14 @@ class BaresipService: Service() {
}
+ "Start Content Observer" -> {
+ registerContentObserver()
+ }
+
+ "Stop Content Observer" -> {
+ unRegisterContentObserver()
+ }
+
"Call Answer" -> {
val uap = intent!!.getStringExtra("uap")!!
val callp = intent.getStringExtra("callp")!!
@@ -666,7 +679,7 @@ class BaresipService: Service() {
PendingIntent.getActivity(applicationContext, CALL_REQ_CODE, intent,
PendingIntent.FLAG_UPDATE_CURRENT)
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
- val caller = Utils.friendlyUri(Utils.contactName(peerUri), Utils.aorDomain(aor))
+ val caller = Utils.friendlyUri(Contact.contactName(peerUri), Utils.aorDomain(aor))
nb.setSmallIcon(R.drawable.ic_stat_call)
.setColor(ContextCompat.getColor(this, R.color.colorBaresip))
.setContentIntent(pi)
@@ -760,7 +773,7 @@ class BaresipService: Service() {
PendingIntent.getActivity(applicationContext, TRANSFER_REQ_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT)
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
- val target = Utils.friendlyUri(Utils.contactName(ev[1]), Utils.aorDomain(aor))
+ val target = Utils.friendlyUri(Contact.contactName(ev[1]), Utils.aorDomain(aor))
nb.setSmallIcon(R.drawable.ic_stat_call)
.setColor(ContextCompat.getColor(this, R.color.colorBaresip))
.setContentIntent(pi)
@@ -836,7 +849,7 @@ class BaresipService: Service() {
}
if (!Utils.isVisible()) {
if (missed) {
- val caller = Utils.friendlyUri(Utils.contactName(call.peerUri), Utils.aorDomain(aor))
+ val caller = Utils.friendlyUri(Contact.contactName(call.peerUri), Utils.aorDomain(aor))
val intent = Intent(applicationContext, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or
Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
@@ -942,7 +955,7 @@ class BaresipService: Service() {
PendingIntent.getActivity(applicationContext, MESSAGE_REQ_CODE, intent,
PendingIntent.FLAG_UPDATE_CURRENT)
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
- val sender = Utils.friendlyUri(Utils.contactName(peer), Utils.aorDomain(ua.account.aor))
+ val sender = Utils.friendlyUri(Contact.contactName(peer), Utils.aorDomain(ua.account.aor))
nb.setSmallIcon(R.drawable.ic_stat_message)
.setColor(ContextCompat.getColor(this, R.color.colorBaresip))
.setContentIntent(pi)
@@ -1389,6 +1402,24 @@ class BaresipService: Service() {
return false
}
+ private fun registerContentObserver() {
+ if (!contentObserverRegistered)
+ try {
+ contentResolver.registerContentObserver(ContactsContract.Contacts.CONTENT_URI,
+ true, contentObserver)
+ contentObserverRegistered = true
+ } catch (e: SecurityException) {
+ Log.i(TAG, "No Contacts permission")
+ }
+ }
+
+ private fun unRegisterContentObserver() {
+ if (contentObserverRegistered) {
+ contentResolver.unregisterContentObserver(contentObserver)
+ contentObserverRegistered = false
+ }
+ }
+
private fun cleanService() {
am.mode = AudioManager.MODE_NORMAL
abandonAudioFocus()
@@ -1429,7 +1460,6 @@ class BaresipService: Service() {
var callActionUri = ""
var isMainVisible = false
var isMicMuted = false
- var preferAndroidContacts = false
val uas = ArrayList()
val status = ArrayList()
@@ -1437,10 +1467,13 @@ class BaresipService: Service() {
var callHistory = ArrayList()
var messages = ArrayList()
val messageUpdate = MutableLiveData()
+ val contactUpdate = MutableLiveData()
val registrationUpdate = MutableLiveData()
+ val baresipContacts = ArrayList()
+ val androidContacts = ArrayList()
val contacts = ArrayList()
- val androidContacts = ArrayList()
- val contactNames = mutableListOf()
+ val contactNames = ArrayList()
+ var contactsMode = "baresip"
val chatTexts: MutableMap = mutableMapOf()
val activities = mutableListOf()
var dnsServers = listOf()
diff --git a/app/src/main/kotlin/com/tutpro/baresip/CallListAdapter.kt b/app/src/main/kotlin/com/tutpro/baresip/CallListAdapter.kt
index 272dd511..3fcb65c7 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/CallListAdapter.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/CallListAdapter.kt
@@ -62,7 +62,7 @@ class CallListAdapter(private val ctx: Context, private val aor: String, private
if (count <= 3)
viewHolder.etcView.text = ""
- val contactName = Utils.contactName(callRow.peerUri)
+ val contactName = Contact.contactName(callRow.peerUri)
if (contactName.startsWith("sip:"))
viewHolder.peerURIView.text = Utils.friendlyUri(contactName, Utils.aorDomain(callRow.aor))
else
diff --git a/app/src/main/kotlin/com/tutpro/baresip/CallsActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/CallsActivity.kt
index ce5f435c..d0cada1a 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/CallsActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/CallsActivity.kt
@@ -50,7 +50,7 @@ class CallsActivity : AppCompatActivity() {
listView.onItemClickListener = AdapterView.OnItemClickListener { _, _, pos, _ ->
val peerUri = uaHistory[pos].peerUri
- var peerName = Utils.contactName(peerUri)
+ var peerName = Contact.contactName(peerUri)
if (peerName.startsWith("sip:"))
peerName = Utils.friendlyUri(peerName, Utils.aorDomain(aor))
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
@@ -95,7 +95,7 @@ class CallsActivity : AppCompatActivity() {
listView.onItemLongClickListener = AdapterView.OnItemLongClickListener { _, _, pos, _ ->
val peerUri = uaHistory[pos].peerUri
- val peerName = Utils.contactName(peerUri)
+ val peerName = Contact.contactName(peerUri)
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_NEGATIVE -> {
diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt
index 62453d07..8d79cd7a 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt
@@ -63,7 +63,7 @@ class ChatActivity : AppCompatActivity() {
imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
this@ChatActivity.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
- var chatPeer = Utils.contactName(peerUri)
+ var chatPeer = Contact.contactName(peerUri)
if (chatPeer.startsWith("sip:"))
chatPeer = Utils.friendlyUri(chatPeer, Utils.aorDomain(aor))
@@ -112,7 +112,7 @@ class ChatActivity : AppCompatActivity() {
}
}
val builder = AlertDialog.Builder(this@ChatActivity, R.style.Theme_AppCompat)
- if (Utils.contactName(peerUri) == peerUri)
+ if (Contact.contactName(peerUri) == peerUri)
with (builder) {
setMessage(String.format(getString(R.string.long_message_question),
chatPeer))
diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatListAdapter.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatListAdapter.kt
index 6d4fa48d..2c0e92ed 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/ChatListAdapter.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/ChatListAdapter.kt
@@ -52,7 +52,7 @@ class ChatListAdapter(private val ctx: Context, private val rows: ArrayList {
val peerUri = uaMessages[pos].peerUri
- val msgs = ArrayList()
+ val messages = ArrayList()
for (m in Message.messages())
if ((m.aor != aor) || (m.peerUri != peerUri))
- msgs.add(m)
+ messages.add(m)
else
clAdapter.remove(m)
clAdapter.notifyDataSetChanged()
- BaresipService.messages = msgs
+ BaresipService.messages = messages
Message.save()
uaMessages = uaMessages(aor)
}
@@ -95,7 +95,7 @@ class ChatsActivity: AppCompatActivity() {
}
val builder = AlertDialog.Builder(this@ChatsActivity, R.style.Theme_AppCompat)
- val peer = Utils.contactName(uaMessages[pos].peerUri)
+ val peer = Contact.contactName(uaMessages[pos].peerUri)
if (peer.startsWith("sip:"))
with (builder) {
setMessage(String.format(getString(R.string.long_chat_question),
@@ -118,12 +118,12 @@ class ChatsActivity: AppCompatActivity() {
peerUri = binding.peer
peerUri.threshold = 2
peerUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
- Utils.contactNames()))
+ Contact.contactNames()))
plusButton.setOnClickListener {
val uriText = peerUri.text.toString().trim()
if (uriText.isNotEmpty()) {
- var uri = Utils.contactUri(uriText)
+ var uri = Contact.contactUri(uriText)
if (uri == null)
uri = if (Utils.isTelNumber(uriText))
"tel:$uriText"
diff --git a/app/src/main/kotlin/com/tutpro/baresip/Config.kt b/app/src/main/kotlin/com/tutpro/baresip/Config.kt
index b9ac9d59..31d41a0b 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/Config.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/Config.kt
@@ -1,5 +1,6 @@
package com.tutpro.baresip
+import android.Manifest
import android.content.Context
import java.net.InetAddress
import java.nio.charset.StandardCharsets
@@ -9,7 +10,7 @@ object Config {
private val configPath = BaresipService.filesPath + "/config"
private var config = String(Utils.getFileContents(configPath)!!, StandardCharsets.ISO_8859_1)
- fun initialize() {
+ fun initialize(ctx: Context) {
config = config.replace("module_tmp uuid.so", "module uuid.so")
@@ -85,7 +86,19 @@ object Config {
config = "${config}jitter_buffer_wish 6\n"
}
- BaresipService.preferAndroidContacts = config.contains("prefer_android_contacts yes")
+ removeVariable("prefer_android_contacts")
+
+ if (config.contains("contacts_mode")) {
+ BaresipService.contactsMode = variable("contacts_mode")[0]
+ if (BaresipService.contactsMode != "baresip" &&
+ !Utils.checkPermissions(ctx, arrayOf(Manifest.permission.READ_CONTACTS,
+ Manifest.permission.WRITE_CONTACTS))) {
+ BaresipService.contactsMode = "baresip"
+ replaceVariable("contacts_mode", "baresip")
+ }
+ } else {
+ BaresipService.contactsMode = "baresip"
+ }
Utils.putFileContents(configPath, config.toByteArray())
BaresipService.isConfigInitialized = true
diff --git a/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt
index 8583627a..012d7393 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/ConfigActivity.kt
@@ -32,6 +32,7 @@ class ConfigActivity : AppCompatActivity() {
private lateinit var binding: ActivityConfigBinding
private lateinit var layout: ScrollView
+ private lateinit var baresipService: Intent
private lateinit var autoStart: CheckBox
private lateinit var batteryOptimizations: CheckBox
private lateinit var listenAddr: EditText
@@ -40,11 +41,14 @@ class ConfigActivity : AppCompatActivity() {
private lateinit var verifyServer: CheckBox
private lateinit var caFile: CheckBox
private lateinit var darkTheme: CheckBox
- private lateinit var androidContacts: CheckBox
+ private lateinit var contactsSpinner: Spinner
+ private lateinit var contactsMode: String
+ private lateinit var contactsModes: ArrayList
private lateinit var debug: CheckBox
private lateinit var sipTrace: CheckBox
private lateinit var reset: CheckBox
private lateinit var requestPermissionLauncher: ActivityResultLauncher
+ private lateinit var requestPermissionsLauncher: ActivityResultLauncher>
private var oldAutoStart = ""
private var oldListenAddr = ""
@@ -54,7 +58,7 @@ class ConfigActivity : AppCompatActivity() {
private var oldCAFile = false
private var oldLogLevel = ""
private var oldDisplayTheme = -1
- private var oldAndroidContacts = ""
+ private var oldContactsMode = ""
private var save = false
private var restart = false
private var menu: Menu? = null
@@ -63,12 +67,16 @@ class ConfigActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
+ val contactsPermissions = arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)
+
binding = ActivityConfigBinding.inflate(layoutInflater)
setContentView(binding.root)
layout = binding.ConfigView
Utils.addActivity("config")
+ baresipService = Intent(this@ConfigActivity, BaresipService::class.java)
+
autoStart = binding.AutoStart
val asCv = Config.variable("auto_start")
oldAutoStart = if (asCv.size == 0) "no" else asCv[0]
@@ -291,10 +299,27 @@ class ConfigActivity : AppCompatActivity() {
oldDisplayTheme = Preferences(applicationContext).displayTheme
darkTheme.isChecked = oldDisplayTheme == AppCompatDelegate.MODE_NIGHT_YES
- androidContacts = binding.AndroidContacts
- val acCv = Config.variable("prefer_android_contacts")
- oldAndroidContacts = if (acCv.size == 0) "no" else acCv[0]
- androidContacts.isChecked = oldAndroidContacts == "yes"
+ contactsModes = arrayListOf(
+ getString(R.string.baresip), getString(R.string.android), getString(R.string.both))
+ contactsSpinner = binding.contactsSpinner
+ val ctCv = Config.variable("contacts_mode")
+ oldContactsMode = if (ctCv.size == 0) "baresip" else ctCv[0]
+ contactsMode = oldContactsMode
+ contactsModes.removeAt(contactsModes.indexOf(oldContactsMode))
+ contactsModes.add(0, oldContactsMode)
+ val contactsAdapter = ArrayAdapter(this,android.R.layout.simple_spinner_item,
+ contactsModes)
+ contactsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+ contactsSpinner.adapter = contactsAdapter
+ contactsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
+ contactsMode = contactsModes[position]
+ if (contactsMode != "baresip" && Build.VERSION.SDK_INT >= 23 &&
+ !Utils.checkPermissions(applicationContext, contactsPermissions))
+ requestPermissions(contactsPermissions, CONTACTS_PERMISSION_REQUEST_CODE)
+ }
+ override fun onNothingSelected(parent: AdapterView<*>) {}
+ }
debug = binding.Debug
val dbCv = Config.variable("log_level")
@@ -340,7 +365,14 @@ class ConfigActivity : AppCompatActivity() {
override fun onStart() {
super.onStart()
requestPermissionLauncher =
- registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
+ requestPermissionsLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
+ if (it.containsValue(false)) {
+ contactsMode = oldContactsMode
+ contactsSpinner.setSelection(contactsModes.indexOf(oldContactsMode))
+ }
+ }
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -356,6 +388,44 @@ class ConfigActivity : AppCompatActivity() {
}
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array,
+ grandResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grandResults)
+ when (requestCode) {
+ CONTACTS_PERMISSION_REQUEST_CODE -> {
+ if (grandResults.contains(PackageManager.PERMISSION_DENIED)) {
+ when {
+ 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)
+ }
+ }
+ 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)
+ }
+ }
+ else -> {
+ requestPermissionsLauncher.launch(permissions)
+ }
+ }
+ }
+ }
+ }
+ }
+
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (BaresipService.activities.indexOf("config") == -1) return true
@@ -433,13 +503,28 @@ class ConfigActivity : AppCompatActivity() {
if (oldDisplayTheme != newDisplayTheme)
Preferences(applicationContext).displayTheme = newDisplayTheme
- val androidContactsString = if (androidContacts.isChecked)
- "yes"
- else
- "no"
- if (oldAndroidContacts != androidContactsString) {
- Config.replaceVariable("prefer_android_contacts", androidContactsString)
- BaresipService.preferAndroidContacts = androidContacts.isChecked
+ if (oldContactsMode != contactsMode) {
+ Config.replaceVariable("contacts_mode", contactsMode)
+ BaresipService.contactsMode = contactsMode
+ when (contactsMode) {
+ "baresip" -> {
+ BaresipService.androidContacts.clear()
+ Contact.restoreBaresipContacts()
+ baresipService.action = "Stop Content Observer"
+ }
+ "Android" -> {
+ BaresipService.baresipContacts.clear()
+ Contact.loadAndroidContacts(this)
+ baresipService.action = "Start Content Observer"
+ }
+ "Both" -> {
+ Contact.restoreBaresipContacts()
+ Contact.loadAndroidContacts(this)
+ baresipService.action = "Start Content Observer"
+ }
+ }
+ Contact.contactsUpdate()
+ startService(baresipService)
save = true
}
@@ -530,9 +615,9 @@ class ConfigActivity : AppCompatActivity() {
Utils.alertView(this, getString(R.string.dark_theme),
getString(R.string.dark_theme_help))
}
- binding.AndroidContactsTitle.setOnClickListener {
- Utils.alertView(this, getString(R.string.show_android_contacts),
- getString(R.string.show_android_contacts_help))
+ binding.ContactsTitle.setOnClickListener {
+ Utils.alertView(this, getString(R.string.contacts),
+ getString(R.string.contacts_help))
}
binding.DebugTitle.setOnClickListener {
Utils.alertView(this, getString(R.string.debug), getString(R.string.debug_help))
diff --git a/app/src/main/kotlin/com/tutpro/baresip/Constants.kt b/app/src/main/kotlin/com/tutpro/baresip/Constants.kt
index b54ad47e..45491b0f 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/Constants.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/Constants.kt
@@ -6,7 +6,7 @@ const val DEFAULT_CHANNEL_ID = "com.tutpro.baresip.default"
const val HIGH_CHANNEL_ID = "com.tutpro.baresip.high"
const val MIC_PERMISSION_REQUEST_CODE = 1
-const val CONTACT_PERMISSION_REQUEST_CODE = 2
+const val CONTACTS_PERMISSION_REQUEST_CODE = 2
const val STATUS_NOTIFICATION_ID = 101
const val CALL_NOTIFICATION_ID = 102
diff --git a/app/src/main/kotlin/com/tutpro/baresip/Contact.kt b/app/src/main/kotlin/com/tutpro/baresip/Contact.kt
index 1b4f576f..e5506a76 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/Contact.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/Contact.kt
@@ -1,39 +1,165 @@
package com.tutpro.baresip
+import android.content.Context
+import android.database.Cursor
import android.graphics.Bitmap
import android.graphics.BitmapFactory
-
+import android.net.Uri
+import android.provider.ContactsContract
+import androidx.core.net.toUri
import java.io.File
import java.util.ArrayList
-class Contact(var name: String, var uri: String, var color: Int, val id: Long) {
+sealed class Contact {
- var avatarImage: Bitmap? = null
- var androidContact = false
+ class BaresipContact(var name: String, var uri: String, var color: Int, val id: Long): Contact() {
+ var avatarImage: Bitmap? = null
+ }
+
+ class AndroidContact(var name: String, var color: Int, var thumbnailUri: Uri?): Contact() {
+ val uris = ArrayList()
+ }
companion object {
- const val CONTACTS_SIZE = 100
+ const val CONTACTS_SIZE = 256
fun contacts(): ArrayList {
return BaresipService.contacts
}
- fun save(): Boolean {
+ fun contactNames(): ArrayList {
+ return BaresipService.contactNames
+ }
+
+ // Return contact name of uri or uri itself if contact with uri is not found
+ fun contactName(uri: String): String {
+ val userPart = Utils.uriUserPart(uri)
+ val contact = if (Utils.isTelNumber(userPart))
+ findContact("tel:$userPart")
+ else
+ findContact(uri)
+ if (contact != null) {
+ return when (contact) {
+ is BaresipContact ->
+ contact.name
+ is AndroidContact ->
+ contact.name
+ }
+ }
+ return uri
+ }
+
+ // Return uri of contact name or null if contact is not found
+ fun contactUri(name: String): String? {
+ for (c in contacts())
+ when (c) {
+ is BaresipContact -> {
+ if (c.name.equals(name, ignoreCase = true))
+ return c.uri.removePrefix("<")
+ .replaceAfter(">", "")
+ .replace(">", "")
+ }
+ is AndroidContact -> {
+ if (c.name == name) {
+ if (c.uris.isNotEmpty()) {
+ for (u in c.uris)
+ if (u.startsWith("sip:"))
+ return u
+ return c.uris.first()
+ }
+ }
+ }
+ }
+ return null
+ }
+
+ fun findContact(uri: String): Contact? {
+ for (c in contacts())
+ when (c) {
+ is BaresipContact -> {
+ if (Utils.uriMatch(c.uri, uri))
+ return c
+ }
+ is AndroidContact -> {
+ for (u in c.uris)
+ if (Utils.uriMatch(u, uri))
+ return c
+ }
+ }
+ return null
+ }
+
+ fun nameExists(name: String, ignoreCase: Boolean): Boolean {
+ for (c in BaresipService.baresipContacts)
+ if (c.name.equals(name, ignoreCase = ignoreCase))
+ return true
+ for (c in BaresipService.androidContacts)
+ if (c.name.equals(name, ignoreCase = ignoreCase))
+ return true
+ return false
+ }
+
+ fun saveBaresipContacts() {
var contents = ""
- for (c in BaresipService.contacts) contents +=
- "\"${c.name}\" <${c.uri}>;id=${c.id};color=${c.color};android=${c.androidContact}\n"
- return Utils.putFileContents(BaresipService.filesPath + "/contacts",
+ for (c in BaresipService.contacts)
+ if (c is BaresipContact)
+ contents += "\"${c.name}\" <${c.uri}>;id=${c.id};color=${c.color}\n"
+ Utils.putFileContents(BaresipService.filesPath + "/contacts",
contents.toByteArray())
}
- fun restore(): Boolean {
+ fun loadAndroidContacts(ctx: Context) {
+ val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME,
+ ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1,
+ 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 + "'"
+ val cur: Cursor? = ctx.contentResolver.query(ContactsContract.Data.CONTENT_URI, projection,
+ selection, null, null)
+ BaresipService.androidContacts.clear()
+ val contacts = HashMap()
+ while (cur != null && cur.moveToNext()) {
+ val id = cur.getLong(0)
+ val name = cur.getString(1) ?: ""
+ val mime = cur.getString(2)
+ val data = cur.getString(3)
+ val thumb = cur.getString(4)?.toUri()
+ if (nameExists(name, true)) {
+ Log.d(TAG, "Skipping Android contact with existing name '$name'")
+ continue
+ }
+ val contact = if (contacts.containsKey(id))
+ contacts[id]!!
+ else
+ AndroidContact(name, Utils.randomColor(), thumb)
+ if (contact.name == "" && name != "")
+ 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)}}")
+ else if (mime == ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
+ contact.uris.add("sip:$data")
+ else
+ continue
+ if (!contacts.containsKey(id))
+ contacts[id] = contact
+ }
+ cur?.close()
+ for ((_, value) in contacts)
+ if (value.name != "")
+ BaresipService.androidContacts.add(value)
+ }
+
+ fun restoreBaresipContacts(): Boolean {
val content = Utils.getFileContents(BaresipService.filesPath + "/contacts")
?: return false
val contacts = String(content)
- BaresipService.contacts.clear()
var contactNo = 0
val baseId = System.currentTimeMillis()
+ BaresipService.baresipContacts.clear()
contacts.lines().forEach {
val parts = it.split("\"")
if (parts.size == 3) {
@@ -47,15 +173,13 @@ class Contact(var name: String, var uri: String, var color: Int, val id: Long) {
colorValue.toInt()
else
Utils.randomColor()
- val androidContact = Utils.paramValue(params, "android" ) == "true"
val idValue = Utils.paramValue(params, "id" )
val id: Long = if (idValue != "")
idValue.toLong()
else
baseId + contactNo
- Log.d(TAG, "Restoring contact $name, $uri, $color, $id, $androidContact")
- val contact = Contact(name, uri, color, id)
- contact.androidContact = androidContact
+ Log.d(TAG, "Restoring contact $name, $uri, $color, $id")
+ val contact = BaresipContact(name, uri, color, id)
val avatarFilePath = BaresipService.filesPath + "/$id.png"
if (File(avatarFilePath).exists()) {
try {
@@ -67,12 +191,38 @@ class Contact(var name: String, var uri: String, var color: Int, val id: Long) {
Log.e(TAG, "Could not read avatar image from '$id.img")
}
}
- BaresipService.contacts.add(contact)
+ BaresipService.baresipContacts.add(contact)
}
}
- Utils.reloadContactNames()
return true
}
+ fun contactsUpdate() {
+ BaresipService.contacts.clear()
+ if (BaresipService.contactsMode != "Android")
+ BaresipService.contacts.addAll(BaresipService.baresipContacts)
+ if (BaresipService.contactsMode != "baresip")
+ BaresipService.contacts.addAll(BaresipService.androidContacts)
+ sortContacts()
+ generateContactNames()
+ BaresipService.contactUpdate.postValue(System.nanoTime())
+ }
+
+ fun sortContacts() {
+ BaresipService.contacts.sortBy{ when (it) {
+ is BaresipContact -> it.name
+ is AndroidContact -> it.name
+ }}
+ }
+
+ fun generateContactNames () {
+ BaresipService.contactNames.clear()
+ BaresipService.contactNames.addAll(
+ BaresipService.contacts.map {
+ when (it) {
+ is BaresipContact -> it.name
+ is AndroidContact -> it.name
+ }})
+ }
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/kotlin/com/tutpro/baresip/ContactActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ContactActivity.kt
index 58a4672f..7f2fc2ee 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/ContactActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/ContactActivity.kt
@@ -1,18 +1,15 @@
package com.tutpro.baresip
-import android.Manifest
import android.app.Activity
import android.content.ContentProviderOperation
import android.content.ContentValues
import android.content.Context
import android.content.Intent
-import android.content.pm.PackageManager
import android.database.Cursor
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
@@ -21,14 +18,10 @@ 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
@@ -44,7 +37,6 @@ class ContactActivity : AppCompatActivity() {
private lateinit var uriView: EditText
private lateinit var androidCheck: CheckBox
private lateinit var menu: Menu
- private lateinit var requestPermissionsLauncher: ActivityResultLauncher>
private var newContact = false
private var newAvatar = ""
@@ -53,10 +45,6 @@ class ContactActivity : AppCompatActivity() {
private var index = 0
private var color = 0
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?) {
@@ -75,6 +63,10 @@ class ContactActivity : AppCompatActivity() {
newContact = intent.getBooleanExtra("new", false)
if (newContact) {
+ if (BaresipService.contactsMode == "baresip") {
+ binding.AndroidTitle.visibility = View.GONE
+ androidCheck.visibility = View.GONE
+ }
title = getString(R.string.new_contact)
color = Utils.randomColor()
id = System.currentTimeMillis()
@@ -88,27 +80,33 @@ class ContactActivity : AppCompatActivity() {
else
uriView.setText(uri)
uOrI = uri
- androidCheck.isChecked = false
+ if ((BaresipService.contactsMode == "Android")) {
+ androidCheck.isChecked = true
+ androidCheck.isClickable = false
+ } else {
+ androidCheck.isChecked = false
+ }
} else {
+ binding.AndroidTitle.visibility = View.GONE
+ androidCheck.visibility = View.GONE
index = intent.getIntExtra("index", 0)
val contact = Contact.contacts()[index]
- val name = contact.name
- color = contact.color
- id = contact.id
- val avatarImage = contact.avatarImage
- if (avatarImage != null)
- showImageAvatar(avatarImage)
- else
- showTextAvatar(name, color)
- title = name
- nameView.setText(name)
- uriView.setText(contact.uri)
- uOrI = index.toString()
- androidCheck.isChecked = contact.androidContact
+ if (contact is Contact.BaresipContact) {
+ val name = contact.name
+ color = contact.color
+ id = contact.id
+ val avatarImage = contact.avatarImage
+ if (avatarImage != null)
+ showImageAvatar(avatarImage)
+ else
+ showTextAvatar(name, color)
+ title = name
+ nameView.setText(name)
+ uriView.setText(contact.uri)
+ uOrI = index.toString()
+ }
}
- oldAndroid = androidCheck.isChecked
-
val avatarRequest =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
@@ -175,12 +173,6 @@ 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)
- }
-
// Log.d(TAG, "Android sip contacts ${logAndroidContacts(this, "sip")}")
// Log.d(TAG, "Android tel contacts ${logAndroidContacts(this, "tel")}")
@@ -188,12 +180,6 @@ class ContactActivity : AppCompatActivity() {
}
- override fun onStart() {
- super.onStart()
- requestPermissionsLauncher =
- registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {}
- }
-
override fun onCreateOptionsMenu(optionsMenu: Menu): Boolean {
super.onCreateOptionsMenu(optionsMenu)
@@ -205,48 +191,6 @@ class ContactActivity : AppCompatActivity() {
}
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array,
- grandResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grandResults)
- when (requestCode) {
- CONTACT_PERMISSION_REQUEST_CODE -> {
- var allowed = true
- for (res in grandResults)
- allowed = allowed && res == PackageManager.PERMISSION_GRANTED
- if (!allowed) {
- androidCheck.isChecked = oldAndroid
- when {
- 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)
- }
- }
- 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)
- }
- }
- else -> {
- requestPermissionsLauncher.launch(permissions)
- }
- }
- }
- }
- }
- }
-
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (BaresipService.activities.indexOf("contact,$newContact,$uOrI") == -1) return true
@@ -265,11 +209,13 @@ class ContactActivity : AppCompatActivity() {
String.format(getString(R.string.invalid_contact), newName))
return false
}
+
val alert: Boolean = if (newContact)
- ContactsActivity.nameExists(newName, true)
- else
- (Contact.contacts()[index].name != newName) &&
- ContactsActivity.nameExists(newName, false)
+ Contact.nameExists(newName, true)
+ else {
+ val c = Contact.contacts()[index] as Contact.BaresipContact
+ (c.name != newName) && Contact.nameExists(newName, false)
+ }
if (alert) {
Utils.alertView(this, getString(R.string.notice),
String.format(getString(R.string.contact_already_exists), newName))
@@ -287,7 +233,8 @@ class ContactActivity : AppCompatActivity() {
return false
}
- val contact: Contact
+ val contact: Contact.BaresipContact
+
if (newContact) {
if (Contact.contacts().size >= Contact.CONTACTS_SIZE) {
Utils.alertView(this, getString(R.string.notice),
@@ -296,16 +243,13 @@ class ContactActivity : AppCompatActivity() {
BaresipService.activities.removeAt(0)
return true
} else {
- contact = Contact(newName, newUri, color, id)
- contact.androidContact = androidCheck.isChecked
- Contact.contacts().add(contact)
+ contact = Contact.BaresipContact(newName, newUri, color, id)
}
} else {
- contact = Contact.contacts()[index]
+ contact = Contact.contacts()[index] as Contact.BaresipContact
contact.uri = newUri
contact.name = newName
contact.color = color
- contact.androidContact = androidCheck.isChecked
}
when (newAvatar) {
@@ -323,21 +267,18 @@ class ContactActivity : AppCompatActivity() {
}
}
- Contact.contacts().sortBy { Contact -> Contact.name }
-
- if (Utils.checkPermissions(this, permissions)) {
- if (contact.androidContact)
- addOrUpdateAndroidContact(this, contact)
- else if (oldAndroid)
- deleteAndroidContact(this, contact)
+ if (androidCheck.isChecked) {
+ addOrUpdateAndroidContact(this, contact)
} else {
- contact.androidContact = oldAndroid
+ if (newContact)
+ Contact.contacts().add(contact)
+ Contact.sortContacts()
+ Contact.generateContactNames()
+ Contact.saveBaresipContacts()
}
- Contact.save()
- Utils.reloadContactNames()
-
BaresipService.activities.remove("contact,$newContact,$uOrI")
+
val i = Intent(this, MainActivity::class.java)
i.putExtra("name", newName)
setResult(Activity.RESULT_OK, i)
@@ -407,7 +348,7 @@ class ContactActivity : AppCompatActivity() {
return rotatedBitmap
}
- private fun addOrUpdateAndroidContact(ctx: Context, contact: Contact) {
+ private fun addOrUpdateAndroidContact(ctx: Context, contact: Contact.BaresipContact) {
val projection = arrayOf(ContactsContract.Data.RAW_CONTACT_ID)
val selection = ContactsContract.Data.MIMETYPE + "='" +
CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "' AND " +
@@ -420,10 +361,9 @@ class ContactActivity : AppCompatActivity() {
addAndroidContact(ctx, contact)
}
c?.close()
- contact.androidContact = true
}
- private fun addAndroidContact(ctx: Context, contact: Contact): Boolean {
+ private fun addAndroidContact(ctx: Context, contact: Contact.BaresipContact): Boolean {
val ops = ArrayList()
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
@@ -464,7 +404,7 @@ class ContactActivity : AppCompatActivity() {
return true
}
- private fun updateAndroidContact(rawContactId: Long, contact: Contact) {
+ private fun updateAndroidContact(rawContactId: Long, contact: Contact.BaresipContact) {
if (updateAndroidUri(rawContactId, contact.uri) == 0)
addAndroidUri(rawContactId, contact.uri)
if (updateAndroidPhoto(rawContactId, contact.avatarImage) == 0)
@@ -561,9 +501,9 @@ class ContactActivity : AppCompatActivity() {
var contact: Contact? = null
- fun deleteAndroidContact(ctx: Context, contact: Contact): Int {
+ fun deleteAndroidContact(ctx: Context, name: String): Int {
return ctx.contentResolver.delete(ContactsContract.RawContacts.CONTENT_URI,
- ContactsContract.Contacts.DISPLAY_NAME + "='" + contact.name + "'",
+ ContactsContract.Contacts.DISPLAY_NAME + "='" + name + "'",
null)
}
diff --git a/app/src/main/kotlin/com/tutpro/baresip/ContactListAdapter.kt b/app/src/main/kotlin/com/tutpro/baresip/ContactListAdapter.kt
index 0033e630..3c5da769 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/ContactListAdapter.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/ContactListAdapter.kt
@@ -1,22 +1,22 @@
package com.tutpro.baresip
-import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.os.SystemClock
-import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.*
+import android.widget.ArrayAdapter
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat.startActivity
-
import java.io.File
import java.io.IOException
-import java.util.*
class ContactListAdapter(private val ctx: Context, private val rows: ArrayList,
private val aor: String) :
@@ -48,82 +48,137 @@ class ContactListAdapter(private val ctx: Context, private val rows: ArrayList
- when (which) {
- DialogInterface.BUTTON_POSITIVE, DialogInterface.BUTTON_NEGATIVE -> {
- val i = Intent(ctx, MainActivity::class.java)
- i.flags = Intent.FLAG_ACTIVITY_NEW_TASK or
- Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
- if (which == DialogInterface.BUTTON_NEGATIVE)
- i.putExtra("action", "call")
- else
- i.putExtra("action", "message")
- val ua = UserAgent.ofAor(aor)
- if (ua == null) {
- Log.w(TAG, "onClickListener did not find AoR $aor")
- } else {
- BaresipService.activities.clear()
- i.putExtra("uap", ua.uap)
- i.putExtra("peer", contact.uri)
- (ctx as Activity).startActivity(i)
+ viewHolder.nameView.text = contact.name
+ viewHolder.nameView.textSize = 20f
+ viewHolder.nameView.setPadding(6, 6, 0, 6)
+
+ if (aor != "") {
+ viewHolder.nameView.setOnClickListener {
+ val dialogClickListener = DialogInterface.OnClickListener { _, which ->
+ when (which) {
+ DialogInterface.BUTTON_POSITIVE, DialogInterface.BUTTON_NEGATIVE -> {
+ val i = Intent(ctx, MainActivity::class.java)
+ i.flags = Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
+ if (which == DialogInterface.BUTTON_NEGATIVE)
+ i.putExtra("action", "call")
+ else
+ i.putExtra("action", "message")
+ val ua = UserAgent.ofAor(aor)
+ if (ua == null) {
+ Log.w(TAG, "onClickListener did not find AoR $aor")
+ } else {
+ BaresipService.activities.clear()
+ i.putExtra("uap", ua.uap)
+ i.putExtra("peer", contact.uri)
+ (ctx as Activity).startActivity(i)
+ }
+ }
+ DialogInterface.BUTTON_NEUTRAL -> {
}
}
- DialogInterface.BUTTON_NEUTRAL -> {
- }
}
- }
- if (SystemClock.elapsedRealtime() - lastClick > 1000) {
- lastClick = SystemClock.elapsedRealtime()
- with (AlertDialog.Builder(ctx, R.style.Theme_AppCompat)) {
- setMessage(String.format(ctx.getString(R.string.contact_action_question),
- Contact.contacts()[position].name))
- setNeutralButton(ctx.getText(R.string.cancel), dialogClickListener)
- setNegativeButton(ctx.getText(R.string.call), dialogClickListener)
- setPositiveButton(ctx.getText(R.string.send_message), dialogClickListener)
- show()
+ if (SystemClock.elapsedRealtime() - lastClick > 1000) {
+ lastClick = SystemClock.elapsedRealtime()
+ with(AlertDialog.Builder(ctx, R.style.Theme_AppCompat)) {
+ setMessage(String.format(ctx.getString(R.string.contact_action_question),
+ contact.name))
+ setNeutralButton(ctx.getText(R.string.cancel), dialogClickListener)
+ setNegativeButton(ctx.getText(R.string.call), dialogClickListener)
+ setPositiveButton(ctx.getText(R.string.send_message), dialogClickListener)
+ show()
+ }
}
}
}
+
+ viewHolder.actionView.visibility = View.VISIBLE
+ viewHolder.actionView.setOnClickListener {
+ if (SystemClock.elapsedRealtime() - lastClick > 1000) {
+ lastClick = SystemClock.elapsedRealtime()
+ val i = Intent(ctx, ContactActivity::class.java)
+ val b = Bundle()
+ b.putBoolean("new", false)
+ b.putInt("index", position)
+ i.putExtras(b)
+ startActivity(ctx, i, null)
+ }
+ }
+
+ }
+
+ if (contact is Contact.AndroidContact) {
+
+ val thumbNailUri = contact.thumbnailUri
+ if (thumbNailUri != null) {
+ viewHolder.imageAvatarView.setImageURI(thumbNailUri)
+ } else {
+ viewHolder.textAvatarView.background.setTint(contact.color)
+ if (contact.name.isNotEmpty())
+ viewHolder.textAvatarView.text = "${contact.name[0]}"
+ else
+ viewHolder.textAvatarView.text = ""
+ viewHolder.imageAvatarView.setImageBitmap(Utils.bitmapFromView(viewHolder.textAvatarView))
+ }
+
+ viewHolder.nameView.text = contact.name
+ viewHolder.nameView.textSize = 20f
+ viewHolder.nameView.setPadding(6, 6, 0, 6)
+
+ viewHolder.nameView.setOnClickListener {
+ if (SystemClock.elapsedRealtime() - lastClick > 1000) {
+ lastClick = SystemClock.elapsedRealtime()
+ val i = Intent(ctx, AndroidContactActivity::class.java)
+ val b = Bundle()
+ b.putString("aor", aor)
+ b.putInt("index", position)
+ i.putExtras(b)
+ startActivity(ctx, i, null)
+ }
+ }
+
+ viewHolder.actionView.visibility = View.GONE
+
}
viewHolder.nameView.setOnLongClickListener {
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
- val id = contact.id
- val avatarFile = File(BaresipService.filesPath, "$id.img")
- if (avatarFile.exists()) {
- try {
- avatarFile.delete()
- } catch (e: IOException) {
- Log.e(TAG, "Could not delete file '$id.img")
+ when (contact) {
+ is Contact.BaresipContact -> {
+ val id = contact.id
+ val avatarFile = File(BaresipService.filesPath, "$id.img")
+ if (avatarFile.exists()) {
+ try {
+ avatarFile.delete()
+ } catch (e: IOException) {
+ Log.e(TAG, "Could not delete file '$id.img")
+ }
+ }
+ Contact.contacts().removeAt(position)
+ Contact.contactNames().removeAt(position)
+ Contact.saveBaresipContacts()
+ this.notifyDataSetChanged()
+ }
+ is Contact.AndroidContact -> {
+ ContactActivity.deleteAndroidContact(ctx, contact.name)
}
}
- if (contact.androidContact &&
- Utils.checkPermissions(ctx, arrayOf(Manifest.permission.WRITE_CONTACTS)))
- ContactActivity.deleteAndroidContact(ctx, contact)
- Contact.contacts().removeAt(position)
- Contact.save()
- Utils.reloadContactNames()
- this.notifyDataSetChanged()
}
DialogInterface.BUTTON_NEGATIVE -> {
}
@@ -131,10 +186,13 @@ class ContactListAdapter(private val ctx: Context, private val rows: ArrayList contact.name
+ is Contact.AndroidContact -> contact.name
+ }))
setNegativeButton(ctx.getText(R.string.cancel), dialogClickListener)
setPositiveButton(ctx.getText(R.string.delete), dialogClickListener)
show()
@@ -142,18 +200,6 @@ class ContactListAdapter(private val ctx: Context, private val rows: ArrayList 1000) {
- lastClick = SystemClock.elapsedRealtime()
- val i = Intent(ctx, ContactActivity::class.java)
- val b = Bundle()
- b.putBoolean("new", false)
- b.putInt("index", position)
- i.putExtras(b)
- startActivity(ctx, i, null)
- }
- }
-
return rowView
}
}
diff --git a/app/src/main/kotlin/com/tutpro/baresip/ContactsActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ContactsActivity.kt
index 1473ffa5..cc149ef3 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/ContactsActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/ContactsActivity.kt
@@ -4,10 +4,10 @@ import android.app.Activity
import android.content.*
import android.os.Bundle
import android.os.SystemClock
-import android.view.Menu
import androidx.appcompat.app.AppCompatActivity
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts
+import androidx.lifecycle.Observer
import com.tutpro.baresip.databinding.ActivityContactsBinding
class ContactsActivity : AppCompatActivity() {
@@ -27,10 +27,15 @@ class ContactsActivity : AppCompatActivity() {
Utils.addActivity("contacts,$aor")
val listView = binding.contacts
- clAdapter = ContactListAdapter(this, Contact.contacts(), aor)
+ clAdapter = ContactListAdapter(this, BaresipService.contacts, aor)
listView.adapter = clAdapter
listView.isLongClickable = true
+ val contactObserver = Observer {
+ clAdapter.notifyDataSetChanged()
+ }
+ BaresipService.contactUpdate.observe(this, contactObserver)
+
val contactRequest =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK)
@@ -58,34 +63,14 @@ class ContactsActivity : AppCompatActivity() {
}
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.swap_contacts_icon, menu)
- return super.onCreateOptionsMenu(menu)
- }
-
override fun onResume() {
-
super.onResume()
-
clAdapter.notifyDataSetChanged()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
-
- R.id.swapIcon -> {
- if (SystemClock.elapsedRealtime() - lastClick > 1000) {
- lastClick = SystemClock.elapsedRealtime()
- BaresipService.activities.remove("contacts,$aor")
- val intent = Intent(this, AndroidContactsActivity::class.java)
- intent.putExtra("aor", aor)
- startActivity(intent)
- finish()
- return true
- }
- }
-
android.R.id.home -> {
BaresipService.activities.remove("contacts,$aor")
setResult(Activity.RESULT_OK, Intent())
@@ -105,40 +90,4 @@ class ContactsActivity : AppCompatActivity() {
}
- companion object {
-
- // Return uri of contact name or null if contact is not found
- fun contactUri(name: String): String? {
- for (c in Contact.contacts())
- if (c.name.equals(name, ignoreCase = true))
- return c.uri.removePrefix("<")
- .replaceAfter(">", "")
- .replace(">", "")
- return null
- }
-
- // Return contact name of uri or null if contact with uri is not found
- fun contactName(uri: String): String? {
- val userPart = Utils.uriUserPart(uri)
- return if (Utils.isTelNumber(userPart))
- findContact("tel:$userPart")?.name
- else
- findContact(uri)?.name
- }
-
- fun findContact(uri: String): Contact? {
- for (c in Contact.contacts()) {
- if (Utils.uriMatch(c.uri, uri))
- return c
- }
- return null
- }
-
- fun nameExists(name: String, ignoreCase: Boolean): Boolean {
- for (c in Contact.contacts())
- if (c.name.equals(name, ignoreCase = ignoreCase)) return true
- return false
- }
-
- }
}
diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt
index 8da854c9..eba979a7 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt
@@ -209,11 +209,13 @@ class MainActivity : AppCompatActivity() {
// Haven't found any explanation why this can happen.
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
Log.d(TAG, "aorSpinner selecting $position")
- val acc = UserAgent.uas()[position].account
- aorSpinner.tag = acc.aor
- val ua = UserAgent.uas()[position]
- showCall(ua)
- updateIcons(acc)
+ if (position < UserAgent.uas().size) {
+ val acc = UserAgent.uas()[position].account
+ aorSpinner.tag = acc.aor
+ val ua = UserAgent.uas()[position]
+ showCall(ua)
+ updateIcons(acc)
+ }
}
override fun onNothingSelected(parent: AdapterView<*>) {
Log.d(TAG, "Nothing selected")
@@ -273,7 +275,7 @@ class MainActivity : AppCompatActivity() {
}
callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
- Utils.contactNames()))
+ Contact.contactNames()))
callUri.threshold = 2
callUri.setOnFocusChangeListener { view, b ->
if (b) {
@@ -456,27 +458,18 @@ class MainActivity : AppCompatActivity() {
contactsRequest = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
- Utils.contactNames()))
+ Contact.contactNames()))
}
contactsButton.setOnClickListener {
- if (BaresipService.preferAndroidContacts) {
- val i = Intent(this@MainActivity, AndroidContactsActivity::class.java)
- if (aorSpinner.selectedItemPosition >= 0)
- i.putExtra("aor", aorSpinner.tag.toString())
- else
- i.putExtra("aor", "")
- startActivity(i)
- } else {
- val i = Intent(this@MainActivity, ContactsActivity::class.java)
- val b = Bundle()
- if (aorSpinner.selectedItemPosition >= 0)
- b.putString("aor", aorSpinner.tag.toString())
- else
- b.putString("aor", "")
- i.putExtras(b)
- contactsRequest.launch(i)
- }
+ val i = Intent(this@MainActivity, ContactsActivity::class.java)
+ val b = Bundle()
+ if (aorSpinner.selectedItemPosition >= 0)
+ b.putString("aor", aorSpinner.tag.toString())
+ else
+ b.putString("aor", "")
+ i.putExtras(b)
+ contactsRequest.launch(i)
}
chatRequests = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
@@ -932,6 +925,13 @@ class MainActivity : AppCompatActivity() {
if (event == "started") {
val callActionUri = params[0]
Log.d(TAG, "Handling service event 'started' with '$callActionUri'")
+ if (!this::uaAdapter.isInitialized) {
+ // Android has restarted baresip when permission has been denied in app settings
+ val i = Intent(this, MainActivity::class.java)
+ i.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ startActivity(i)
+ return
+ }
uaAdapter.notifyDataSetChanged()
if (callActionUri != "") {
var ua = UserAgent.ofDomain(Utils.uriHostPart(callActionUri))
@@ -1105,7 +1105,7 @@ class MainActivity : AppCompatActivity() {
val call = Call.ofCallp(callp)!!
val titleView = View.inflate(this, R.layout.alert_title, null) as TextView
titleView.text = getString(R.string.transfer_request)
- val target = Utils.friendlyUri(Utils.contactName(ev[1]), Utils.aorDomain(aor))
+ val target = Utils.friendlyUri(Contact.contactName(ev[1]), Utils.aorDomain(aor))
with(AlertDialog.Builder(this)) {
setCustomTitle(titleView)
setMessage(String.format(getString(R.string.transfer_request_query),
@@ -1403,7 +1403,7 @@ class MainActivity : AppCompatActivity() {
titleView.text = getString(R.string.call_transfer)
val transferUri = layout.findViewById(R.id.transferUri) as AutoCompleteTextView
transferUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
- Utils.contactNames()))
+ Contact.contactNames()))
transferUri.threshold = 2
transferUri.requestFocus()
val builder = AlertDialog.Builder(this)
@@ -1414,7 +1414,7 @@ class MainActivity : AppCompatActivity() {
dialog.dismiss()
var uriText = transferUri.text.toString().trim()
if (uriText.isNotEmpty()) {
- uriText = Utils.contactUri(uriText) ?: uriText
+ uriText = Contact.contactUri(uriText) ?: uriText
if (Utils.isTelNumber(uriText))
uriText = "tel:$uriText"
val uri = if (Utils.isTelUri(uriText))
@@ -1702,7 +1702,7 @@ class MainActivity : AppCompatActivity() {
if (Call.calls().isEmpty()) {
var uriText = callUri.text.toString().trim()
if (uriText.isNotEmpty()) {
- uriText = Utils.contactUri(uriText) ?: uriText
+ uriText = Contact.contactUri(uriText) ?: uriText
if (Utils.isTelNumber(uriText))
uriText = "tel:$uriText"
val uri = if (Utils.isTelUri(uriText)) {
@@ -1750,10 +1750,8 @@ class MainActivity : AppCompatActivity() {
} else {
val latest = NewCallHistory.aorLatestHistory(aor)
if (latest != null)
- callUri.setText(
- Utils.friendlyUri(Utils.contactName(latest.peerUri), Utils.aorDomain(aor)
- )
- )
+ callUri.setText(Utils.friendlyUri(Contact.contactName(latest.peerUri),
+ Utils.aorDomain(aor)))
}
}
}
@@ -1772,7 +1770,7 @@ class MainActivity : AppCompatActivity() {
callUri.isFocusableInTouchMode = true
imm.hideSoftInputFromWindow(callUri.windowToken, 0)
callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
- Utils.contactNames()))
+ Contact.contactNames()))
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.VISIBLE
callButton.isEnabled = true
@@ -1797,7 +1795,7 @@ class MainActivity : AppCompatActivity() {
else
getString(R.string.outgoing_call_to_dots)
callTimer.visibility = View.INVISIBLE
- callUri.setText(Utils.friendlyUri(Utils.contactName(call.peerUri),
+ callUri.setText(Utils.friendlyUri(Contact.contactName(call.peerUri),
Utils.aorDomain(ua.account.aor)))
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.INVISIBLE
@@ -1812,7 +1810,7 @@ class MainActivity : AppCompatActivity() {
"incoming" -> {
callTitle.text = getString(R.string.incoming_call_from_dots)
callTimer.visibility = View.INVISIBLE
- callUri.setText(Utils.friendlyUri(Utils.contactName(call.peerUri),
+ callUri.setText(Utils.friendlyUri(Contact.contactName(call.peerUri),
Utils.aorDomain(ua.account.aor)))
callUri.setAdapter(null)
securityButton.visibility = View.INVISIBLE
@@ -1832,7 +1830,7 @@ class MainActivity : AppCompatActivity() {
}
if (call.referTo != "") {
callTitle.text = getString(R.string.transferring_call_to_dots)
- callUri.setText(Utils.friendlyUri(Utils.contactName(call.referTo),
+ callUri.setText(Utils.friendlyUri(Contact.contactName(call.referTo),
Utils.aorDomain(ua.account.aor)))
transferButton.isEnabled = false
} else {
@@ -1840,7 +1838,7 @@ class MainActivity : AppCompatActivity() {
callTitle.text = getString(R.string.outgoing_call_to_dots)
else
callTitle.text = getString(R.string.incoming_call_from_dots)
- callUri.setText(Utils.friendlyUri(Utils.contactName(call.peerUri),
+ callUri.setText(Utils.friendlyUri(Contact.contactName(call.peerUri),
Utils.aorDomain(ua.account.aor)))
transferButton.isEnabled = true
}
@@ -1973,21 +1971,6 @@ class MainActivity : AppCompatActivity() {
i.putExtras(b)
startActivity(i)
}
- "android contacts" -> {
- val i = Intent(this, AndroidContactsActivity::class.java)
- val b = Bundle()
- b.putString("aor", activity[1])
- i.putExtras(b)
- startActivity(i)
- }
- "android contact" -> {
- val i = Intent(this, AndroidContactActivity::class.java)
- val b = Bundle()
- b.putString("aor", activity[1])
- b.putInt("index", activity[2].toInt())
- i.putExtras(b)
- startActivity(i)
- }
"chats" -> {
val i = Intent(this, ChatsActivity::class.java)
val b = Bundle()
diff --git a/app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt b/app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt
index 619ab43f..e7038332 100644
--- a/app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt
+++ b/app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt
@@ -45,7 +45,7 @@ class MessageListAdapter(private val ctx: Context, private val rows: ArrayList Contact.name})
- BaresipService.contactNames.addAll(AndroidContact.contacts().map{AndroidContact -> AndroidContact.name})
- BaresipService.contactNames.sort()
- }
-
- fun contactNames() : List {
- return BaresipService.contactNames
- }
-
fun setAvatar(ctx: Context, imageView: ImageView, textView: TextView, uri: String) {
- val contact = ContactsActivity.findContact(uri)
- if (contact != null) {
- val avatarImage = contact.avatarImage
- if (avatarImage != null) {
- imageView.setImageBitmap(avatarImage)
- } else {
- textView.background.setTint(contact.color)
- if (contact.name.isNotEmpty())
- textView.text = "${contact.name[0]}"
- else
- textView.text = ""
- imageView.setImageBitmap(bitmapFromView(textView))
- }
- } else {
- val androidContact = AndroidContactsActivity.findContact(uri)
- if (androidContact != null) {
- val thumbnailUri = androidContact.thumbnailUri
- if (thumbnailUri != null) {
- imageView.setImageURI(thumbnailUri)
+
+ when (val contact = Contact.findContact(uri)) {
+
+ is Contact.BaresipContact -> {
+ val avatarImage = contact.avatarImage
+ if (avatarImage != null) {
+ imageView.setImageBitmap(avatarImage)
} else {
- textView.background.setTint(androidContact.color)
- if (androidContact.name.isNotEmpty())
- textView.text = "${androidContact.name[0]}"
+ textView.background.setTint(contact.color)
+ if (contact.name.isNotEmpty())
+ textView.text = "${contact.name[0]}"
else
textView.text = ""
imageView.setImageBitmap(bitmapFromView(textView))
}
- } else {
+ }
+
+ is Contact.AndroidContact -> {
+ val thumbnailUri = contact.thumbnailUri
+ if (thumbnailUri != null) {
+ imageView.setImageURI(thumbnailUri)
+ } else {
+ textView.background.setTint(contact.color)
+ if (contact.name.isNotEmpty())
+ textView.text = "${contact.name[0]}"
+ else
+ textView.text = ""
+ imageView.setImageBitmap(bitmapFromView(textView))
+ }
+ }
+
+ null -> {
val bitmap = BitmapFactory.decodeResource(ctx.resources, R.drawable.person_image)
imageView.setImageBitmap(bitmap)
}
+
}
}
diff --git a/app/src/main/res/layout/activity_config.xml b/app/src/main/res/layout/activity_config.xml
index c7fb3748..3ca12e2f 100644
--- a/app/src/main/res/layout/activity_config.xml
+++ b/app/src/main/res/layout/activity_config.xml
@@ -215,37 +215,27 @@
android:id="@+id/AudioSettingsTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
+ android:layout_marginBottom="12dp"
android:textSize="18sp"
android:textStyle="bold"
android:text="@string/audio_settings" >
-
+
+
+
-
-
-
-
-
+ android:paddingTop="8dp" >
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a92f18cb..f7bfd012 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -329,9 +329,7 @@
Size of transmitted video frames (width x height).
Factory default is 800x600.
Android Settings
- Show Android Contacts
- If checked, Android contacts are shown when Contacts
- button is touched.
+ Chooses if baresip contacts, Android contacts, or both will be used.
Debug
If checked, provides debug and info level log messages to Logcat.
SIP Trace
@@ -356,8 +354,7 @@
Invalid contact name \'%1$s\'
Contact \'%1$s\' already exists.
Invalid SIP URI
- Android
- If checked, this contact is available also in Android contacts.
+ If checked, this contact is added to Android contacts.
Profile image
Contacts
@@ -392,6 +389,9 @@
…
\u2022 %1$s
Invalid SIP or tel URI \'%1$s\'
+ baresip
+ Android
+ Both
Backup
Restore