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:
parent
d26bebae37
commit
6aa17309d8
3 changed files with 143 additions and 88 deletions
|
@ -22,6 +22,7 @@ package org.linphone.activities.main.contact.viewmodels
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.media.ExifInterface
|
import android.media.ExifInterface
|
||||||
|
import android.provider.ContactsContract
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -79,9 +80,24 @@ class ContactEditorViewModel(val c: Friend?) : ViewModel(), ContactDataInterface
|
||||||
} else {
|
} else {
|
||||||
displayName.value = ""
|
displayName.value = ""
|
||||||
}
|
}
|
||||||
firstName.value = c?.vcard?.givenName ?: ""
|
|
||||||
lastName.value = c?.vcard?.familyName ?: ""
|
organization.value = c?.organization ?: ""
|
||||||
organization.value = c?.vcard?.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()
|
updateNumbersAndAddresses()
|
||||||
}
|
}
|
||||||
|
@ -231,4 +247,43 @@ class ContactEditorViewModel(val c: Friend?) : ViewModel(), ContactDataInterface
|
||||||
}
|
}
|
||||||
addresses.value = sipAddresses
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
"data1", // Company, Phone or SIP Address
|
"data1", // Company, Phone or SIP Address
|
||||||
"data2", // ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.SipAddress.TYPE
|
"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
|
"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
|
previousId = id
|
||||||
}
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
val friend = friends[id] ?: core.createFriend()
|
||||||
val friend = friends[id] ?: core.createFriend()
|
friend.refKey = id
|
||||||
friend.refKey = id
|
if (friend.name.isNullOrEmpty()) {
|
||||||
if (friend.name.isNullOrEmpty()) {
|
friend.name = displayName
|
||||||
friend.name = displayName
|
friend.photo = Uri.withAppendedPath(
|
||||||
friend.photo = Uri.withAppendedPath(
|
ContentUris.withAppendedId(
|
||||||
ContentUris.withAppendedId(
|
ContactsContract.Contacts.CONTENT_URI,
|
||||||
ContactsContract.Contacts.CONTENT_URI,
|
id.toLong()
|
||||||
id.toLong()
|
),
|
||||||
),
|
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
|
||||||
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
|
).toString()
|
||||||
).toString()
|
friend.starred = starred
|
||||||
friend.starred = starred
|
friend.nativeUri =
|
||||||
friend.nativeUri =
|
"${ContactsContract.Contacts.CONTENT_LOOKUP_URI}/$lookupKey"
|
||||||
"${ContactsContract.Contacts.CONTENT_LOOKUP_URI}/$lookupKey"
|
|
||||||
|
|
||||||
// Disable short term presence
|
// Disable short term presence
|
||||||
friend.isSubscribesEnabled = false
|
friend.isSubscribesEnabled = false
|
||||||
friend.incSubscribePolicy = SubscribePolicy.SPDeny
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
} catch (e: Exception) {
|
||||||
Log.e("[Contacts Loader] Exception: $e")
|
Log.e("[Contacts Loader] Exception: $e")
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@ class NativeContactEditor(val friend: Friend) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOrganization(value: String): NativeContactEditor {
|
fun setOrganization(value: String): NativeContactEditor {
|
||||||
val previousValue = friend.vcard?.organization.orEmpty()
|
val previousValue = friend.organization.orEmpty()
|
||||||
if (value == previousValue) {
|
if (value == previousValue) {
|
||||||
Log.d("[Native Contact Editor] Organization hasn't changed")
|
Log.d("[Native Contact Editor] Organization hasn't changed")
|
||||||
return this
|
return this
|
||||||
|
|
Loading…
Reference in a new issue