From 6aa17309d893a27c945cf271d24187a7725d551b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 25 Aug 2022 14:22:47 +0200 Subject: [PATCH] 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 --- .../viewmodels/ContactEditorViewModel.kt | 61 ++++++- .../org/linphone/contact/ContactLoader.kt | 168 +++++++++--------- .../linphone/contact/NativeContactEditor.kt | 2 +- 3 files changed, 143 insertions(+), 88 deletions(-) diff --git a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactEditorViewModel.kt b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactEditorViewModel.kt index d07aa4f38..7518aa1bf 100644 --- a/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactEditorViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/contact/viewmodels/ContactEditorViewModel.kt @@ -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") + } + } } diff --git a/app/src/main/java/org/linphone/contact/ContactLoader.kt b/app/src/main/java/org/linphone/contact/ContactLoader.kt index 5281bacac..8c2eb829e 100644 --- a/app/src/main/java/org/linphone/contact/ContactLoader.kt +++ b/app/src/main/java/org/linphone/contact/ContactLoader.kt @@ -53,7 +53,7 @@ class ContactLoader : LoaderManager.LoaderCallbacks { "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 { 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") } diff --git a/app/src/main/java/org/linphone/contact/NativeContactEditor.kt b/app/src/main/java/org/linphone/contact/NativeContactEditor.kt index 1adeed96b..29accf52a 100644 --- a/app/src/main/java/org/linphone/contact/NativeContactEditor.kt +++ b/app/src/main/java/org/linphone/contact/NativeContactEditor.kt @@ -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