From cf89c988cf30f592046ee65e2c0c4ddd64f8b03e Mon Sep 17 00:00:00 2001 From: Pratyush Venkatakrishnan Date: Tue, 16 Jan 2024 14:47:29 -0500 Subject: [PATCH] Set structured name when creating contacts. Fixes #12305. When creating copies of contacts, set the structured name fields instead of the unstructured name fields. This fixes bugs where certain types of names are displayed incorrectly because the structured name is inaccurately reconstructed from the unstructured name. Closes #13366 --- .../contactstest/ContactListViewModel.kt | 2 +- .../contacts/SystemContactsRepository.kt | 47 +++++++++++++++---- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/contacts/app/src/main/java/org/signal/contactstest/ContactListViewModel.kt b/contacts/app/src/main/java/org/signal/contactstest/ContactListViewModel.kt index 9f356b1e9f..bc5f0865ea 100644 --- a/contacts/app/src/main/java/org/signal/contactstest/ContactListViewModel.kt +++ b/contacts/app/src/main/java/org/signal/contactstest/ContactListViewModel.kt @@ -37,7 +37,7 @@ class ContactListViewModel(application: Application) : AndroidViewModel(applicat val contactList: List = SystemContactsRepository.getAllSystemContacts( context = application, e164Formatter = { number -> PhoneNumberUtils.formatNumberToE164(number, "US") ?: number } - ).use { it.toList() } + ).use { it.toList().sortedBy { c -> c.givenName } } _contacts.postValue(contactList) } else { diff --git a/contacts/lib/src/main/java/org/signal/contacts/SystemContactsRepository.kt b/contacts/lib/src/main/java/org/signal/contacts/SystemContactsRepository.kt index 436e5c0fec..645d54ba33 100644 --- a/contacts/lib/src/main/java/org/signal/contacts/SystemContactsRepository.kt +++ b/contacts/lib/src/main/java/org/signal/contacts/SystemContactsRepository.kt @@ -488,7 +488,12 @@ object SystemContactsRepository { // Data entry for name ContentProviderOperation.newInsert(dataUri) .withValueBackReference(ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID, operationIndex) - .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, systemContactInfo.displayName) + .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, systemContactInfo.name.displayName) + .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, systemContactInfo.name.givenName) + .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, systemContactInfo.name.familyName) + .withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, systemContactInfo.name.prefix) + .withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, systemContactInfo.name.suffix) + .withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, systemContactInfo.name.middleName) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .build(), @@ -596,15 +601,41 @@ object SystemContactsRepository { val systemNumber: String? = contactCursor.requireString(ContactsContract.PhoneLookup.NUMBER) if (systemNumber != null && e164Formatter(systemNumber) == e164) { val phoneLookupId = contactCursor.requireLong(ContactsContract.PhoneLookup._ID) + val idProjection = arrayOf(ContactsContract.RawContacts._ID) + val idSelection = "${ContactsContract.RawContacts.CONTACT_ID} = ? " + val idArgs = SqlUtil.buildArgs(phoneLookupId) - context.contentResolver.query(ContactsContract.RawContacts.CONTENT_URI, arrayOf(ContactsContract.RawContacts._ID), "${ContactsContract.RawContacts.CONTACT_ID} = ? ", SqlUtil.buildArgs(phoneLookupId), null)?.use { idCursor -> + context.contentResolver.query(ContactsContract.RawContacts.CONTENT_URI, idProjection, idSelection, idArgs, null)?.use { idCursor -> if (idCursor.moveToNext()) { - return SystemContactInfo( - displayName = contactCursor.requireString(ContactsContract.PhoneLookup.DISPLAY_NAME), - displayPhone = systemNumber, - siblingRawContactId = idCursor.requireLong(ContactsContract.RawContacts._ID), - type = contactCursor.requireInt(ContactsContract.PhoneLookup.TYPE) + val rawContactId = idCursor.requireLong(ContactsContract.RawContacts._ID) + val nameProjection = arrayOf( + ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, + ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, + ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, + ContactsContract.CommonDataKinds.StructuredName.PREFIX, + ContactsContract.CommonDataKinds.StructuredName.SUFFIX, + ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME ) + val nameSelection = "${ContactsContract.Data.RAW_CONTACT_ID} = ? AND ${ContactsContract.Data.MIMETYPE} = ?" + val nameArgs = SqlUtil.buildArgs(rawContactId, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) + + context.contentResolver.query(ContactsContract.Data.CONTENT_URI, nameProjection, nameSelection, nameArgs, null)?.use { nameCursor -> + if (nameCursor.moveToNext()) { + return SystemContactInfo( + name = NameDetails( + displayName = nameCursor.requireString(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME), + givenName = nameCursor.requireString(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME), + familyName = nameCursor.requireString(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME), + prefix = nameCursor.requireString(ContactsContract.CommonDataKinds.StructuredName.PREFIX), + suffix = nameCursor.requireString(ContactsContract.CommonDataKinds.StructuredName.SUFFIX), + middleName = nameCursor.requireString(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME) + ), + displayPhone = systemNumber, + siblingRawContactId = rawContactId, + type = contactCursor.requireInt(ContactsContract.PhoneLookup.TYPE) + ) + } + } } } } @@ -824,7 +855,7 @@ object SystemContactsRepository { ) private data class SystemContactInfo( - val displayName: String?, + val name: NameDetails, val displayPhone: String, val siblingRawContactId: Long, val type: Int