From 73bc7220db11599c8698338e86585807de69a673 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Thu, 16 Jul 2015 22:40:04 -0700 Subject: [PATCH] Force explicit raw contact aggregation when possible. 1) Don't add registered numbers that aren't already contacts. 2) When adding raw contacts, force aggregation to an existing raw contact. // FREEBIE --- .../securesms/contacts/ContactsDatabase.java | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java b/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java index 38e2df5331..fdf2f043c7 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java @@ -24,6 +24,7 @@ import android.database.Cursor; import android.database.CursorWrapper; import android.database.MatrixCursor; import android.net.Uri; +import android.os.Build; import android.os.RemoteException; import android.provider.BaseColumns; import android.provider.ContactsContract; @@ -34,6 +35,7 @@ import android.text.TextUtils; import android.util.Pair; import org.thoughtcrime.securesms.R; +import org.whispersystems.libaxolotl.util.guava.Optional; import java.util.ArrayList; import java.util.HashMap; @@ -93,7 +95,11 @@ public class ContactsDatabase { for (String number : e164numbers) { if (!currentContacts.containsKey(number)) { - addTextSecureRawContact(operations, account, number); + Optional> systemContactInfo = getSystemContactInfo(number); + + if (systemContactInfo.isPresent()) { + addTextSecureRawContact(operations, account, systemContactInfo.get().first, systemContactInfo.get().second); + } } } @@ -109,7 +115,7 @@ public class ContactsDatabase { } private void addTextSecureRawContact(List operations, - Account account, String e164number) + Account account, String e164number, long aggregateId) { int index = operations.size(); Uri dataUri = ContactsContract.Data.CONTENT_URI.buildUpon() @@ -137,6 +143,14 @@ public class ContactsDatabase { .withValue(ContactsContract.Data.DATA3, context.getString(R.string.ContactsDatabase_message_s, e164number)) .withYieldAllowed(true) .build()); + + if (Build.VERSION.SDK_INT >= 11) { + operations.add(ContentProviderOperation.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI) + .withValue(ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, aggregateId) + .withValueBackReference(ContactsContract.AggregationExceptions.RAW_CONTACT_ID2, index) + .withValue(ContactsContract.AggregationExceptions.TYPE, ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER) + .build()); + } } private void removeTextSecureRawContact(List operations, @@ -232,6 +246,35 @@ public class ContactsDatabase { return newNumberCursor; } + private Optional> getSystemContactInfo(String e164number) { + Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(e164number)); + String[] projection = {ContactsContract.PhoneLookup.NUMBER, + ContactsContract.PhoneLookup._ID}; + Cursor numberCursor = null; + Cursor idCursor = null; + + try { + numberCursor = context.getContentResolver().query(uri, projection, null, null, null); + + if (numberCursor != null && numberCursor.moveToNext()) { + idCursor = context.getContentResolver().query(RawContacts.CONTENT_URI, + new String[] {RawContacts._ID}, + RawContacts.CONTACT_ID + " = ? ", + new String[] {String.valueOf(numberCursor.getLong(1))}, + null); + + if (idCursor != null && idCursor.moveToNext()) { + return Optional.of(new Pair<>(numberCursor.getString(0), idCursor.getLong(0))); + } + } + } finally { + if (numberCursor != null) numberCursor.close(); + if (idCursor != null) idCursor.close(); + } + + return Optional.absent(); + } + private static class ProjectionMappingCursor extends CursorWrapper { private final Map projectionMap;