Access all RecipientDatabase settings directly from Recipient

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2017-08-22 10:44:04 -07:00
parent d1790dfe17
commit f17af19d09
29 changed files with 504 additions and 390 deletions

View File

@ -108,8 +108,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientPreferenceEvent;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.identity.IdentityRecordList;
@ -142,7 +141,6 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.DirectoryHelper.Capability;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ExpirationUtil;
@ -574,10 +572,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
.setExpireMessages(recipient, expirationTime);
recipient.setExpireMessages(expirationTime);
DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient, expirationTime);
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(getRecipient(), System.currentTimeMillis(), expirationTime * 1000);
MessageSender.send(ConversationActivity.this, masterSecret, outgoingMessage, threadId, false, null);
@ -639,8 +634,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
.setPositiveButton(R.string.ConversationActivity_unblock, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
recipient.setBlocked(false);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
@ -1012,19 +1005,19 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
new AsyncTask<Recipient, Void, boolean[]>() {
@Override
protected boolean[] doInBackground(Recipient... params) {
Context context = ConversationActivity.this;
Recipient recipient = params[0];
Capability capability = DirectoryHelper.getUserCapabilities(context, recipient);
Context context = ConversationActivity.this;
Recipient recipient = params[0];
RegisteredState registeredState = recipient.resolve().getRegistered();
if (capability == Capability.UNKNOWN) {
if (registeredState == RegisteredState.UNKNOWN) {
try {
capability = DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipient);
registeredState = DirectoryHelper.refreshDirectoryFor(context, masterSecret, recipient);
} catch (IOException e) {
Log.w(TAG, e);
}
}
return new boolean[] {capability == Capability.SUPPORTED, Util.isDefaultSmsProvider(context)};
return new boolean[] {registeredState == RegisteredState.REGISTERED, Util.isDefaultSmsProvider(context)};
}
@Override
@ -1041,11 +1034,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void onSecurityUpdated() {
updateRecipientPreferences();
}
private void updateRecipientPreferences() {
new RecipientPreferencesTask().execute(recipient);
updateInviteReminder(recipient.hasSeenInviteReminder());
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
}
protected void updateInviteReminder(boolean seenInvite) {
@ -1284,19 +1274,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
titleView.setVerified(identityRecords.isVerified());
setBlockedUserState(recipient, isSecureText, isDefaultSms);
setActionBarColor(recipient.getColor());
updateInviteReminder(recipient.hasSeenInviteReminder());
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
initializeSecurity(isSecureText, isDefaultSms);
invalidateOptionsMenu();
updateRecipientPreferences();
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onRecipientPreferenceUpdate(final RecipientPreferenceEvent event) {
if (event.getRecipient().getAddress().equals(this.recipient.getAddress())) {
new RecipientPreferencesTask().execute(this.recipient);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onIdentityRecordUpdate(final IdentityRecord event) {
initializeIdentityRecords();
@ -1652,7 +1637,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
protected Long doInBackground(OutgoingMediaMessage... messages) {
if (initiating) {
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient.getAddress(), true);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
}
return MessageSender.send(context, masterSecret, messages[0], threadId, forceSms, new SmsDatabase.InsertListener() {
@ -1692,7 +1677,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
protected Long doInBackground(OutgoingTextMessage... messages) {
if (initiatingConversation) {
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient.getAddress(), true);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
}
return MessageSender.send(context, masterSecret, messages[0], threadId, forceSms, new SmsDatabase.InsertListener() {
@ -1989,27 +1974,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
updateToggleButtonState();
}
private class RecipientPreferencesTask extends AsyncTask<Recipient, Void, Pair<Recipient,RecipientSettings>> {
@Override
protected Pair<Recipient, RecipientSettings> doInBackground(Recipient... recipient) {
if (recipient.length != 1 || recipient[0] == null) {
throw new AssertionError("task needs exactly one Recipients object");
}
Optional<RecipientSettings> prefs = DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
.getRecipientSettings(recipient[0].getAddress());
return new Pair<>(recipient[0], prefs.orNull());
}
@Override
protected void onPostExecute(@NonNull Pair<Recipient, RecipientSettings> result) {
if (result.first == recipient) {
updateInviteReminder(result.second != null && result.second.hasSeenInviteReminder());
updateDefaultSubscriptionId(result.second != null ? result.second.getDefaultSubscriptionId() : Optional.<Integer>absent());
}
}
}
private class UnverifiedDismissedListener implements UnverifiedBannerView.DismissListener {
@Override
public void onDismissed(final List<IdentityRecord> unverifiedIdentities) {

View File

@ -18,7 +18,6 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
@ -54,7 +53,7 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
@ -167,9 +166,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
}
}
private static boolean isActiveInDirectory(Context context, Recipient recipient) {
Optional<RecipientSettings> preferences = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(recipient.getAddress());
return preferences.isPresent() && preferences.get().isRegistered();
private static boolean isActiveInDirectory(Recipient recipient) {
return recipient.resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED;
}
private void addSelectedContacts(@NonNull Recipient... recipients) {
@ -495,7 +493,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
final List<Result> results = new LinkedList<>();
for (Recipient recipient : recipients) {
boolean isPush = isActiveInDirectory(activity, recipient);
boolean isPush = isActiveInDirectory(recipient);
if (failIfNotPush && !isPush) {
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_cannot_add_non_push_to_existing_group,

View File

@ -230,9 +230,8 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
if (context == null) return null;
for (String number : numbers) {
Recipient recipient = Recipient.from(context, Address.fromExternal(context, number), false);
Optional<RecipientSettings> settings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(recipient.getAddress());
int subscriptionId = settings.isPresent() ? settings.get().getDefaultSubscriptionId().or(-1) : -1;
Recipient recipient = Recipient.from(context, Address.fromExternal(context, number), false);
int subscriptionId = recipient.getDefaultSubscriptionId().or(-1);
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipient, message, subscriptionId), -1L, true, null);

View File

@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
@ -43,7 +44,6 @@ import org.thoughtcrime.securesms.preferences.AdvancedRingtonePreference;
import org.thoughtcrime.securesms.preferences.ColorPreference;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
@ -350,8 +350,6 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
uri = Uri.parse(value);
}
recipient.setRingtone(uri);
new AsyncTask<Uri, Void, Void>() {
@Override
protected Void doInBackground(Uri... params) {
@ -371,8 +369,6 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
int value = Integer.parseInt((String) newValue);
final VibrateState vibrateState = VibrateState.fromId(value);
recipient.setVibrate(vibrateState);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
@ -397,16 +393,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
if (selectedColor == null) return true;
if (preference.isEnabled() && !currentColor.equals(selectedColor)) {
recipient.setColor(selectedColor);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Context context = getActivity();
DatabaseFactory.getRecipientDatabase(context)
.setColor(recipient, selectedColor);
DatabaseFactory.getRecipientDatabase(context).setColor(recipient, selectedColor);
if (DirectoryHelper.getUserCapabilities(context, recipient) == DirectoryHelper.Capability.SUPPORTED) {
if (recipient.resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceContactUpdateJob(context, recipient.getAddress()));
@ -516,8 +509,6 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
}
private void setBlocked(final Recipient recipient, final boolean blocked) {
recipient.setBlocked(blocked);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {

View File

@ -29,8 +29,8 @@ import android.util.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.NumberUtil;
import java.util.ArrayList;
@ -102,9 +102,9 @@ public class ContactsCursorLoader extends CursorLoader {
ContactsDatabase.CONTACT_TYPE_COLUMN});
while (cursor.moveToNext()) {
final String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN));
final Recipient recipient = Recipient.from(getContext(), Address.fromExternal(getContext(), number), true);
final Recipient recipient = Recipient.from(getContext(), Address.fromExternal(getContext(), number), false);
if (DirectoryHelper.getUserCapabilities(getContext(), recipient) != DirectoryHelper.Capability.SUPPORTED) {
if (recipient.resolve().getRegistered() != RecipientDatabase.RegisteredState.REGISTERED) {
matrix.addRow(new Object[]{cursor.getLong(cursor.getColumnIndexOrThrow(ContactsDatabase.ID_COLUMN)),
cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NAME_COLUMN)),
number,

View File

@ -32,4 +32,9 @@ public class BitmapContactPhoto implements ContactPhoto {
public Drawable asCallCard(Context context) {
return new BitmapDrawable(context.getResources(), bitmap);
}
@Override
public boolean isGenerated() {
return false;
}
}

View File

@ -8,5 +8,6 @@ public interface ContactPhoto {
public Drawable asDrawable(Context context, int color);
public Drawable asDrawable(Context context, int color, boolean inverted);
public Drawable asCallCard(Context context);
public boolean isGenerated();
}

View File

@ -50,4 +50,9 @@ public class GeneratedContactPhoto implements ContactPhoto {
public Drawable asCallCard(Context context) {
return ContextCompat.getDrawable(context, R.drawable.ic_contact_picture_large);
}
@Override
public boolean isGenerated() {
return true;
}
}

View File

@ -45,6 +45,11 @@ public class ResourceContactPhoto implements ContactPhoto {
return context.getResources().getDrawable(resourceId);
}
@Override
public boolean isGenerated() {
return false;
}
private static class ExpandingLayerDrawable extends LayerDrawable {
public ExpandingLayerDrawable(Drawable[] layers) {
super(layers);

View File

@ -26,4 +26,9 @@ public class TransparentContactPhoto implements ContactPhoto {
public Drawable asCallCard(Context context) {
return ContextCompat.getDrawable(context, R.drawable.ic_contact_picture_large);
}
@Override
public boolean isGenerated() {
return false;
}
}

View File

@ -191,20 +191,20 @@ public class DatabaseFactory {
}
private DatabaseFactory(Context context) {
this.databaseHelper = new DatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
this.sms = new SmsDatabase(context, databaseHelper);
this.encryptingSms = new EncryptingSmsDatabase(context, databaseHelper);
this.mms = new MmsDatabase(context, databaseHelper);
this.attachments = new AttachmentDatabase(context, databaseHelper);
this.media = new MediaDatabase(context, databaseHelper);
this.thread = new ThreadDatabase(context, databaseHelper);
this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper);
this.identityDatabase = new IdentityDatabase(context, databaseHelper);
this.draftDatabase = new DraftDatabase(context, databaseHelper);
this.pushDatabase = new PushDatabase(context, databaseHelper);
this.groupDatabase = new GroupDatabase(context, databaseHelper);
this.databaseHelper = new DatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
this.sms = new SmsDatabase(context, databaseHelper);
this.encryptingSms = new EncryptingSmsDatabase(context, databaseHelper);
this.mms = new MmsDatabase(context, databaseHelper);
this.attachments = new AttachmentDatabase(context, databaseHelper);
this.media = new MediaDatabase(context, databaseHelper);
this.thread = new ThreadDatabase(context, databaseHelper);
this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper);
this.identityDatabase = new IdentityDatabase(context, databaseHelper);
this.draftDatabase = new DraftDatabase(context, databaseHelper);
this.pushDatabase = new PushDatabase(context, databaseHelper);
this.groupDatabase = new GroupDatabase(context, databaseHelper);
this.recipientDatabase = new RecipientDatabase(context, databaseHelper);
this.contactsDatabase = new ContactsDatabase(context);
this.contactsDatabase = new ContactsDatabase(context);
}
public void reset(Context context) {
@ -1290,7 +1290,7 @@ public class DatabaseFactory {
String address = new NumberMigrator(TextSecurePreferences.getLocalNumber(context)).migrate(cursor.getString(0));
ContentValues contentValues = new ContentValues(1);
contentValues.put("registered", cursor.getInt(1) == 1);
contentValues.put("registered", cursor.getInt(1) == 1 ? 1 : 2);
if (db.update("recipient_preferences", contentValues, "recipient_ids = ?", new String[] {address}) < 1) {
contentValues.put("recipient_ids", address);

View File

@ -12,10 +12,11 @@ import android.util.Log;
import com.annimon.stream.Stream;
import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
@ -74,6 +75,24 @@ public class RecipientDatabase extends Database {
}
}
public enum RegisteredState {
UNKNOWN(0), REGISTERED(1), NOT_REGISTERED(2);
private final int id;
RegisteredState(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static RegisteredState fromId(int id) {
return values()[id];
}
}
public static final String CREATE_TABLE =
"CREATE TABLE " + TABLE_NAME +
" (" + ID + " INTEGER PRIMARY KEY, " +
@ -120,7 +139,7 @@ public class RecipientDatabase extends Database {
cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null);
if (cursor != null && cursor.moveToNext()) {
return getRecipientPreferences(cursor);
return getRecipientSettings(cursor);
}
return Optional.absent();
@ -129,7 +148,7 @@ public class RecipientDatabase extends Database {
}
}
Optional<RecipientSettings> getRecipientPreferences(@NonNull Cursor cursor) {
Optional<RecipientSettings> getRecipientSettings(@NonNull Cursor cursor) {
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
String notification = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION));
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE));
@ -139,12 +158,12 @@ public class RecipientDatabase extends Database {
boolean seenInviteReminder = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_INVITE_REMINDER)) == 1;
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;
int registeredState = cursor.getInt(cursor.getColumnIndexOrThrow(REGISTERED));
String profileKeyString = cursor.getString(cursor.getColumnIndexOrThrow(PROFILE_KEY));
String systemDisplayName = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME));
String signalProfileName = cursor.getString(cursor.getColumnIndexOrThrow(SIGNAL_PROFILE_NAME));
String signalProfileAvatar = cursor.getString(cursor.getColumnIndexOrThrow(SIGNAL_PROFILE_AVATAR));
boolean profileSharing = cursor.getInt(cursor.getColumnIndexOrThrow(PROFILE_SHARING)) == 1;
boolean profileSharing = cursor.getInt(cursor.getColumnIndexOrThrow(PROFILE_SHARING)) == 1;
MaterialColor color;
byte[] profileKey = null;
@ -168,7 +187,8 @@ public class RecipientDatabase extends Database {
return Optional.of(new RecipientSettings(blocked, muteUntil,
VibrateState.fromId(vibrateState),
notificationUri, color, seenInviteReminder,
defaultSubscriptionId, expireMessages, registered,
defaultSubscriptionId, expireMessages,
RegisteredState.fromId(registeredState),
profileKey, systemDisplayName, signalProfileName,
signalProfileAvatar, profileSharing));
}
@ -185,117 +205,129 @@ public class RecipientDatabase extends Database {
return new BulkOperationsHandle(database);
}
public void setColor(Recipient recipient, MaterialColor color) {
public void setColor(@NonNull Recipient recipient, @NonNull MaterialColor color) {
ContentValues values = new ContentValues();
values.put(COLOR, color.serialize());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setColor(color);
}
public void setDefaultSubscriptionId(@NonNull Recipient recipient, int defaultSubscriptionId) {
ContentValues values = new ContentValues();
values.put(DEFAULT_SUBSCRIPTION_ID, defaultSubscriptionId);
updateOrInsert(recipient.getAddress(), values);
EventBus.getDefault().post(new RecipientPreferenceEvent(recipient));
recipient.resolve().setDefaultSubscriptionId(Optional.of(defaultSubscriptionId));
}
public void setBlocked(Recipient recipient, boolean blocked) {
public void setBlocked(@NonNull Recipient recipient, boolean blocked) {
ContentValues values = new ContentValues();
values.put(BLOCK, blocked ? 1 : 0);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setBlocked(blocked);
}
public void setRingtone(Recipient recipient, @Nullable Uri notification) {
public void setRingtone(@NonNull Recipient recipient, @Nullable Uri notification) {
ContentValues values = new ContentValues();
values.put(NOTIFICATION, notification == null ? null : notification.toString());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setRingtone(notification);
}
public void setVibrate(Recipient recipient, @NonNull VibrateState enabled) {
public void setVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) {
ContentValues values = new ContentValues();
values.put(VIBRATE, enabled.getId());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setVibrate(enabled);
}
public void setMuted(Recipient recipient, long until) {
public void setMuted(@NonNull Recipient recipient, long until) {
ContentValues values = new ContentValues();
values.put(MUTE_UNTIL, until);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setMuted(until);
}
public void setSeenInviteReminder(Recipient recipient, boolean seen) {
public void setSeenInviteReminder(@NonNull Recipient recipient, boolean seen) {
ContentValues values = new ContentValues(1);
values.put(SEEN_INVITE_REMINDER, seen ? 1 : 0);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setHasSeenInviteReminder(seen);
}
public void setExpireMessages(Recipient recipient, int expiration) {
public void setExpireMessages(@NonNull Recipient recipient, int expiration) {
recipient.setExpireMessages(expiration);
ContentValues values = new ContentValues(1);
values.put(EXPIRE_MESSAGES, expiration);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setExpireMessages(expiration);
}
public void setSystemDisplayName(@NonNull Address address, @Nullable String systemDisplayName) {
ContentValues values = new ContentValues(1);
values.put(SYSTEM_DISPLAY_NAME, systemDisplayName);
updateOrInsert(address, values);
}
public void setProfileKey(@NonNull Address address, @Nullable byte[] profileKey) {
public void setProfileKey(@NonNull Recipient recipient, @Nullable byte[] profileKey) {
ContentValues values = new ContentValues(1);
values.put(PROFILE_KEY, profileKey == null ? null : Base64.encodeBytes(profileKey));
updateOrInsert(address, values);;
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setProfileKey(profileKey);
}
public void setProfileName(@NonNull Address address, @Nullable String profileName) {
public void setProfileName(@NonNull Recipient recipient, @Nullable String profileName) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(SIGNAL_PROFILE_NAME, profileName);
updateOrInsert(address, contentValues);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.resolve().setProfileName(profileName);
}
public void setProfileAvatar(@NonNull Address address, @Nullable String profileAvatar) {
public void setProfileAvatar(@NonNull Recipient recipient, @Nullable String profileAvatar) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(SIGNAL_PROFILE_AVATAR, profileAvatar);
updateOrInsert(address, contentValues);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.resolve().setProfileAvatar(profileAvatar);
}
public void setProfileSharing(@NonNull Address address, boolean enabled) {
public void setProfileSharing(@NonNull Recipient recipient, boolean enabled) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(PROFILE_SHARING, enabled ? 1 : 0);
updateOrInsert(address, contentValues);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.setProfileSharing(enabled);
}
public Set<Address> getAllRecipients() {
public Set<Recipient> getAllRecipients() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Set<Address> results = new HashSet<>();
Set<Recipient> results = new HashSet<>();
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, null, null, null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
results.add(Address.fromExternal(context, cursor.getString(0)));
results.add(Recipient.from(context, Address.fromExternal(context, cursor.getString(0)), true));
}
}
return results;
}
public void setRegistered(@NonNull List<Address> activeAddresses,
@NonNull List<Address> inactiveAddresses)
public void setRegistered(@NonNull Recipient recipient, RegisteredState registeredState) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(REGISTERED, registeredState.getId());
updateOrInsert(recipient.getAddress(), contentValues);
recipient.setRegistered(registeredState);
}
public void setRegistered(@NonNull List<Recipient> activeRecipients,
@NonNull List<Recipient> inactiveRecipients)
{
SQLiteDatabase db = databaseHelper.getWritableDatabase();
for (Address activeAddress : activeAddresses) {
for (Recipient activeRecipient : activeRecipients) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(REGISTERED, 1);
contentValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
updateOrInsert(activeAddress, contentValues);
updateOrInsert(activeRecipient.getAddress(), contentValues);
activeRecipient.setRegistered(RegisteredState.REGISTERED);
}
for (Address inactiveAddress : inactiveAddresses) {
for (Recipient inactiveRecipient : inactiveRecipients) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(REGISTERED, 0);
contentValues.put(REGISTERED, RegisteredState.NOT_REGISTERED.getId());
updateOrInsert(inactiveAddress, contentValues);
updateOrInsert(inactiveRecipient.getAddress(), contentValues);
inactiveRecipient.setRegistered(RegisteredState.NOT_REGISTERED);
}
context.getContentResolver().notifyChange(Uri.parse(RECIPIENT_PREFERENCES_URI), null);
@ -341,39 +373,44 @@ public class RecipientDatabase extends Database {
private final SQLiteDatabase database;
public BulkOperationsHandle(SQLiteDatabase database) {
private final List<Pair<Recipient, String>> pendingDisplayNames = new LinkedList<>();
BulkOperationsHandle(SQLiteDatabase database) {
this.database = database;
}
public void setDisplayName(@NonNull Address address, @Nullable String displayName) {
public void setDisplayName(@NonNull Recipient recipient, @Nullable String displayName) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(SYSTEM_DISPLAY_NAME, displayName);
updateOrInsert(address, contentValues);
updateOrInsert(recipient.getAddress(), contentValues);
pendingDisplayNames.add(new Pair<>(recipient, displayName));
}
public void finish() {
database.setTransactionSuccessful();
database.endTransaction();
Recipient.clearCache(context);
Stream.of(pendingDisplayNames).forEach(pair -> pair.first().resolve().setSystemDisplayName(pair.second()));
context.getContentResolver().notifyChange(Uri.parse(RECIPIENT_PREFERENCES_URI), null);
}
}
public static class RecipientSettings {
private final boolean blocked;
private final long muteUntil;
private final VibrateState vibrateState;
private final Uri notification;
private final MaterialColor color;
private final boolean seenInviteReminder;
private final int defaultSubscriptionId;
private final int expireMessages;
private final boolean registered;
private final byte[] profileKey;
private final String systemDisplayName;
private final String signalProfileName;
private final String signalProfileAvatar;
private final boolean profileSharing;
private final boolean blocked;
private final long muteUntil;
private final VibrateState vibrateState;
private final Uri notification;
private final MaterialColor color;
private final boolean seenInviteReminder;
private final int defaultSubscriptionId;
private final int expireMessages;
private final RegisteredState registered;
private final byte[] profileKey;
private final String systemDisplayName;
private final String signalProfileName;
private final String signalProfileAvatar;
private final boolean profileSharing;
RecipientSettings(boolean blocked, long muteUntil,
@NonNull VibrateState vibrateState,
@ -382,7 +419,7 @@ public class RecipientDatabase extends Database {
boolean seenInviteReminder,
int defaultSubscriptionId,
int expireMessages,
boolean registered,
@NonNull RegisteredState registered,
@Nullable byte[] profileKey,
@Nullable String systemDisplayName,
@Nullable String signalProfileName,
@ -437,7 +474,7 @@ public class RecipientDatabase extends Database {
return expireMessages;
}
public boolean isRegistered() {
public RegisteredState getRegistered() {
return registered;
}
@ -485,17 +522,4 @@ public class RecipientDatabase extends Database {
return getCurrent();
}
}
public static class RecipientPreferenceEvent {
private final Recipient recipient;
public RecipientPreferenceEvent(Recipient recipients) {
this.recipient = recipients;
}
public Recipient getRecipient() {
return recipient;
}
}
}

View File

@ -624,7 +624,7 @@ public class ThreadDatabase extends Database {
Optional<GroupRecord> groupRecord;
if (distributionType != DistributionTypes.ARCHIVE) {
settings = DatabaseFactory.getRecipientDatabase(context).getRecipientPreferences(cursor);
settings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(cursor);
groupRecord = DatabaseFactory.getGroupDatabase(context).getGroup(cursor);
} else {
settings = Optional.absent();

View File

@ -43,21 +43,21 @@ public class GroupManager {
@Nullable String name,
boolean mms)
{
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
final String groupId = GroupUtil.getEncodedId(groupDatabase.allocateGroupId(), mms);
final Set<Address> memberAddresses = getMemberAddresses(members);
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
final String groupId = GroupUtil.getEncodedId(groupDatabase.allocateGroupId(), mms);
final Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), false);
final Set<Address> memberAddresses = getMemberAddresses(members);
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null);
if (!mms) {
groupDatabase.updateAvatar(groupId, avatarBytes);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Address.fromSerialized(groupId), true);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true);
return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, avatarBytes);
} else {
Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), true);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
return new GroupActionResult(groupRecipient, threadId);
}
}

View File

@ -803,19 +803,14 @@ public class PushDecryptJob extends ContextJob {
private void handleProfileKey(@NonNull SignalServiceEnvelope envelope,
@NonNull SignalServiceDataMessage message)
{
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
Address sourceAddress = Address.fromExternal(context, envelope.getSource());
Optional<RecipientSettings> settings = database.getRecipientSettings(sourceAddress);
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
Address sourceAddress = Address.fromExternal(context, envelope.getSource());
Recipient recipient = Recipient.from(context, sourceAddress, false);
if (!settings.isPresent() || settings.get().getProfileKey() == null ||
!MessageDigest.isEqual(message.getProfileKey().get(), settings.get().getProfileKey()))
{
database.setProfileKey(sourceAddress, message.getProfileKey().get());
Recipient recipient = Recipient.from(context, sourceAddress, true);
if (recipient.getProfileKey() == null || MessageDigest.isEqual(recipient.getProfileKey(), message.getProfileKey().get())) {
database.setProfileKey(recipient, message.getProfileKey().get());
ApplicationContext.getInstance(context).getJobManager().add(new RetrieveProfileJob(context, recipient));
}
}
private Optional<InsertResult> insertPlaceholder(@NonNull SignalServiceEnvelope envelope) {

View File

@ -114,7 +114,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(masterSecret, scaledAttachments);
Optional<byte[]> profileKey = getProfileKey(message.getRecipient().getAddress());
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
.withBody(message.getBody())
.withAttachments(attachmentStreams)

View File

@ -1,12 +1,14 @@
package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.KeyCachingService;
@ -27,11 +29,11 @@ public abstract class PushReceivedJob extends ContextJob {
}
public void handle(SignalServiceEnvelope envelope, boolean sendExplicitReceipt) {
Address source = Address.fromExternal(context, envelope.getSource());
Address source = Address.fromExternal(context, envelope.getSource());
Recipient recipient = Recipient.from(context, source, false);
if (!isActiveNumber(context, source)) {
DatabaseFactory.getRecipientDatabase(context).setRegistered(Util.asList(source), new LinkedList<>());
Recipient recipient = Recipient.from(context, source, false);
if (!isActiveNumber(recipient)) {
DatabaseFactory.getRecipientDatabase(context).setRegistered(recipient, RecipientDatabase.RegisteredState.REGISTERED);
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context, KeyCachingService.getMasterSecret(context), recipient));
}
@ -68,9 +70,8 @@ public abstract class PushReceivedJob extends ContextJob {
envelope.getTimestamp()));
}
private boolean isActiveNumber(Context context, Address address) {
Optional<RecipientSettings> settings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(address);
return settings.isPresent() && settings.get().isRegistered();
private boolean isActiveNumber(@NonNull Recipient recipient) {
return recipient.resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED;
}

View File

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
@ -64,17 +65,11 @@ public abstract class PushSendJob extends SendJob {
onPushSend(masterSecret);
}
protected Optional<byte[]> getProfileKey(Address address) {
protected Optional<byte[]> getProfileKey(@NonNull Recipient recipient) {
try {
Optional<RecipientSettings> recipientsPreferences = DatabaseFactory.getRecipientDatabase(context)
.getRecipientSettings(address);
if (!recipientsPreferences.isPresent()) return Optional.absent();
boolean isSystemContact = !TextUtils.isEmpty(recipientsPreferences.get().getSystemDisplayName());
boolean isApproved = recipientsPreferences.get().isProfileSharing();
if (!isSystemContact & !isApproved) return Optional.absent();
if (!recipient.resolve().isSystemContact() && !recipient.resolve().isProfileSharing()) {
return Optional.absent();
}
String profileKey = TextSecurePreferences.getProfileKey(context);

View File

@ -102,7 +102,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
try {
SignalServiceAddress address = getPushAddress(message.getIndividualRecipient().getAddress());
SignalServiceMessageSender messageSender = messageSenderFactory.create();
Optional<byte[]> profileKey = getProfileKey(message.getIndividualRecipient().getAddress());
Optional<byte[]> profileKey = getProfileKey(message.getIndividualRecipient());
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
.withTimestamp(message.getDateSent())
.withBody(message.getBody().getBody())

View File

@ -5,16 +5,16 @@ import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
@ -51,20 +51,15 @@ public class RetrieveProfileAvatarJob extends ContextJob implements InjectableTy
@Override
public void onRun() throws IOException {
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
Optional<RecipientSettings> recipientSettings = database.getRecipientSettings(recipient.getAddress());
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
byte[] profileKey = recipient.resolve().getProfileKey();
if (!recipientSettings.isPresent()) {
Log.w(TAG, "Recipient preference row is gone!");
return;
}
if (recipientSettings.get().getProfileKey() == null) {
if (profileKey == null) {
Log.w(TAG, "Recipient profile key is gone!");
return;
}
if (Util.equals(profileAvatar, recipientSettings.get().getProfileAvatar())) {
if (Util.equals(profileAvatar, recipient.resolve().getProfileAvatar())) {
Log.w(TAG, "Already retrieved profile avatar: " + profileAvatar);
return;
}
@ -72,13 +67,14 @@ public class RetrieveProfileAvatarJob extends ContextJob implements InjectableTy
if (TextUtils.isEmpty(profileAvatar)) {
Log.w(TAG, "Removing profile avatar for: " + recipient.getAddress().serialize());
AvatarHelper.delete(context, recipient.getAddress());
database.setProfileAvatar(recipient, profileAvatar);
return;
}
File downloadDestination = File.createTempFile("avatar", "jpg", context.getCacheDir());
try {
InputStream avatarStream = receiver.retrieveProfileAvatar(profileAvatar, downloadDestination, recipientSettings.get().getProfileKey(), MAX_PROFILE_SIZE_BYTES);
InputStream avatarStream = receiver.retrieveProfileAvatar(profileAvatar, downloadDestination, profileKey, MAX_PROFILE_SIZE_BYTES);
File decryptDestination = File.createTempFile("avatar", "jpg", context.getCacheDir());
Util.copy(avatarStream, new FileOutputStream(decryptDestination));
@ -87,8 +83,11 @@ public class RetrieveProfileAvatarJob extends ContextJob implements InjectableTy
if (downloadDestination != null) downloadDestination.delete();
}
database.setProfileAvatar(recipient.getAddress(), profileAvatar);
Recipient.clearCache(context);
database.setProfileAvatar(recipient, profileAvatar);
if (recipient.resolve().getContactPhoto().isGenerated()) {
recipient.setContactPhoto(ContactPhotoFactory.getSignalAvatarContactPhoto(context, recipient.getAddress(), recipient.getName(), context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size)));
}
}
@Override

View File

@ -71,13 +71,12 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
private void handleIndividualRecipient(Recipient recipient)
throws IOException, InvalidKeyException, InvalidNumberException
{
String number = recipient.getAddress().toPhoneString();
SignalServiceProfile profile = retrieveProfile(number);
Optional<RecipientSettings> recipientSettings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(recipient.getAddress());
String number = recipient.getAddress().toPhoneString();
SignalServiceProfile profile = retrieveProfile(number);
setIdentityKey(recipient, profile.getIdentityKey());
setProfileName(recipient, recipientSettings, profile.getName());
setProfileAvatar(recipient, recipientSettings, profile.getAvatar());
setProfileName(recipient, profile.getName());
setProfileAvatar(recipient, profile.getAvatar());
}
private void handleGroupRecipient(Recipient group)
@ -127,32 +126,30 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
}
}
private void setProfileName(Recipient recipient, Optional<RecipientSettings> recipientPreferences, String profileName) {
private void setProfileName(Recipient recipient, String profileName) {
try {
if (!recipientPreferences.isPresent()) return;
if (recipientPreferences.get().getProfileKey() == null) return;
byte[] profileKey = recipient.getProfileKey();
if (profileKey == null) return;
String plaintextProfileName = null;
if (profileName != null) {
ProfileCipher profileCipher = new ProfileCipher(recipientPreferences.get().getProfileKey());
ProfileCipher profileCipher = new ProfileCipher(profileKey);
plaintextProfileName = new String(profileCipher.decryptName(Base64.decode(profileName)));
}
if (!Util.equals(plaintextProfileName, recipientPreferences.get().getProfileName())) {
DatabaseFactory.getRecipientDatabase(context).setProfileName(recipient.getAddress(), plaintextProfileName);
Recipient.clearCache(context);
if (!Util.equals(plaintextProfileName, recipient.getProfileName())) {
DatabaseFactory.getRecipientDatabase(context).setProfileName(recipient, plaintextProfileName);
}
} catch (ProfileCipher.InvalidCiphertextException | IOException e) {
Log.w(TAG, e);
}
}
private void setProfileAvatar(Recipient recipient, Optional<RecipientSettings> recipientPreferences, String profileAvatar) {
if (!recipientPreferences.isPresent()) return;
if (recipientPreferences.get().getProfileKey() == null) return;
private void setProfileAvatar(Recipient recipient, String profileAvatar) {
if (recipient.getProfileKey() == null) return;
if (!Util.equals(profileAvatar, recipientPreferences.get().getProfileAvatar())) {
if (!Util.equals(profileAvatar, recipient.getProfileAvatar())) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new RetrieveProfileAvatarJob(context, recipient, profileAvatar));

View File

@ -73,9 +73,8 @@ public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
long replyThreadId;
Optional<RecipientSettings> settings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(address);
int subscriptionId = settings.isPresent() ? settings.get().getDefaultSubscriptionId().or(-1) : -1;
long expiresIn = settings.isPresent() ? settings.get().getExpireMessages() * 1000 : 0;
int subscriptionId = recipient.getDefaultSubscriptionId().or(-1);
long expiresIn = recipient.getExpireMessages() * 1000;
if (recipient.isGroupRecipient()) {
Log.w("AndroidAutoReplyReceiver", "GroupRecipient, Sending media message");

View File

@ -67,10 +67,9 @@ public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
protected Void doInBackground(Void... params) {
long threadId;
Optional<RecipientSettings> settings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(address);
int subscriptionId = settings.isPresent() ? settings.get().getDefaultSubscriptionId().or(-1) : -1;
long expiresIn = settings.isPresent() ? settings.get().getExpireMessages() * 1000 : 0;
Recipient recipient = Recipient.from(context, address, false);
int subscriptionId = recipient.getDefaultSubscriptionId().or(-1);
long expiresIn = recipient.getExpireMessages() * 1000;
if (recipient.isGroupRecipient()) {
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipient, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);

View File

@ -52,11 +52,6 @@ public class UnknownSenderView extends FrameLayout {
if (threadId != -1) DatabaseFactory.getThreadDatabase(context).setHasSent(threadId, true);
return null;
}
@Override
protected void onPostExecute(Void result) {
recipient.setBlocked(true);
}
}.execute();
})
.setNegativeButton(android.R.string.cancel, null)
@ -94,7 +89,7 @@ public class UnknownSenderView extends FrameLayout {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient.getAddress(), true);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
if (threadId != -1) DatabaseFactory.getThreadDatabase(context).setHasSent(threadId, true);
return null;
}

View File

@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
import org.thoughtcrime.securesms.util.FutureTaskListener;
@ -61,16 +62,24 @@ public class Recipient implements RecipientModifiedListener {
private boolean stale;
private boolean resolving;
private ContactPhoto contactPhoto;
private Uri contactUri;
private Uri ringtone = null;
private long mutedUntil = 0;
private boolean blocked = false;
private VibrateState vibrate = VibrateState.DEFAULT;
private int expireMessages = 0;
private String profileName = null;
private ContactPhoto contactPhoto;
private Uri contactUri;
private @Nullable Uri ringtone = null;
private long mutedUntil = 0;
private boolean blocked = false;
private VibrateState vibrate = VibrateState.DEFAULT;
private int expireMessages = 0;
private Optional<Integer> defaultSubscriptionId = Optional.absent();
private @NonNull RegisteredState registered = RegisteredState.UNKNOWN;
private @Nullable MaterialColor color;
private boolean seenInviteReminder;
private @Nullable byte[] profileKey;
private @Nullable String profileName;
private @Nullable String profileAvatar;
private boolean profileSharing;
private boolean isSystemContact;
@Nullable private MaterialColor color;
public static @NonNull Recipient from(@NonNull Context context, @NonNull Address address, boolean asynchronous) {
if (address == null) throw new AssertionError(address);
@ -98,31 +107,45 @@ public class Recipient implements RecipientModifiedListener {
this.resolving = true;
if (stale != null) {
this.name = stale.name;
this.contactUri = stale.contactUri;
this.contactPhoto = stale.contactPhoto;
this.color = stale.color;
this.customLabel = stale.customLabel;
this.ringtone = stale.ringtone;
this.mutedUntil = stale.mutedUntil;
this.blocked = stale.blocked;
this.vibrate = stale.vibrate;
this.expireMessages = stale.expireMessages;
this.profileName = stale.profileName;
this.name = stale.name;
this.contactUri = stale.contactUri;
this.contactPhoto = stale.contactPhoto;
this.color = stale.color;
this.customLabel = stale.customLabel;
this.ringtone = stale.ringtone;
this.mutedUntil = stale.mutedUntil;
this.blocked = stale.blocked;
this.vibrate = stale.vibrate;
this.expireMessages = stale.expireMessages;
this.seenInviteReminder = stale.seenInviteReminder;
this.defaultSubscriptionId = stale.defaultSubscriptionId;
this.registered = stale.registered;
this.profileKey = stale.profileKey;
this.profileName = stale.profileName;
this.profileAvatar = stale.profileAvatar;
this.profileSharing = stale.profileSharing;
this.isSystemContact = stale.isSystemContact;
this.participants.clear();
this.participants.addAll(stale.participants);
}
if (details.isPresent()) {
this.name = details.get().name;
this.contactPhoto = details.get().avatar;
this.color = details.get().color;
this.ringtone = details.get().ringtone;
this.mutedUntil = details.get().mutedUntil;
this.blocked = details.get().blocked;
this.vibrate = details.get().vibrateState;
this.expireMessages = details.get().expireMessages;
this.profileName = details.get().profileName;
this.name = details.get().name;
this.contactPhoto = details.get().avatar;
this.color = details.get().color;
this.ringtone = details.get().ringtone;
this.mutedUntil = details.get().mutedUntil;
this.blocked = details.get().blocked;
this.vibrate = details.get().vibrateState;
this.expireMessages = details.get().expireMessages;
this.seenInviteReminder = details.get().seenInviteReminder;
this.defaultSubscriptionId = details.get().defaultSubscriptionId;
this.registered = details.get().registered;
this.profileKey = details.get().profileKey;
this.profileName = details.get().profileName;
this.profileAvatar = details.get().profileAvatar;
this.profileSharing = details.get().profileSharing;
this.isSystemContact = details.get().systemContact;
this.participants.clear();
this.participants.addAll(details.get().participants);
}
@ -132,25 +155,35 @@ public class Recipient implements RecipientModifiedListener {
public void onSuccess(RecipientDetails result) {
if (result != null) {
synchronized (Recipient.this) {
Recipient.this.name = result.name;
Recipient.this.contactUri = result.contactUri;
Recipient.this.contactPhoto = result.avatar;
Recipient.this.color = result.color;
Recipient.this.customLabel = result.customLabel;
Recipient.this.ringtone = result.ringtone;
Recipient.this.mutedUntil = result.mutedUntil;
Recipient.this.blocked = result.blocked;
Recipient.this.vibrate = result.vibrateState;
Recipient.this.expireMessages = result.expireMessages;
Recipient.this.profileName = result.profileName;
Recipient.this.name = result.name;
Recipient.this.contactUri = result.contactUri;
Recipient.this.contactPhoto = result.avatar;
Recipient.this.color = result.color;
Recipient.this.customLabel = result.customLabel;
Recipient.this.ringtone = result.ringtone;
Recipient.this.mutedUntil = result.mutedUntil;
Recipient.this.blocked = result.blocked;
Recipient.this.vibrate = result.vibrateState;
Recipient.this.expireMessages = result.expireMessages;
Recipient.this.seenInviteReminder = result.seenInviteReminder;
Recipient.this.defaultSubscriptionId = result.defaultSubscriptionId;
Recipient.this.registered = result.registered;
Recipient.this.profileKey = result.profileKey;
Recipient.this.profileName = result.profileName;
Recipient.this.profileAvatar = result.profileAvatar;
Recipient.this.profileSharing = result.profileSharing;
Recipient.this.profileName = result.profileName;
Recipient.this.isSystemContact = result.systemContact;
Recipient.this.participants.clear();
Recipient.this.participants.addAll(result.participants);
Recipient.this.resolving = false;
Recipient.this.resolving = false;
if (!listeners.isEmpty()) {
for (Recipient recipient : participants) recipient.addListener(Recipient.this);
}
Recipient.this.notifyAll();
}
notifyListeners();
@ -165,18 +198,25 @@ public class Recipient implements RecipientModifiedListener {
}
Recipient(@NonNull Address address, @NonNull RecipientDetails details) {
this.address = address;
this.contactUri = details.contactUri;
this.name = details.name;
this.contactPhoto = details.avatar;
this.color = details.color;
this.customLabel = details.customLabel;
this.ringtone = details.ringtone;
this.mutedUntil = details.mutedUntil;
this.blocked = details.blocked;
this.vibrate = details.vibrateState;
this.expireMessages = details.expireMessages;
this.profileName = details.profileName;
this.address = address;
this.contactUri = details.contactUri;
this.name = details.name;
this.contactPhoto = details.avatar;
this.color = details.color;
this.customLabel = details.customLabel;
this.ringtone = details.ringtone;
this.mutedUntil = details.mutedUntil;
this.blocked = details.blocked;
this.vibrate = details.vibrateState;
this.expireMessages = details.expireMessages;
this.seenInviteReminder = details.seenInviteReminder;
this.defaultSubscriptionId = details.defaultSubscriptionId;
this.registered = details.registered;
this.profileKey = details.profileKey;
this.profileName = details.profileName;
this.profileAvatar = details.profileAvatar;
this.profileSharing = details.profileSharing;
this.isSystemContact = details.systemContact;
this.participants.addAll(details.participants);
this.resolving = false;
}
@ -222,10 +262,54 @@ public class Recipient implements RecipientModifiedListener {
return customLabel;
}
public @Nullable String getProfileName() {
public synchronized Optional<Integer> getDefaultSubscriptionId() {
return defaultSubscriptionId;
}
public void setDefaultSubscriptionId(Optional<Integer> defaultSubscriptionId) {
synchronized (this) {
this.defaultSubscriptionId = defaultSubscriptionId;
}
notifyListeners();
}
public synchronized @Nullable String getProfileName() {
return profileName;
}
public void setProfileName(@Nullable String profileName) {
synchronized (this) {
this.profileName = profileName;
}
notifyListeners();
}
public synchronized @Nullable String getProfileAvatar() {
return profileAvatar;
}
public void setProfileAvatar(@Nullable String profileAvatar) {
synchronized (this) {
this.profileAvatar = profileAvatar;
}
notifyListeners();
}
public synchronized boolean isProfileSharing() {
return profileSharing;
}
public void setProfileSharing(boolean value) {
synchronized (this) {
this.profileSharing = value;
}
notifyListeners();
}
public boolean isGroupRecipient() {
return address.isGroup();
}
@ -265,6 +349,14 @@ public class Recipient implements RecipientModifiedListener {
return contactPhoto;
}
public void setContactPhoto(@NonNull ContactPhoto contactPhoto) {
synchronized (this) {
this.contactPhoto = contactPhoto;
}
notifyListeners();
}
public synchronized @Nullable Uri getRingtone() {
return ringtone;
}
@ -325,6 +417,60 @@ public class Recipient implements RecipientModifiedListener {
notifyListeners();
}
public synchronized boolean hasSeenInviteReminder() {
return seenInviteReminder;
}
public void setHasSeenInviteReminder(boolean value) {
synchronized (this) {
this.seenInviteReminder = value;
}
notifyListeners();
}
public synchronized RegisteredState getRegistered() {
return registered;
}
public void setRegistered(@NonNull RegisteredState value) {
synchronized (this) {
this.registered = value;
}
notifyListeners();
}
public synchronized @Nullable byte[] getProfileKey() {
return profileKey;
}
public void setProfileKey(@Nullable byte[] profileKey) {
synchronized (this) {
this.profileKey = profileKey;
}
notifyListeners();
}
public synchronized boolean isSystemContact() {
return isSystemContact;
}
public void setSystemDisplayName(@Nullable String displayName) {
synchronized (this) {
if (displayName == null) this.name = profileName;
else this.name = displayName;
}
notifyListeners();
}
public synchronized Recipient resolve() {
while (resolving) Util.wait(this, 0);
return this;
}
@Override
public boolean equals(Object o) {
@ -369,4 +515,5 @@ public class Recipient implements RecipientModifiedListener {
return resolving;
}
}

View File

@ -33,7 +33,9 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
import org.thoughtcrime.securesms.util.LRUCache;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
@ -187,38 +189,52 @@ class RecipientProvider {
}
static class RecipientDetails {
@Nullable public final String name;
@Nullable public final String customLabel;
@NonNull public final ContactPhoto avatar;
@Nullable public final Uri contactUri;
@Nullable public final MaterialColor color;
@Nullable public final Uri ringtone;
public final long mutedUntil;
@Nullable public final VibrateState vibrateState;
public final boolean blocked;
public final int expireMessages;
@NonNull public final List<Recipient> participants;
@Nullable public final String profileName;
@Nullable public final String name;
@Nullable public final String customLabel;
@NonNull public final ContactPhoto avatar;
@Nullable public final Uri contactUri;
@Nullable public final MaterialColor color;
@Nullable public final Uri ringtone;
public final long mutedUntil;
@Nullable public final VibrateState vibrateState;
public final boolean blocked;
public final int expireMessages;
@NonNull public final List<Recipient> participants;
@Nullable public final String profileName;
public final boolean seenInviteReminder;
public final Optional<Integer> defaultSubscriptionId;
@NonNull public final RegisteredState registered;
@Nullable public final byte[] profileKey;
@Nullable public final String profileAvatar;
public final boolean profileSharing;
public final boolean systemContact;
public RecipientDetails(@Nullable String name, @Nullable String customLabel,
@Nullable Uri contactUri, @NonNull ContactPhoto avatar,
@Nullable RecipientSettings settings,
@Nullable List<Recipient> participants)
{
this.customLabel = customLabel;
this.avatar = avatar;
this.contactUri = contactUri;
this.color = settings != null ? settings.getColor() : null;
this.ringtone = settings != null ? settings.getRingtone() : null;
this.mutedUntil = settings != null ? settings.getMuteUntil() : 0;
this.vibrateState = settings != null ? settings.getVibrateState() : null;
this.blocked = settings != null && settings.isBlocked();
this.expireMessages = settings != null ? settings.getExpireMessages() : 0;
this.participants = participants == null ? new LinkedList<Recipient>() : participants;
this.profileName = settings != null ? settings.getProfileName() : null;
this.customLabel = customLabel;
this.avatar = avatar;
this.contactUri = contactUri;
this.color = settings != null ? settings.getColor() : null;
this.ringtone = settings != null ? settings.getRingtone() : null;
this.mutedUntil = settings != null ? settings.getMuteUntil() : 0;
this.vibrateState = settings != null ? settings.getVibrateState() : null;
this.blocked = settings != null && settings.isBlocked();
this.expireMessages = settings != null ? settings.getExpireMessages() : 0;
this.participants = participants == null ? new LinkedList<Recipient>() : participants;
this.profileName = settings != null ? settings.getProfileName() : null;
this.seenInviteReminder = settings != null && settings.hasSeenInviteReminder();
this.defaultSubscriptionId = settings != null ? settings.getDefaultSubscriptionId() : Optional.absent();
this.registered = settings != null ? settings.getRegistered() : RegisteredState.UNKNOWN;
this.profileKey = settings != null ? settings.getProfileKey() : null;
this.profileAvatar = settings != null ? settings.getProfileAvatar() : null;
this.profileSharing = settings != null && settings.isProfileSharing();
this.systemContact = settings != null && !TextUtils.isEmpty(settings.getSystemDisplayName());
if (name == null && settings != null) this.name = settings.getSystemDisplayName();
else this.name = name;
else this.name = name;
}
}

View File

@ -51,11 +51,10 @@ public class QuickResponseService extends MasterSecretIntentService {
number = URLDecoder.decode(number);
}
Address address = Address.fromExternal(this, number);
Recipient recipient = Recipient.from(this, address, false);
Optional<RecipientSettings> settings = DatabaseFactory.getRecipientDatabase(this).getRecipientSettings(recipient.getAddress());
int subscriptionId = settings.isPresent() ? settings.get().getDefaultSubscriptionId().or(-1) : -1;
long expiresIn = settings.isPresent() ? settings.get().getExpireMessages() * 1000 : 0;
Address address = Address.fromExternal(this, number);
Recipient recipient = Recipient.from(this, address, false);
int subscriptionId = recipient.getDefaultSubscriptionId().or(-1);
long expiresIn = recipient.getExpireMessages() * 1000;
if (!TextUtils.isEmpty(content)) {
MessageSender.send(this, masterSecret, new OutgoingTextMessage(recipient, content, expiresIn, subscriptionId), -1, false, null);

View File

@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
@ -50,7 +49,6 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
import java.io.IOException;
import java.util.LinkedList;
public class MessageSender {
@ -232,7 +230,7 @@ public class MessageSender {
return false;
}
return isPushDestination(context, recipient.getAddress());
return isPushDestination(context, recipient);
}
private static boolean isPushMediaSend(Context context, Recipient recipient) {
@ -244,7 +242,7 @@ public class MessageSender {
return false;
}
return isPushDestination(context, recipient.getAddress());
return isPushDestination(context, recipient);
}
private static boolean isGroupPushSend(Recipient recipient) {
@ -264,22 +262,21 @@ public class MessageSender {
return Util.isOwnNumber(context, recipient.getAddress());
}
private static boolean isPushDestination(Context context, Address destination) {
RecipientDatabase recipientsDatabase = DatabaseFactory.getRecipientDatabase(context);
Optional<RecipientSettings> recipientPreferences = recipientsDatabase.getRecipientSettings(destination);
if (recipientPreferences.isPresent()) {
return recipientPreferences.get().isRegistered();
private static boolean isPushDestination(Context context, Recipient destination) {
if (destination.resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
return true;
} else if (destination.resolve().getRegistered() == RecipientDatabase.RegisteredState.NOT_REGISTERED) {
return false;
} else {
try {
SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context);
Optional<ContactTokenDetails> registeredUser = accountManager.getContact(destination.serialize());
Optional<ContactTokenDetails> registeredUser = accountManager.getContact(destination.getAddress().serialize());
if (!registeredUser.isPresent()) {
recipientsDatabase.setRegistered(new LinkedList<>(), Util.asList(destination));
DatabaseFactory.getRecipientDatabase(context).setRegistered(destination, RecipientDatabase.RegisteredState.NOT_REGISTERED);
return false;
} else {
recipientsDatabase.setRegistered(Util.asList(destination), new LinkedList<>());
DatabaseFactory.getRecipientDatabase(context).setRegistered(destination, RecipientDatabase.RegisteredState.REGISTERED);
return true;
}
} catch (IOException e1) {

View File

@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.push.AccountManagerFactory;
@ -44,10 +45,6 @@ import java.util.Set;
public class DirectoryHelper {
public enum Capability {
UNKNOWN, SUPPORTED, UNSUPPORTED
}
private static final String TAG = DirectoryHelper.class.getSimpleName();
public static void refreshDirectory(@NonNull Context context, @Nullable MasterSecret masterSecret)
@ -75,33 +72,38 @@ public class DirectoryHelper {
return new RefreshResult(new LinkedList<>(), false);
}
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
Set<Address> eligibleContactNumbers = recipientDatabase.getAllRecipients();
eligibleContactNumbers.addAll(ContactAccessor.getInstance().getAllContactsWithNumbers(context));
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
Stream<String> eligibleRecipientDatabaseContactNumbers = Stream.of(recipientDatabase.getAllRecipients()).map(recipient -> recipient.getAddress().serialize());
Stream<String> eligibleSystemDatabaseContactNumbers = Stream.of(ContactAccessor.getInstance().getAllContactsWithNumbers(context)).map(Address::serialize);
Set<String> eligibleContactNumbers = Stream.concat(eligibleRecipientDatabaseContactNumbers, eligibleSystemDatabaseContactNumbers).collect(Collectors.toSet());
Set<String> serializedAddress = Stream.of(eligibleContactNumbers).map(Address::serialize).collect(Collectors.toSet());
List<ContactTokenDetails> activeTokens = accountManager.getContacts(serializedAddress);
List<ContactTokenDetails> activeTokens = accountManager.getContacts(eligibleContactNumbers);
if (activeTokens != null) {
List<Address> activeAddresses = new LinkedList<>();
Set<Address> inactiveAddresses = new HashSet<>(eligibleContactNumbers);
List<Recipient> activeRecipients = new LinkedList<>();
List<Recipient> inactiveRecipients = new LinkedList<>();
Set<String> inactiveContactNumbers = new HashSet<>(eligibleContactNumbers);
for (ContactTokenDetails activeToken : activeTokens) {
Address activeAddress = Address.fromSerialized(activeToken.getNumber());
activeAddresses.add(activeAddress);
inactiveAddresses.remove(activeAddress);
activeRecipients.add(Recipient.from(context, Address.fromSerialized(activeToken.getNumber()), true));
inactiveContactNumbers.remove(activeToken.getNumber());
}
recipientDatabase.setRegistered(activeAddresses, new LinkedList<>(inactiveAddresses));
return updateContactsDatabase(context, activeAddresses, true);
for (String inactiveContactNumber : inactiveContactNumbers) {
inactiveRecipients.add(Recipient.from(context, Address.fromSerialized(inactiveContactNumber), true));
}
recipientDatabase.setRegistered(activeRecipients, inactiveRecipients);
return updateContactsDatabase(context, Stream.of(activeRecipients).map(Recipient::getAddress).toList(), true);
}
return new RefreshResult(new LinkedList<>(), false);
}
public static Capability refreshDirectoryFor(@NonNull Context context,
@Nullable MasterSecret masterSecret,
@NonNull Recipient recipient)
public static RegisteredState refreshDirectoryFor(@NonNull Context context,
@Nullable MasterSecret masterSecret,
@NonNull Recipient recipient)
throws IOException
{
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
@ -110,7 +112,7 @@ public class DirectoryHelper {
Optional<ContactTokenDetails> details = accountManager.getContact(number);
if (details.isPresent()) {
recipientDatabase.setRegistered(Util.asList(recipient.getAddress()), new LinkedList<>());
recipientDatabase.setRegistered(recipient, RegisteredState.REGISTERED);
RefreshResult result = updateContactsDatabase(context, Util.asList(recipient.getAddress()), false);
@ -122,38 +124,13 @@ public class DirectoryHelper {
notifyNewUsers(context, masterSecret, result.getNewUsers());
}
return Capability.SUPPORTED;
return RegisteredState.REGISTERED;
} else {
recipientDatabase.setRegistered(new LinkedList<>(), Util.asList(recipient.getAddress()));
return Capability.UNSUPPORTED;
recipientDatabase.setRegistered(recipient, RegisteredState.NOT_REGISTERED);
return RegisteredState.NOT_REGISTERED;
}
}
public static @NonNull Capability getUserCapabilities(@NonNull Context context, @Nullable Recipient recipient) {
if (recipient == null) {
return Capability.UNSUPPORTED;
}
if (!TextSecurePreferences.isPushRegistered(context)) {
return Capability.UNSUPPORTED;
}
if (recipient.isMmsGroupRecipient()) {
return Capability.UNSUPPORTED;
}
if (recipient.isPushGroupRecipient()) {
return Capability.SUPPORTED;
}
final RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
final Optional<RecipientSettings> recipientSettings = recipientDatabase.getRecipientSettings(recipient.getAddress());
if (recipientSettings.isPresent() && recipientSettings.get().isRegistered()) return Capability.SUPPORTED;
else if (recipientSettings.isPresent()) return Capability.UNSUPPORTED;
else return Capability.UNKNOWN;
}
private static @NonNull RefreshResult updateContactsDatabase(@NonNull Context context, @NonNull List<Address> activeAddresses, boolean removeMissing) {
Optional<AccountHolder> account = getOrCreateAccount(context);
@ -162,7 +139,7 @@ public class DirectoryHelper {
List<Address> newUsers = DatabaseFactory.getContactsDatabase(context)
.setRegisteredUsers(account.get().getAccount(), activeAddresses, removeMissing);
Cursor cursor = ContactAccessor.getInstance().getAllSystemContacts(context);
Cursor cursor = ContactAccessor.getInstance().getAllSystemContacts(context);
RecipientDatabase.BulkOperationsHandle handle = DatabaseFactory.getRecipientDatabase(context).resetAllDisplayNames();
try {
@ -170,10 +147,11 @@ public class DirectoryHelper {
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));
Address address = Address.fromExternal(context, number);
Recipient recipient = Recipient.from(context, address, true);
String displayName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
handle.setDisplayName(address, displayName);
handle.setDisplayName(recipient, displayName);
}
}
} finally {