Changes regarding contacts: always create & store changes in default account + always use linphone sync account for presence storage

This commit is contained in:
Sylvain Berfini 2020-06-16 14:08:32 +02:00
parent 2979ca0934
commit 888e136368
4 changed files with 68 additions and 112 deletions

View file

@ -81,14 +81,15 @@ class ContactEditorViewModel(val c: Contact?) : ViewModel(), ContactViewModelInt
if (contact == null) {
created = true
contact = if (PermissionHelper.get().hasWriteContactsPermission()) {
NativeContact(NativeContactEditor.createAndroidContact(null, null).toString())
// Store native contact in default sync account
NativeContact(NativeContactEditor.createAndroidContact().toString())
} else {
Contact()
}
}
if (contact is NativeContact) {
NativeContactEditor(contact, null, null)
NativeContactEditor(contact)
.setFirstAndLastNames(firstName.value.orEmpty(), lastName.value.orEmpty())
.setOrganization(organization.value.orEmpty())
.setPhoneNumbers(numbers.value.orEmpty())

View file

@ -247,11 +247,6 @@ class ContactsManager(private val context: Context) {
}
private fun initSyncAccount() {
if (!corePreferences.useLinphoneSyncAccount) {
Log.w("[Contacts Manager] Linphone sync account disabled, skipping initialization")
return
}
val accountManager = context.getSystemService(Context.ACCOUNT_SERVICE) as AccountManager
val accounts = accountManager.getAccountsByType(context.getString(R.string.sync_account_type))
if (accounts.isEmpty()) {
@ -332,13 +327,13 @@ class ContactsManager(private val context: Context) {
for (phoneNumber in contact.phoneNumbers) {
val sipAddress = contact.getContactForPhoneNumberOrAddress(phoneNumber)
if (sipAddress != null) {
Log.d("[Contacts Manager] Found presence information to store in native contact $contact")
val contactEditor = NativeContactEditor(contact, null, null)
Log.d("[Contacts Manager] Found presence information to store in native contact $contact under Linphone sync account")
val contactEditor = NativeContactEditor(contact, context.getString(R.string.sync_account_name), context.getString(R.string.sync_account_type))
val coroutineScope = CoroutineScope(Dispatchers.Main)
coroutineScope.launch {
val deferred = async {
withContext(Dispatchers.IO) {
contactEditor.setPresenceInformation(phoneNumber, sipAddress).commit()
contactEditor.ensureSyncAccountRawIdExists().setPresenceInformation(phoneNumber, sipAddress).commit()
}
}
deferred.await()

View file

@ -27,7 +27,6 @@ import android.provider.ContactsContract
import android.provider.ContactsContract.CommonDataKinds
import android.provider.ContactsContract.RawContacts
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R
import org.linphone.activities.main.contact.viewmodels.NumberOrAddressEditorViewModel
import org.linphone.core.tools.Log
@ -36,20 +35,14 @@ import org.linphone.utils.PermissionHelper
class NativeContactEditor(
val contact: NativeContact,
private var syncAccountName: String?,
private var syncAccountType: String?
private var syncAccountName: String? = null,
private var syncAccountType: String? = null
) {
companion object {
fun createAndroidContact(accountName: String?, accountType: String?): Long {
fun createAndroidContact(accountName: String? = null, accountType: String? = null): Long {
val values = ContentValues()
if (accountName == null && accountType == null && corePreferences.useLinphoneSyncAccount) {
values.put(RawContacts.ACCOUNT_NAME, AppUtils.getString(R.string.sync_account_name))
values.put(RawContacts.ACCOUNT_TYPE, AppUtils.getString(R.string.sync_account_type))
} else {
values.put(RawContacts.ACCOUNT_NAME, accountName)
values.put(RawContacts.ACCOUNT_TYPE, accountType)
}
values.put(RawContacts.ACCOUNT_NAME, accountName)
values.put(RawContacts.ACCOUNT_TYPE, accountType)
val rawContactUri = coreContext.context.contentResolver
.insert(RawContacts.CONTENT_URI, values)
@ -66,19 +59,13 @@ class NativeContactEditor(
"${ContactsContract.Data.CONTACT_ID} =? AND (${ContactsContract.Data.MIMETYPE} =? OR ${ContactsContract.Data.MIMETYPE} =?) AND data1=?"
private val presenceUpdateSelection =
"${ContactsContract.Data.CONTACT_ID} =? AND ${ContactsContract.Data.MIMETYPE} =? AND data3=?"
private val useLinphoneSyncAccount = corePreferences.useLinphoneSyncAccount
private val contactUri = ContactsContract.Data.CONTENT_URI
private var rawId: String? = null
private var linphoneRawId: String? = null
private var syncAccountRawId: String? = null
private var pictureByteArray: ByteArray? = null
init {
if (syncAccountName == null && syncAccountType == null && useLinphoneSyncAccount) {
syncAccountName = AppUtils.getString(R.string.sync_account_name)
syncAccountType = AppUtils.getString(R.string.sync_account_type)
}
Log.i("[Native Contact Editor] Using sync account $syncAccountName with type $syncAccountType")
val contentResolver = coreContext.context.contentResolver
val cursor = contentResolver.query(
@ -96,40 +83,16 @@ class NativeContactEditor(
}
val accountType = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_TYPE))
if (accountType == syncAccountType && linphoneRawId == null) {
linphoneRawId = cursor.getString(cursor.getColumnIndex(RawContacts._ID))
Log.d("[Native Contact Editor] Found linphone raw id $linphoneRawId for native contact with id ${contact.nativeId}")
if (accountType == syncAccountType && syncAccountRawId == null) {
syncAccountRawId = cursor.getString(cursor.getColumnIndex(RawContacts._ID))
Log.d("[Native Contact Editor] Found sync account raw id $syncAccountRawId for native contact with id ${contact.nativeId}")
}
} while (cursor.moveToNext() && linphoneRawId == null)
} while (cursor.moveToNext() && syncAccountRawId == null)
}
cursor?.close()
// When contact has been created with NativeContactEditor.createAndroidContact this is required
if (rawId == null) rawId = contact.nativeId
if (linphoneRawId == null && useLinphoneSyncAccount) {
Log.w("[Native Contact Editor] Linphone raw id not found")
val insert = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
.withValue(RawContacts.ACCOUNT_TYPE, syncAccountType)
.withValue(RawContacts.ACCOUNT_NAME, syncAccountName)
.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT)
.build()
addChanges(insert)
val update =
ContentProviderOperation.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI)
.withValue(
ContactsContract.AggregationExceptions.TYPE,
ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER
)
.withValue(ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, rawId)
.withValueBackReference(
ContactsContract.AggregationExceptions.RAW_CONTACT_ID2,
0
)
.build()
addChanges(update)
commit()
}
}
fun setFirstAndLastNames(firstName: String, lastName: String): NativeContactEditor {
@ -238,11 +201,7 @@ class NativeContactEditor(
// New address to add
addCount++
val address = sipAddress.newValue.value.orEmpty()
if (useLinphoneSyncAccount) {
addLinphoneAddress(address, address)
} else {
addSipAddress(address)
}
addSipAddress(address)
}
sipAddress.toRemove.value == true -> {
// Existing address to remove
@ -267,15 +226,41 @@ class NativeContactEditor(
return this
}
fun setPresenceInformation(phoneNumber: String, sipAddress: String): NativeContactEditor {
Log.d("[Native Contact Editor] Trying to add presence information to contact as ${if (useLinphoneSyncAccount) "phone number" else "SIP address"}")
fun ensureSyncAccountRawIdExists(): NativeContactEditor {
if (syncAccountRawId == null) {
Log.w("[Native Contact Editor] Sync account raw id not found")
val insert = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
.withValue(RawContacts.ACCOUNT_TYPE, syncAccountType)
.withValue(RawContacts.ACCOUNT_NAME, syncAccountName)
.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT)
.build()
addChanges(insert)
val update =
ContentProviderOperation.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI)
.withValue(
ContactsContract.AggregationExceptions.TYPE,
ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER
)
.withValue(ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, rawId)
.withValueBackReference(
ContactsContract.AggregationExceptions.RAW_CONTACT_ID2,
0
)
.build()
addChanges(update)
commit()
}
return this
}
if (useLinphoneSyncAccount) {
setPresenceLinphoneSipAddressForPhoneNumber(sipAddress, phoneNumber)
} else {
setPresenceSipAddress(sipAddress)
fun setPresenceInformation(phoneNumber: String, sipAddress: String): NativeContactEditor {
if (syncAccountRawId == null) {
Log.e("[Native Contact Editor] Can't add presence to contact in Linphone sync account, no raw id")
return this
}
Log.d("[Native Contact Editor] Trying to add presence information to contact")
setPresenceLinphoneSipAddressForPhoneNumber(sipAddress, phoneNumber)
return this
}
@ -287,9 +272,9 @@ class NativeContactEditor(
val results = contentResolver.applyBatch(ContactsContract.AUTHORITY, changes)
for (result in results) {
Log.i("[Native Contact Editor] Result is $result")
if (linphoneRawId == null && useLinphoneSyncAccount && result?.uri != null) {
linphoneRawId = ContentUris.parseId(result.uri).toString()
Log.i("[Native Contact Editor] Linphone raw id is $linphoneRawId")
if (syncAccountRawId == null && result?.uri != null) {
syncAccountRawId = ContentUris.parseId(result.uri).toString()
Log.i("[Native Contact Editor] Sync account raw id is $syncAccountRawId")
}
}
}
@ -362,20 +347,6 @@ class NativeContactEditor(
addChanges(delete)
}
private fun addLinphoneAddress(address: String, detail: String) {
val insert = ContentProviderOperation.newInsert(contactUri)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, linphoneRawId)
.withValue(
ContactsContract.Data.MIMETYPE,
AppUtils.getString(R.string.linphone_address_mime_type)
)
.withValue("data1", address) // value
.withValue("data2", AppUtils.getString(R.string.app_name)) // summary
.withValue("data3", detail) // detail
.build()
addChanges(insert)
}
private fun addSipAddress(address: String) {
val insert = ContentProviderOperation.newInsert(contactUri)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawId)
@ -431,7 +402,7 @@ class NativeContactEditor(
ContactsContract.Data.CONTENT_URI,
arrayOf("data1"),
"${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? AND data3 = ?",
arrayOf(linphoneRawId, AppUtils.getString(R.string.linphone_address_mime_type), phoneNumber),
arrayOf(syncAccountRawId, AppUtils.getString(R.string.linphone_address_mime_type), phoneNumber),
null
)
val count = cursor?.count ?: 0
@ -444,7 +415,7 @@ class NativeContactEditor(
if (count == 0) {
Log.i("[Native Contact Editor] No existing presence information found for this phone number & SIP address, let's add it")
addLinphoneAddress(sipAddress, phoneNumber)
addPresenceLinphoneSipAddressForPhoneNumber(sipAddress, phoneNumber)
} else {
if (data1 != null && data1 == sipAddress) {
Log.d("[Native Contact Editor] There is already an entry for this phone number and SIP address, skipping")
@ -455,6 +426,20 @@ class NativeContactEditor(
}
}
private fun addPresenceLinphoneSipAddressForPhoneNumber(address: String, detail: String) {
val insert = ContentProviderOperation.newInsert(contactUri)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, syncAccountRawId)
.withValue(
ContactsContract.Data.MIMETYPE,
AppUtils.getString(R.string.linphone_address_mime_type)
)
.withValue("data1", address) // value
.withValue("data2", AppUtils.getString(R.string.app_name)) // summary
.withValue("data3", detail) // detail
.build()
addChanges(insert)
}
private fun updatePresenceLinphoneSipAddressForPhoneNumber(
sipAddress: String,
phoneNumber: String
@ -479,26 +464,6 @@ class NativeContactEditor(
addChanges(update)
}
private fun setPresenceSipAddress(sipAddress: String) {
val contentResolver = coreContext.context.contentResolver
val cursor = contentResolver.query(
ContactsContract.Data.CONTENT_URI,
arrayOf("data1"),
"${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ? AND data1 = ?",
arrayOf(rawId, CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE, sipAddress),
null
)
val count = cursor?.count ?: 0
cursor?.close()
if (count == 0) {
Log.i("[Native Contact Editor] SIP address not found, let's add it")
addSipAddress(sipAddress)
} else {
Log.d("[Native Contact Editor] There is already an entry for this SIP address, skipping")
}
}
private fun updatePicture() {
val value = pictureByteArray
val id = rawId

View file

@ -227,11 +227,6 @@ class CorePreferences constructor(private val context: Context) {
val contactOrganizationVisible: Boolean
get() = config.getBool("app", "display_contact_organization", true)
// If enabled, SIP addresses will be stored in a different raw id than the contact and with a custom MIME type
// If disabled, contacts will be created in default account & addresses will be stored in native SIP field
val useLinphoneSyncAccount: Boolean
get() = config.getBool("app", "use_linphone_tag", true)
private val darkModeAllowed: Boolean
get() = config.getBool("app", "dark_mode_allowed", true)