diff --git a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java index 2c6480432a..4cb80b8650 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java @@ -78,6 +78,10 @@ public class ContactAccessor { return results; } + public Cursor getAllSystemContacts(Context context) { + return context.getContentResolver().query(Phone.CONTENT_URI, new String[] {Phone.NUMBER, Phone.DISPLAY_NAME}, null, null, null); + } + public boolean isSystemContact(Context context, String number) { Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); String[] projection = new String[]{PhoneLookup.DISPLAY_NAME, PhoneLookup.LOOKUP_KEY, diff --git a/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java b/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java index e81059e7ba..378aa5afe4 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java @@ -44,9 +44,11 @@ import org.whispersystems.signalservice.api.util.PhoneNumberFormatter; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; /** * Database to supply all types of contacts that TextSecure needs to know about @@ -78,20 +80,17 @@ public class ContactsDatabase { } public synchronized @NonNull List
setRegisteredUsers(@NonNull Account account, - @NonNull List registeredContacts, + @NonNull List
registeredAddressList, boolean remove) throws RemoteException, OperationApplicationException { + Set
registeredAddressSet = new HashSet<>(); + List
addedAddresses = new LinkedList<>(); + ArrayList operations = new ArrayList<>(); + Map currentContacts = getSignalRawContacts(account); - Map registeredAddresses = new HashMap<>(); - List
addedAddresses = new LinkedList<>(); - ArrayList operations = new ArrayList<>(); - Map currentContacts = getSignalRawContacts(account); - - for (ContactTokenDetails registeredContact : registeredContacts) { - Address registeredAddress = Address.fromSerialized(registeredContact.getNumber()); - - registeredAddresses.put(registeredAddress, registeredContact); + for (Address registeredAddress : registeredAddressList) { + registeredAddressSet.add(registeredAddress); if (!currentContacts.containsKey(registeredAddress)) { Optional systemContactInfo = getSystemContactInfo(registeredAddress); @@ -107,9 +106,7 @@ public class ContactsDatabase { } for (Map.Entry currentContactEntry : currentContacts.entrySet()) { - ContactTokenDetails tokenDetails = registeredAddresses.get(currentContactEntry.getKey()); - - if (tokenDetails == null) { + if (!registeredAddressSet.contains(currentContactEntry.getKey())) { if (remove) { Log.w(TAG, "Removing number: " + currentContactEntry.getKey()); removeTextSecureRawContact(operations, account, currentContactEntry.getValue().getId()); @@ -132,7 +129,7 @@ public class ContactsDatabase { return addedAddresses; } - @NonNull Cursor querySystemContacts(String filter) { + @NonNull Cursor querySystemContacts(@Nullable String filter) { Uri uri; if (!TextUtils.isEmpty(filter)) { diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index 04720986d0..f92a6a9c3f 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -102,7 +102,8 @@ public class DatabaseFactory { private static final int NO_MORE_CANONICAL_ADDRESS_DATABASE = 37; private static final int NO_MORE_RECIPIENTS_PLURAL = 38; private static final int INTERNAL_DIRECTORY = 39; - private static final int DATABASE_VERSION = 39; + private static final int INTERNAL_SYSTEM_DISPLAY_NAME = 40; + private static final int DATABASE_VERSION = 40; private static final String DATABASE_NAME = "messages.db"; private static final Object lock = new Object(); @@ -1292,6 +1293,10 @@ public class DatabaseFactory { } } + if (oldVersion < INTERNAL_SYSTEM_DISPLAY_NAME) { + db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN system_display_name TEXT DEFAULT NULL"); + } + db.setTransactionSuccessful(); db.endTransaction(); } diff --git a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java index ebf231d32a..7c623e5229 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java @@ -40,9 +40,10 @@ public class RecipientPreferenceDatabase extends Database { private static final String DEFAULT_SUBSCRIPTION_ID = "default_subscription_id"; private static final String EXPIRE_MESSAGES = "expire_messages"; private static final String REGISTERED = "registered"; + private static final String SYSTEM_DISPLAY_NAME = "system_display_name"; private static final String[] RECIPIENT_PROJECTION = new String[] { - BLOCK, NOTIFICATION, VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED + BLOCK, NOTIFICATION, VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED, SYSTEM_DISPLAY_NAME }; static final List TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION) @@ -79,7 +80,8 @@ public class RecipientPreferenceDatabase extends Database { SEEN_INVITE_REMINDER + " INTEGER DEFAULT 0, " + DEFAULT_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " + EXPIRE_MESSAGES + " INTEGER DEFAULT 0, " + - REGISTERED + " INTEGER DEFAULT 0);"; + REGISTERED + " INTEGER DEFAULT 0, " + + SYSTEM_DISPLAY_NAME + " TEXT DEFAULT NULL);"; public RecipientPreferenceDatabase(Context context, SQLiteOpenHelper databaseHelper) { super(context, databaseHelper); @@ -128,6 +130,7 @@ public class RecipientPreferenceDatabase extends Database { int defaultSubscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(DEFAULT_SUBSCRIPTION_ID)); int expireMessages = cursor.getInt(cursor.getColumnIndexOrThrow(EXPIRE_MESSAGES)); boolean registered = cursor.getInt(cursor.getColumnIndexOrThrow(REGISTERED)) == 1; + String systemDisplayname = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME)); MaterialColor color; @@ -141,51 +144,52 @@ public class RecipientPreferenceDatabase extends Database { return new RecipientsPreferences(blocked, muteUntil, VibrateState.fromId(vibrateState), notificationUri, color, seenInviteReminder, - defaultSubscriptionId, expireMessages, registered); + defaultSubscriptionId, expireMessages, registered, + systemDisplayname); } public void setColor(Recipient recipient, MaterialColor color) { ContentValues values = new ContentValues(); values.put(COLOR, color.serialize()); - updateOrInsert(recipient, values); + updateOrInsert(recipient.getAddress(), values); } public void setDefaultSubscriptionId(@NonNull Recipient recipient, int defaultSubscriptionId) { ContentValues values = new ContentValues(); values.put(DEFAULT_SUBSCRIPTION_ID, defaultSubscriptionId); - updateOrInsert(recipient, values); + updateOrInsert(recipient.getAddress(), values); EventBus.getDefault().post(new RecipientPreferenceEvent(recipient)); } public void setBlocked(Recipient recipient, boolean blocked) { ContentValues values = new ContentValues(); values.put(BLOCK, blocked ? 1 : 0); - updateOrInsert(recipient, values); + updateOrInsert(recipient.getAddress(), values); } public void setRingtone(Recipient recipient, @Nullable Uri notification) { ContentValues values = new ContentValues(); values.put(NOTIFICATION, notification == null ? null : notification.toString()); - updateOrInsert(recipient, values); + updateOrInsert(recipient.getAddress(), values); } public void setVibrate(Recipient recipient, @NonNull VibrateState enabled) { ContentValues values = new ContentValues(); values.put(VIBRATE, enabled.getId()); - updateOrInsert(recipient, values); + updateOrInsert(recipient.getAddress(), values); } public void setMuted(Recipient recipient, long until) { Log.w(TAG, "Setting muted until: " + until); ContentValues values = new ContentValues(); values.put(MUTE_UNTIL, until); - updateOrInsert(recipient, values); + updateOrInsert(recipient.getAddress(), values); } public void setSeenInviteReminder(Recipient recipient, boolean seen) { ContentValues values = new ContentValues(1); values.put(SEEN_INVITE_REMINDER, seen ? 1 : 0); - updateOrInsert(recipient, values); + updateOrInsert(recipient.getAddress(), values); } public void setExpireMessages(Recipient recipient, int expiration) { @@ -193,7 +197,13 @@ public class RecipientPreferenceDatabase extends Database { ContentValues values = new ContentValues(1); values.put(EXPIRE_MESSAGES, expiration); - updateOrInsert(recipient, values); + updateOrInsert(recipient.getAddress(), values); + } + + public void setSystemDisplayName(@NonNull Address address, @Nullable String systemDisplayName) { + ContentValues values = new ContentValues(1); + values.put(SYSTEM_DISPLAY_NAME, systemDisplayName); + updateOrInsert(address, values); } public Set
getAllRecipients() { @@ -246,16 +256,16 @@ public class RecipientPreferenceDatabase extends Database { return results; } - private void updateOrInsert(Recipient recipient, ContentValues contentValues) { + private void updateOrInsert(Address address, ContentValues contentValues) { SQLiteDatabase database = databaseHelper.getWritableDatabase(); database.beginTransaction(); int updated = database.update(TABLE_NAME, contentValues, ADDRESS + " = ?", - new String[] {recipient.getAddress().serialize()}); + new String[] {address.serialize()}); if (updated < 1) { - contentValues.put(ADDRESS, recipient.getAddress().serialize()); + contentValues.put(ADDRESS, address.serialize()); database.insert(TABLE_NAME, null, contentValues); } @@ -275,6 +285,7 @@ public class RecipientPreferenceDatabase extends Database { private final int defaultSubscriptionId; private final int expireMessages; private final boolean registered; + private final String systemDisplayName; RecipientsPreferences(boolean blocked, long muteUntil, @NonNull VibrateState vibrateState, @@ -283,7 +294,8 @@ public class RecipientPreferenceDatabase extends Database { boolean seenInviteReminder, int defaultSubscriptionId, int expireMessages, - boolean registered) + boolean registered, + String systemDisplayName) { this.blocked = blocked; this.muteUntil = muteUntil; @@ -294,6 +306,7 @@ public class RecipientPreferenceDatabase extends Database { this.defaultSubscriptionId = defaultSubscriptionId; this.expireMessages = expireMessages; this.registered = registered; + this.systemDisplayName = systemDisplayName; } public @Nullable MaterialColor getColor() { @@ -331,6 +344,10 @@ public class RecipientPreferenceDatabase extends Database { public boolean isRegistered() { return registered; } + + public String getSystemDisplayName() { + return systemDisplayName; + } } public static class BlockedReader { diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index d78c7eb675..b7fca83afe 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.recipients; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.text.TextUtils; import android.util.Log; import org.thoughtcrime.securesms.color.MaterialColor; @@ -26,11 +27,13 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactColors; import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences; import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState; import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.libsignal.util.guava.Optional; import java.util.Collections; import java.util.HashSet; @@ -66,6 +69,7 @@ public class Recipient implements RecipientModifiedListener { Recipient(@NonNull Address address, @Nullable Recipient stale, + @NonNull Optional preferences, @NonNull ListenableFutureTask future) { this.address = address; @@ -86,6 +90,19 @@ public class Recipient implements RecipientModifiedListener { this.expireMessages = stale.expireMessages; } + if (preferences.isPresent()) { + if (!TextUtils.isEmpty(preferences.get().getSystemDisplayName())) { + this.name = preferences.get().getSystemDisplayName(); + } + + this.color = preferences.get().getColor(); + this.ringtone = preferences.get().getRingtone(); + this.mutedUntil = preferences.get().getMuteUntil(); + this.blocked = preferences.get().isBlocked(); + this.vibrate = preferences.get().getVibrateState(); + this.expireMessages = preferences.get().getExpireMessages(); + } + future.addListener(new FutureTaskListener() { @Override public void onSuccess(RecipientDetails result) { diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index 448b17f271..1c53a5fb4a 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -75,7 +75,7 @@ class RecipientProvider { } if (asynchronous) { - cachedRecipient = new Recipient(address, cachedRecipient, getRecipientDetailsAsync(context, address, preferences)); + cachedRecipient = new Recipient(address, cachedRecipient, preferences, getRecipientDetailsAsync(context, address, preferences)); } else { cachedRecipient = new Recipient(address, getRecipientDetailsSync(context, address, preferences, false)); } diff --git a/src/org/thoughtcrime/securesms/util/DirectoryHelper.java b/src/org/thoughtcrime/securesms/util/DirectoryHelper.java index b5e0248483..b178a1176d 100644 --- a/src/org/thoughtcrime/securesms/util/DirectoryHelper.java +++ b/src/org/thoughtcrime/securesms/util/DirectoryHelper.java @@ -5,6 +5,7 @@ import android.accounts.AccountManager; import android.content.ContentResolver; import android.content.Context; import android.content.OperationApplicationException; +import android.database.Cursor; import android.os.RemoteException; import android.provider.ContactsContract; import android.support.annotation.NonNull; @@ -92,7 +93,7 @@ public class DirectoryHelper { } recipientPreferenceDatabase.setRegistered(activeAddresses, new LinkedList<>(inactiveAddresses)); - return updateContactsDatabase(context, activeTokens, true); + return updateContactsDatabase(context, activeAddresses, true); } return new RefreshResult(new LinkedList<>(), false); @@ -111,7 +112,7 @@ public class DirectoryHelper { if (details.isPresent()) { recipientDatabase.setRegistered(Util.asList(recipient.getAddress()), new LinkedList<>()); - RefreshResult result = updateContactsDatabase(context, details.get()); + RefreshResult result = updateContactsDatabase(context, Util.asList(recipient.getAddress()), false); if (!result.getNewUsers().isEmpty() && TextSecurePreferences.isMultiDevice(context)) { ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceContactUpdateJob(context)); @@ -153,22 +154,26 @@ public class DirectoryHelper { else return Capability.UNKNOWN; } - private static @NonNull RefreshResult updateContactsDatabase(@NonNull Context context, - @NonNull final ContactTokenDetails activeToken) - { - return updateContactsDatabase(context, new LinkedList() {{add(activeToken);}}, false); - } - - private static @NonNull RefreshResult updateContactsDatabase(@NonNull Context context, - @NonNull List activeTokens, - boolean removeMissing) - { + private static @NonNull RefreshResult updateContactsDatabase(@NonNull Context context, @NonNull List
activeAddresses, boolean removeMissing) { Optional account = getOrCreateAccount(context); if (account.isPresent()) { try { List
newUsers = DatabaseFactory.getContactsDatabase(context) - .setRegisteredUsers(account.get().getAccount(), activeTokens, removeMissing); + .setRegisteredUsers(account.get().getAccount(), activeAddresses, removeMissing); + + Cursor cursor = ContactAccessor.getInstance().getAllSystemContacts(context); + + while (cursor != null && cursor.moveToNext()) { + String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)); + + if (!TextUtils.isEmpty(number)) { + Address address = Address.fromExternal(context, number); + String displayName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); + + DatabaseFactory.getRecipientPreferenceDatabase(context).setSystemDisplayName(address, displayName); + } + } return new RefreshResult(newUsers, account.get().isFresh()); } catch (RemoteException | OperationApplicationException e) {