Improved contacts implementation

This commit is contained in:
Juha Heinanen
2025-04-03 17:21:18 +03:00
parent 06b6092356
commit dd11873f67
5 changed files with 52 additions and 55 deletions
@@ -231,7 +231,7 @@ class BaresipContactActivity : ComponentActivity() {
imageAvatarUri = Uri.fromFile(tmpFile).toString() imageAvatarUri = Uri.fromFile(tmpFile).toString()
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Could not read avatar image: $e") Log.e(TAG, "Could not read avatar image: ${e.message}")
} }
} }
@@ -498,10 +498,6 @@ class BaresipContactActivity : ComponentActivity() {
Contact.updateBaresipContact(contact) Contact.updateBaresipContact(contact)
} }
Contact.contactsUpdate()
Contact.saveBaresipContacts()
BaresipService.activities.remove("baresip contact,$new,$uriOrName") BaresipService.activities.remove("baresip contact,$new,$uriOrName")
val i = Intent(ctx, MainActivity::class.java) val i = Intent(ctx, MainActivity::class.java)
@@ -595,7 +591,7 @@ class BaresipContactActivity : ComponentActivity() {
try { try {
ctx.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) ctx.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Adding of contact ${contact.name} failed") Log.e(TAG, "Adding of contact ${contact.name} failed: ${e.message}")
return false return false
} }
return true return true
@@ -625,7 +621,7 @@ class BaresipContactActivity : ComponentActivity() {
try { try {
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Adding of SIP URI $uri failed") Log.e(TAG, "Adding of SIP URI $uri failed: ${e.message}")
} }
} }
@@ -641,7 +637,7 @@ class BaresipContactActivity : ComponentActivity() {
return try { return try {
contentResolver.update(ContactsContract.Data.CONTENT_URI, contentValues, where, null) contentResolver.update(ContactsContract.Data.CONTENT_URI, contentValues, where, null)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Update of Android URI $uri failed") Log.e(TAG, "Update of Android URI $uri failed: ${e.message}")
0 0
} }
} }
@@ -660,7 +656,7 @@ class BaresipContactActivity : ComponentActivity() {
try { try {
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Adding of Android photo failed") Log.e(TAG, "Adding of Android photo failed: ${e.message}")
} }
} }
} }
@@ -677,7 +673,7 @@ class BaresipContactActivity : ComponentActivity() {
return try { return try {
contentResolver.update(ContactsContract.Data.CONTENT_URI, contentValues, where, null) contentResolver.update(ContactsContract.Data.CONTENT_URI, contentValues, where, null)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "updateAndroidPhoto failed") Log.e(TAG, "updateAndroidPhoto failed: ${e.message}")
0 0
} }
} }
@@ -691,7 +687,7 @@ class BaresipContactActivity : ComponentActivity() {
out.close() out.close()
out.toByteArray() out.toByteArray()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Unable to serialize photo: $e") Log.w(TAG, "Unable to serialize photo: ${e.message}")
null null
} }
} }
@@ -412,7 +412,7 @@ class BaresipService: Service() {
try { try {
File(filesPath).mkdirs() File(filesPath).mkdirs()
} catch (e: Error) { } catch (e: Error) {
Log.e(TAG, "Failed to create directory: $e") Log.e(TAG, "Failed to create directory: ${e.message}")
} }
} }
for (a in assets) { for (a in assets) {
@@ -618,6 +618,7 @@ class BaresipService: Service() {
sendBroadcast(Intent("com.tutpro.baresip.Restart")) sendBroadcast(Intent("com.tutpro.baresip.Restart"))
} }
@Suppress("unused")
@SuppressLint("UnspecifiedImmutableFlag", "DiscouragedApi") @SuppressLint("UnspecifiedImmutableFlag", "DiscouragedApi")
@Keep @Keep
fun uaEvent(event: String, uap: Long, callp: Long) { fun uaEvent(event: String, uap: Long, callp: Long) {
@@ -1092,6 +1093,7 @@ class BaresipService: Service() {
} }
} }
@Suppress("unused")
@SuppressLint("UnspecifiedImmutableFlag") @SuppressLint("UnspecifiedImmutableFlag")
@Keep @Keep
fun messageEvent(uap: Long, peerUri: String, cType: String, msg: ByteArray) { fun messageEvent(uap: Long, peerUri: String, cType: String, msg: ByteArray) {
@@ -1105,13 +1107,13 @@ class BaresipService: Service() {
val charsetString = Utils.paramValue(cType.replace(" ", ""), "charset") val charsetString = Utils.paramValue(cType.replace(" ", ""), "charset")
val charset = try { val charset = try {
Charset.forName(charsetString) Charset.forName(charsetString)
} catch (e: Exception) { } catch (_: Exception) {
StandardCharsets.UTF_8 StandardCharsets.UTF_8
} }
val text = try { val text = try {
String(msg, charset) String(msg, charset)
} catch (e: Exception) { } catch (e: Exception) {
val error = "Decoding of message failed using charset $charset from $cType!" val error = "Decoding of message failed using charset $charset from $cType: ${e.message}!"
Log.w(TAG, error) Log.w(TAG, error)
error error
} }
@@ -1194,6 +1196,7 @@ class BaresipService: Service() {
} }
} }
@Suppress("unused")
@Keep @Keep
fun started() { fun started() {
Log.d(TAG, "Received 'started' from baresip") Log.d(TAG, "Received 'started' from baresip")
@@ -1207,6 +1210,7 @@ class BaresipService: Service() {
updateStatusNotification() updateStatusNotification()
} }
@Suppress("unused")
@Keep @Keep
fun stopped(error: String) { fun stopped(error: String) {
Log.d(TAG, "Received 'stopped' from baresip with start error '$error'") Log.d(TAG, "Received 'stopped' from baresip with start error '$error'")
@@ -1262,7 +1266,7 @@ class BaresipService: Service() {
else else
startForeground(STATUS_NOTIFICATION_ID, snb.build()) startForeground(STATUS_NOTIFICATION_ID, snb.build())
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed to start foreground service") Log.e(TAG, "Failed to start foreground service: ${e.message}")
} }
} }
@@ -1564,7 +1568,7 @@ class BaresipService: Service() {
true, androidContactsObserver) true, androidContactsObserver)
androidContactsObserverRegistered = true androidContactsObserverRegistered = true
} catch (e: SecurityException) { } catch (e: SecurityException) {
Log.i(TAG, "No Contacts permission") Log.i(TAG, "No Contacts permission: ${e.message}")
} }
} }
@@ -1609,6 +1613,7 @@ class BaresipService: Service() {
external fun baresipStop(force: Boolean) external fun baresipStop(force: Boolean)
@SuppressLint("MutableCollectionMutableState")
companion object { companion object {
var isServiceRunning = false var isServiceRunning = false
@@ -1631,7 +1636,7 @@ class BaresipService: Service() {
val uas = mutableStateOf(emptyList<UserAgent>()) val uas = mutableStateOf(emptyList<UserAgent>())
val uasStatus = mutableStateOf(emptyMap<String, Int>()) val uasStatus = mutableStateOf(emptyMap<String, Int>())
var contacts by mutableStateOf(emptyList<Contact>()) var contacts by mutableStateOf(mutableListOf<Contact>())
val darkTheme = mutableStateOf(false) val darkTheme = mutableStateOf(false)
var messages by mutableStateOf(emptyList<Message>()) var messages by mutableStateOf(emptyList<Message>())
@@ -1640,7 +1645,8 @@ class BaresipService: Service() {
val messageUpdate = MutableLiveData<Long>() val messageUpdate = MutableLiveData<Long>()
val contactUpdate = MutableLiveData<Long>() val contactUpdate = MutableLiveData<Long>()
val registrationUpdate = MutableLiveData<Long>() val registrationUpdate = MutableLiveData<Long>()
val baresipContacts = mutableStateOf(emptyList<Contact.BaresipContact>()) @SuppressLint("MutableCollectionMutableState")
val baresipContacts = mutableStateOf(mutableListOf<Contact.BaresipContact>())
val androidContacts = mutableStateOf(emptyList<Contact.AndroidContact>()) val androidContacts = mutableStateOf(emptyList<Contact.AndroidContact>())
val contactNames = mutableStateOf(emptyList<String>()) val contactNames = mutableStateOf(emptyList<String>())
var contactsMode = "baresip" var contactsMode = "baresip"
@@ -140,7 +140,7 @@ class ConfigActivity : ComponentActivity() {
} catch (e: Error) { } catch (e: Error) {
Utils.alertView( Utils.alertView(
this, getString(R.string.error), this, getString(R.string.error),
getString(R.string.read_cert_error) getString(R.string.read_cert_error) + ": " + e.message
) )
newTlsCertificateFile = false newTlsCertificateFile = false
} }
@@ -165,7 +165,7 @@ class ConfigActivity : ComponentActivity() {
} catch (e: Error) { } catch (e: Error) {
Utils.alertView( Utils.alertView(
this, getString(R.string.error), this, getString(R.string.error),
getString(R.string.read_ca_certs_error) getString(R.string.read_ca_certs_error) + ": " + e.message
) )
newCaFile = false newCaFile = false
} }
@@ -222,7 +222,7 @@ class ConfigActivity : ComponentActivity() {
val caCertsFile = File(BaresipService.filesPath + "/ca_certs.crt") val caCertsFile = File(BaresipService.filesPath + "/ca_certs.crt")
oldCaFile = caCertsFile.exists() oldCaFile = caCertsFile.exists()
powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager powerManager = getSystemService(POWER_SERVICE) as PowerManager
oldBatteryOptimizations = powerManager oldBatteryOptimizations = powerManager
.isIgnoringBatteryOptimizations(packageName) == false .isIgnoringBatteryOptimizations(packageName) == false
@@ -814,7 +814,7 @@ class ConfigActivity : ComponentActivity() {
try { try {
androidSettingsRequest.launch(Intent("android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS")) androidSettingsRequest.launch(Intent("android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"))
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
Log.e(TAG, "ActivityNotFound exception: $e") Log.e(TAG, "ActivityNotFound exception: ${e.message}")
} }
} }
) )
@@ -857,7 +857,7 @@ class ConfigActivity : ComponentActivity() {
try { try {
dialerRoleRequest.launch(Intent("android.settings.MANAGE_DEFAULT_APPS_SETTINGS")) dialerRoleRequest.launch(Intent("android.settings.MANAGE_DEFAULT_APPS_SETTINGS"))
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
Log.e(TAG, "ActivityNotFound exception: $e") Log.e(TAG, "ActivityNotFound exception: ${e.message}")
} }
} }
} }
@@ -1173,7 +1173,7 @@ class ConfigActivity : ComponentActivity() {
baresipService.action = "Stop Content Observer" baresipService.action = "Stop Content Observer"
} }
"android" -> { "android" -> {
BaresipService.baresipContacts.value = listOf() BaresipService.baresipContacts.value = mutableListOf<Contact.BaresipContact>()
Contact.loadAndroidContacts(this) Contact.loadAndroidContacts(this)
baresipService.action = "Start Content Observer" baresipService.action = "Start Content Observer"
} }
@@ -53,9 +53,9 @@ sealed class Contact {
} }
when (this) { when (this) {
is BaresipContact -> is BaresipContact ->
(copy as BaresipContact).avatarImage = avatarImage (copy as BaresipContact).avatarImage = this.avatarImage
is AndroidContact -> is AndroidContact ->
(copy as AndroidContact).uris.addAll(uris) (copy as AndroidContact).uris.addAll(this.uris)
} }
return copy return copy
} }
@@ -211,8 +211,7 @@ sealed class Contact {
val contacts = String(content) val contacts = String(content)
var contactNo = 0 var contactNo = 0
val baseId = System.currentTimeMillis() val baseId = System.currentTimeMillis()
val restored = mutableListOf<BaresipContact>() BaresipService.baresipContacts.value = mutableListOf<BaresipContact>()
BaresipService.baresipContacts.value = listOf()
contacts.lines().forEach { contacts.lines().forEach {
val parts = it.split("\"") val parts = it.split("\"")
if (parts.size == 3) { if (parts.size == 3) {
@@ -242,53 +241,50 @@ sealed class Contact {
if (contact.avatarImage == null) if (contact.avatarImage == null)
Log.d(TAG, "Contact $id avatarImage is null") Log.d(TAG, "Contact $id avatarImage is null")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Could not read avatar image from '$id.png") Log.e(TAG, "Could not read avatar image from file $id.png: ${e.message}")
} }
} }
restored.add(contact) BaresipService.baresipContacts.value.add(contact)
} }
} }
BaresipService.baresipContacts.value = restored.toList()
return true return true
} }
fun contactsUpdate() { fun contactsUpdate() {
val newList = mutableListOf<Contact>() BaresipService.contacts = mutableListOf<Contact>()
if (BaresipService.contactsMode != "android") if (BaresipService.contactsMode != "android")
for (c in BaresipService.baresipContacts.value) for (c in BaresipService.baresipContacts.value)
newList.add(c.copy()) BaresipService.contacts.add(c.copy())
if (BaresipService.contactsMode != "baresip") if (BaresipService.contactsMode != "baresip")
for (c in BaresipService.androidContacts.value) for (c in BaresipService.androidContacts.value)
if (!nameExists(c.name, newList, true)) if (!nameExists(c.name, BaresipService.contacts, true))
newList.add(c.copy()) BaresipService.contacts.add(c.copy())
newList.sortBy{ when (it) { BaresipService.contacts.sortBy{ when (it) {
is BaresipContact -> if (it.favorite) "0" + it.name else "1" + it.name is BaresipContact -> if (it.favorite) "0" + it.name else "1" + it.name
is AndroidContact -> if (it.favorite) "0" + it.name else "1" + it.name is AndroidContact -> if (it.favorite) "0" + it.name else "1" + it.name
}} }}
BaresipService.contacts = newList.toList()
generateContactNames() generateContactNames()
//BaresipService.contactUpdate.postValue(System.nanoTime())
} }
fun addBaresipContact(contact: BaresipContact) { fun addBaresipContact(contact: BaresipContact) {
val updatedList = BaresipService.baresipContacts.value.toMutableList() BaresipService.baresipContacts.value.add(contact)
updatedList.add(contact) saveBaresipContacts()
BaresipService.baresipContacts.value = updatedList.toList() contactsUpdate()
} }
fun updateBaresipContact(contact: BaresipContact) { fun updateBaresipContact(contact: BaresipContact) {
val updatedList = BaresipService.baresipContacts.value.toMutableList() val newContact = contact.copy() as BaresipContact
val contactCopy = contact.copy() BaresipService.baresipContacts.value.removeIf { it.id == contact.id }
updatedList.removeIf { it.id == contact.id } newContact.id = System.currentTimeMillis()
updatedList.add(contactCopy as BaresipContact) BaresipService.baresipContacts.value.add(newContact)
BaresipService.baresipContacts.value = updatedList.toList() saveBaresipContacts()
contactsUpdate()
} }
fun removeBaresipContact(contact: BaresipContact) { fun removeBaresipContact(contact: BaresipContact) {
val updatedList = BaresipService.baresipContacts.value.toMutableList() BaresipService.baresipContacts.value.removeIf { it.id == contact.id }
updatedList.removeIf { it.id == contact.id }
BaresipService.baresipContacts.value = updatedList.toList()
saveBaresipContacts() saveBaresipContacts()
contactsUpdate()
} }
private fun generateContactNames () { private fun generateContactNames () {
@@ -83,7 +83,6 @@ class ContactsActivity : ComponentActivity() {
if (it.data != null && it.data!!.hasExtra("name")) if (it.data != null && it.data!!.hasExtra("name"))
newAndroidName = it.data!!.getStringExtra("name") newAndroidName = it.data!!.getStringExtra("name")
} }
Contact.contactsUpdate()
} }
public override fun onCreate(savedInstanceState: Bundle?) { public override fun onCreate(savedInstanceState: Bundle?) {
@@ -107,11 +106,11 @@ class ContactsActivity : ComponentActivity() {
ContactsContract.Contacts.DISPLAY_NAME + "='" + newAndroidName + "'", null ContactsContract.Contacts.DISPLAY_NAME + "='" + newAndroidName + "'", null
) )
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Update of Android favorite failed") Log.e(TAG, "Update of Android favorite failed: ${e.message}")
} }
newAndroidName = null newAndroidName = null
} }
Contact.contactsUpdate() //Contact.contactsUpdate()
} }
BaresipService.contactUpdate.observe(this, androidContactsObserver) BaresipService.contactUpdate.observe(this, androidContactsObserver)
@@ -207,7 +206,7 @@ class ContactsActivity : ComponentActivity() {
state = lazyListState, state = lazyListState,
verticalArrangement = Arrangement.spacedBy(10.dp), verticalArrangement = Arrangement.spacedBy(10.dp),
) { ) {
items(BaresipService.contacts, key = { contact -> contact.id() }) { contact -> items(BaresipService.contacts, key = { it.id() }) { contact ->
val name = contact.name() val name = contact.name()
@@ -336,12 +335,12 @@ class ContactsActivity : ComponentActivity() {
} catch (e: IOException) { } catch (e: IOException) {
Log.e( Log.e(
TAG, TAG,
"Could not delete file '$id.png" "Could not delete file $id.png: ${e.message}"
) )
} }
} }
Contact.removeBaresipContact(contact) Contact.removeBaresipContact(contact)
Contact.contactsUpdate() //Contact.contactsUpdate()
} }
DialogInterface.BUTTON_NEUTRAL -> { DialogInterface.BUTTON_NEUTRAL -> {