Revert latest changes on contact loader, keep creating friends in IO dispatcher but don't set first & last name in the vCard at that time, fetching those values when entering contact editor if needed

This commit is contained in:
Sylvain Berfini 2022-08-25 14:22:47 +02:00
parent d26bebae37
commit 6aa17309d8
3 changed files with 143 additions and 88 deletions

View file

@ -22,6 +22,7 @@ package org.linphone.activities.main.contact.viewmodels
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.media.ExifInterface
import android.provider.ContactsContract
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
@ -79,9 +80,24 @@ class ContactEditorViewModel(val c: Friend?) : ViewModel(), ContactDataInterface
} else {
displayName.value = ""
}
firstName.value = c?.vcard?.givenName ?: ""
lastName.value = c?.vcard?.familyName ?: ""
organization.value = c?.vcard?.organization ?: ""
organization.value = c?.organization ?: ""
firstName.value = ""
lastName.value = ""
val vCard = c?.vcard
if (vCard?.familyName.isNullOrEmpty() && vCard?.givenName.isNullOrEmpty()) {
val refKey = c?.refKey
if (refKey != null) {
Log.w("[Contact Editor] vCard first & last name not filled-in yet, doing it now")
fetchFirstAndLastNames(refKey)
} else {
Log.e("[Contact Editor] vCard first & last name not available as contact doesn't have a native ID")
}
} else {
firstName.value = vCard?.givenName
lastName.value = vCard?.familyName
}
updateNumbersAndAddresses()
}
@ -231,4 +247,43 @@ class ContactEditorViewModel(val c: Friend?) : ViewModel(), ContactDataInterface
}
addresses.value = sipAddresses
}
private fun fetchFirstAndLastNames(contactId: String) {
try {
val cursor = coreContext.context.contentResolver.query(
ContactsContract.Data.CONTENT_URI,
arrayOf(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME
),
ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?",
arrayOf(contactId),
null
)
while (cursor != null && cursor.moveToNext()) {
val mime: String? = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Data.MIMETYPE))
if (mime == ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) {
val givenName: String? =
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME))
if (!givenName.isNullOrEmpty()) {
c?.vcard?.givenName = givenName
firstName.value = givenName!!
}
val familyName: String? =
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME))
if (!familyName.isNullOrEmpty()) {
c?.vcard?.familyName = familyName
lastName.value = familyName!!
}
}
}
cursor?.close()
} catch (e: Exception) {
Log.e("[Contact Editor] Failed to fetch first & last name: $e")
}
}
}

View file

@ -53,7 +53,7 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
"data1", // Company, Phone or SIP Address
"data2", // ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.SipAddress.TYPE
"data3", // ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, ContactsContract.CommonDataKinds.Phone.LABEL, ContactsContract.CommonDataKinds.SipAddress.LABEL
"data4"
"data4" // Normalized phone number
)
}
@ -128,91 +128,91 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
previousId = id
}
withContext(Dispatchers.Main) {
val friend = friends[id] ?: core.createFriend()
friend.refKey = id
if (friend.name.isNullOrEmpty()) {
friend.name = displayName
friend.photo = Uri.withAppendedPath(
ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI,
id.toLong()
),
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
).toString()
friend.starred = starred
friend.nativeUri =
"${ContactsContract.Contacts.CONTENT_LOOKUP_URI}/$lookupKey"
val friend = friends[id] ?: core.createFriend()
friend.refKey = id
if (friend.name.isNullOrEmpty()) {
friend.name = displayName
friend.photo = Uri.withAppendedPath(
ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI,
id.toLong()
),
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
).toString()
friend.starred = starred
friend.nativeUri =
"${ContactsContract.Contacts.CONTENT_LOOKUP_URI}/$lookupKey"
// Disable short term presence
friend.isSubscribesEnabled = false
friend.incSubscribePolicy = SubscribePolicy.SPDeny
}
when (mime) {
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
val label =
PhoneNumberUtils.addressBookLabelTypeToVcardParamString(
data2?.toInt()
?: ContactsContract.CommonDataKinds.BaseTypes.TYPE_CUSTOM,
data3
)
val number =
if (corePreferences.preferNormalizedPhoneNumbersFromAddressBook ||
data1.isNullOrEmpty() ||
!Patterns.PHONE.matcher(data1).matches()
) {
data4 ?: data1
} else {
data1
}
if (number != null) {
if (
friendsPhoneNumbers.find {
PhoneNumberUtils.arePhoneNumberWeakEqual(
it,
number
)
} == null
) {
val phoneNumber = Factory.instance()
.createFriendPhoneNumber(number, label)
friend.addPhoneNumberWithLabel(phoneNumber)
friendsPhoneNumbers.add(number)
}
}
}
linphoneMime, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
if (data1 != null) {
val address = core.interpretUrl(data1, true)
if (address != null &&
friendsAddresses.find {
it.weakEqual(address)
} == null
) {
friend.addAddress(address)
friendsAddresses.add(address)
}
}
}
ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE -> {
if (data1 != null) {
friend.organization = data1
}
}
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
if (data2 != null && data3 != null) {
val vCard = friend.vcard
vCard?.givenName = data2
vCard?.familyName = data3
}
}
}
friends[id] = friend
// Disable short term presence
friend.isSubscribesEnabled = false
friend.incSubscribePolicy = SubscribePolicy.SPDeny
}
when (mime) {
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
val label =
PhoneNumberUtils.addressBookLabelTypeToVcardParamString(
data2?.toInt()
?: ContactsContract.CommonDataKinds.BaseTypes.TYPE_CUSTOM,
data3
)
val number =
if (corePreferences.preferNormalizedPhoneNumbersFromAddressBook ||
data1.isNullOrEmpty() ||
!Patterns.PHONE.matcher(data1).matches()
) {
data4 ?: data1
} else {
data1
}
if (number != null) {
if (
friendsPhoneNumbers.find {
PhoneNumberUtils.arePhoneNumberWeakEqual(
it,
number
)
} == null
) {
val phoneNumber = Factory.instance()
.createFriendPhoneNumber(number, label)
friend.addPhoneNumberWithLabel(phoneNumber)
friendsPhoneNumbers.add(number)
}
}
}
linphoneMime, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
if (data1 != null) {
val address = core.interpretUrl(data1, true)
if (address != null &&
friendsAddresses.find {
it.weakEqual(address)
} == null
) {
friend.addAddress(address)
friendsAddresses.add(address)
}
}
}
ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE -> {
if (data1 != null) {
friend.organization = data1
}
}
// Our API not being thread safe this causes crashes sometimes given the Play Store reports
// So these values will be fetched at the only moment they are required: contact edition
/*ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
if (data2 != null && data3 != null) {
val vCard = friend.vcard
vCard?.givenName = data2
vCard?.familyName = data3
}
}*/
}
friends[id] = friend
} catch (e: Exception) {
Log.e("[Contacts Loader] Exception: $e")
}

View file

@ -146,7 +146,7 @@ class NativeContactEditor(val friend: Friend) {
}
fun setOrganization(value: String): NativeContactEditor {
val previousValue = friend.vcard?.organization.orEmpty()
val previousValue = friend.organization.orEmpty()
if (value == previousValue) {
Log.d("[Native Contact Editor] Organization hasn't changed")
return this