Migrated to locally-assigned RecipientId's.

Oh boy.
This commit is contained in:
Greyson Parrelli
2019-08-07 14:22:51 -04:00
parent 233cc7ecce
commit 0e2d52026e
168 changed files with 3927 additions and 3110 deletions

View File

@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -32,40 +33,53 @@ public class RecipientDatabase extends Database {
private static final String TAG = RecipientDatabase.class.getSimpleName();
static final String TABLE_NAME = "recipient_preferences";
private static final String ID = "_id";
static final String ADDRESS = "recipient_ids";
private static final String BLOCK = "block";
private static final String NOTIFICATION = "notification";
private static final String VIBRATE = "vibrate";
static final String TABLE_NAME = "recipient";
public static final String ID = "_id";
private static final String UUID = "uuid";
static final String PHONE = "phone";
static final String EMAIL = "email";
static final String GROUP_ID = "group_id";
private static final String BLOCKED = "blocked";
private static final String MESSAGE_RINGTONE = "message_ringtone";
private static final String MESSAGE_VIBRATE = "message_vibrate";
private static final String CALL_RINGTONE = "call_ringtone";
private static final String CALL_VIBRATE = "call_vibrate";
private static final String NOTIFICATION_CHANNEL = "notification_channel";
private static final String MUTE_UNTIL = "mute_until";
private static final String COLOR = "color";
private static final String SEEN_INVITE_REMINDER = "seen_invite_reminder";
private static final String DEFAULT_SUBSCRIPTION_ID = "default_subscription_id";
private static final String EXPIRE_MESSAGES = "expire_messages";
private static final String MESSAGE_EXPIRATION_TIME = "message_expiration_time";
static final String REGISTERED = "registered";
private static final String PROFILE_KEY = "profile_key";
private static final String SYSTEM_DISPLAY_NAME = "system_display_name";
private static final String SYSTEM_PHOTO_URI = "system_contact_photo";
private static final String SYSTEM_PHOTO_URI = "system_photo_uri";
private static final String SYSTEM_PHONE_LABEL = "system_phone_label";
private static final String SYSTEM_CONTACT_URI = "system_contact_uri";
private static final String PROFILE_KEY = "profile_key";
private static final String SIGNAL_PROFILE_NAME = "signal_profile_name";
private static final String SIGNAL_PROFILE_AVATAR = "signal_profile_avatar";
private static final String PROFILE_SHARING = "profile_sharing_approval";
private static final String CALL_RINGTONE = "call_ringtone";
private static final String CALL_VIBRATE = "call_vibrate";
private static final String NOTIFICATION_CHANNEL = "notification_channel";
private static final String PROFILE_SHARING = "profile_sharing";
private static final String UNIDENTIFIED_ACCESS_MODE = "unidentified_access_mode";
private static final String FORCE_SMS_SELECTION = "force_sms_selection";
private static final String[] RECIPIENT_PROJECTION = new String[] {
BLOCK, NOTIFICATION, CALL_RINGTONE, VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED,
UUID, PHONE, EMAIL, GROUP_ID,
BLOCKED, MESSAGE_RINGTONE, CALL_RINGTONE, MESSAGE_VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, MESSAGE_EXPIRATION_TIME, REGISTERED,
PROFILE_KEY, SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_CONTACT_URI,
SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL,
UNIDENTIFIED_ACCESS_MODE,
FORCE_SMS_SELECTION,
};
private static final String[] ID_PROJECTION = new String[] { ID };
private static Address addressFromCursor(Cursor cursor) {
String phone = cursor.getString(cursor.getColumnIndexOrThrow(PHONE));
String email = cursor.getString(cursor.getColumnIndexOrThrow(EMAIL));
String groupId = cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
return phone != null ? Address.fromSerialized(phone) : email != null ? Address.fromSerialized(email) : Address.fromSerialized(groupId);
}
static final List<String> TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION)
.map(columnName -> TABLE_NAME + "." + columnName)
.toList();
@@ -125,40 +139,105 @@ public class RecipientDatabase extends Database {
}
public static final String CREATE_TABLE =
"CREATE TABLE " + TABLE_NAME +
" (" + ID + " INTEGER PRIMARY KEY, " +
ADDRESS + " TEXT UNIQUE, " +
BLOCK + " INTEGER DEFAULT 0," +
NOTIFICATION + " TEXT DEFAULT NULL, " +
VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
MUTE_UNTIL + " INTEGER DEFAULT 0, " +
COLOR + " TEXT DEFAULT NULL, " +
SEEN_INVITE_REMINDER + " INTEGER DEFAULT 0, " +
DEFAULT_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
EXPIRE_MESSAGES + " INTEGER DEFAULT 0, " +
REGISTERED + " INTEGER DEFAULT 0, " +
SYSTEM_DISPLAY_NAME + " TEXT DEFAULT NULL, " +
SYSTEM_PHOTO_URI + " TEXT DEFAULT NULL, " +
SYSTEM_PHONE_LABEL + " TEXT DEFAULT NULL, " +
SYSTEM_CONTACT_URI + " TEXT DEFAULT NULL, " +
PROFILE_KEY + " TEXT DEFAULT NULL, " +
SIGNAL_PROFILE_NAME + " TEXT DEFAULT NULL, " +
SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL, " +
PROFILE_SHARING + " INTEGER DEFAULT 0, " +
CALL_RINGTONE + " TEXT DEFAULT NULL, " +
CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
NOTIFICATION_CHANNEL + " TEXT DEFAULT NULL, " +
UNIDENTIFIED_ACCESS_MODE + " INTEGER DEFAULT 0, " +
FORCE_SMS_SELECTION + " INTEGER DEFAULT 0);";
"CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
UUID + " TEXT UNIQUE DEFAULT NULL, " +
PHONE + " TEXT UNIQUE DEFAULT NULL, " +
EMAIL + " TEXT UNIQUE DEFAULT NULL, " +
GROUP_ID + " TEXT UNIQUE DEFAULT NULL, " +
BLOCKED + " INTEGER DEFAULT 0," +
MESSAGE_RINGTONE + " TEXT DEFAULT NULL, " +
MESSAGE_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
CALL_RINGTONE + " TEXT DEFAULT NULL, " +
CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
NOTIFICATION_CHANNEL + " TEXT DEFAULT NULL, " +
MUTE_UNTIL + " INTEGER DEFAULT 0, " +
COLOR + " TEXT DEFAULT NULL, " +
SEEN_INVITE_REMINDER + " INTEGER DEFAULT 0, " +
DEFAULT_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
MESSAGE_EXPIRATION_TIME + " INTEGER DEFAULT 0, " +
REGISTERED + " INTEGER DEFAULT " + RegisteredState.UNKNOWN.getId() + ", " +
SYSTEM_DISPLAY_NAME + " TEXT DEFAULT NULL, " +
SYSTEM_PHOTO_URI + " TEXT DEFAULT NULL, " +
SYSTEM_PHONE_LABEL + " TEXT DEFAULT NULL, " +
SYSTEM_CONTACT_URI + " TEXT DEFAULT NULL, " +
PROFILE_KEY + " TEXT DEFAULT NULL, " +
SIGNAL_PROFILE_NAME + " TEXT DEFAULT NULL, " +
SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL, " +
PROFILE_SHARING + " INTEGER DEFAULT 0, " +
UNIDENTIFIED_ACCESS_MODE + " INTEGER DEFAULT 0, " +
FORCE_SMS_SELECTION + " INTEGER DEFAULT 0);";
public RecipientDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
}
public RecipientId getOrInsertFromE164(@NonNull String e164) {
if (TextUtils.isEmpty(e164)) {
throw new AssertionError("Phone number cannot be empty.");
}
SQLiteDatabase db = databaseHelper.getWritableDatabase();
String query = PHONE + " = ?";
String[] args = new String[] { e164 };
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, query, args, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
return RecipientId.from(cursor.getLong(0));
} else {
ContentValues values = new ContentValues();
values.put(PHONE, e164);
long id = db.insert(TABLE_NAME, null, values);
return RecipientId.from(id);
}
}
}
public RecipientId getOrInsertFromEmail(@NonNull String email) {
if (TextUtils.isEmpty(email)) {
throw new AssertionError("Email cannot be empty.");
}
SQLiteDatabase db = databaseHelper.getWritableDatabase();
String query = EMAIL + " = ?";
String[] args = new String[] { email };
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, query, args, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
return RecipientId.from(cursor.getLong(0));
} else {
ContentValues values = new ContentValues();
values.put(EMAIL, email);
long id = db.insert(TABLE_NAME, null, values);
return RecipientId.from(id);
}
}
}
public RecipientId getOrInsertFromGroupId(@NonNull String groupId) {
if (TextUtils.isEmpty(groupId)) {
throw new AssertionError("GroupId cannot be empty.");
}
SQLiteDatabase db = databaseHelper.getWritableDatabase();
String query = GROUP_ID + " = ?";
String[] args = new String[] { groupId };
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, query, args, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
return RecipientId.from(cursor.getLong(0));
} else {
ContentValues values = new ContentValues();
values.put(GROUP_ID, groupId);
long id = db.insert(TABLE_NAME, null, values);
return RecipientId.from(id);
}
}
}
public Cursor getBlocked() {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
return database.query(TABLE_NAME, new String[] {ID, ADDRESS}, BLOCK + " = 1",
return database.query(TABLE_NAME, ID_PROJECTION, BLOCKED + " = 1",
null, null, null, null, null);
}
@@ -168,40 +247,40 @@ public class RecipientDatabase extends Database {
public RecipientReader getRecipientsWithNotificationChannels() {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS}, NOTIFICATION_CHANNEL + " NOT NULL",
Cursor cursor = database.query(TABLE_NAME, ID_PROJECTION, NOTIFICATION_CHANNEL + " NOT NULL",
null, null, null, null, null);
return new RecipientReader(context, cursor);
}
public Optional<RecipientSettings> getRecipientSettings(@NonNull Address address) {
public @NonNull RecipientSettings getRecipientSettings(@NonNull RecipientId id) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
Cursor cursor = null;
try {
cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null);
String query = ID + " = ?";
String[] args = new String[] { id.serialize() };
try (Cursor cursor = database.query(TABLE_NAME, null, query, args, null, null, null)) {
if (cursor != null && cursor.moveToNext()) {
return getRecipientSettings(cursor);
} else {
// TODO: Maybe not make this an error?
throw new AssertionError("Couldn't find recipient!");
}
return Optional.absent();
} finally {
if (cursor != null) cursor.close();
}
}
Optional<RecipientSettings> getRecipientSettings(@NonNull Cursor cursor) {
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION));
@NonNull RecipientSettings getRecipientSettings(@NonNull Cursor cursor) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
Address address = addressFromCursor(cursor);
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCKED)) == 1;
String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(MESSAGE_RINGTONE));
String callRingtone = cursor.getString(cursor.getColumnIndexOrThrow(CALL_RINGTONE));
int messageVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE));
int messageVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(MESSAGE_VIBRATE));
int callVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(CALL_VIBRATE));
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
String serializedColor = cursor.getString(cursor.getColumnIndexOrThrow(COLOR));
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));
int expireMessages = cursor.getInt(cursor.getColumnIndexOrThrow(MESSAGE_EXPIRATION_TIME));
int registeredState = cursor.getInt(cursor.getColumnIndexOrThrow(REGISTERED));
String profileKeyString = cursor.getString(cursor.getColumnIndexOrThrow(PROFILE_KEY));
String systemDisplayName = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME));
@@ -234,18 +313,18 @@ public class RecipientDatabase extends Database {
}
}
return Optional.of(new RecipientSettings(blocked, muteUntil,
VibrateState.fromId(messageVibrateState),
VibrateState.fromId(callVibrateState),
Util.uri(messageRingtone), Util.uri(callRingtone),
color, seenInviteReminder,
defaultSubscriptionId, expireMessages,
RegisteredState.fromId(registeredState),
profileKey, systemDisplayName, systemContactPhoto,
systemPhoneLabel, systemContactUri,
signalProfileName, signalProfileAvatar, profileSharing,
notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
forceSmsSelection));
return new RecipientSettings(RecipientId.from(id), address, blocked, muteUntil,
VibrateState.fromId(messageVibrateState),
VibrateState.fromId(callVibrateState),
Util.uri(messageRingtone), Util.uri(callRingtone),
color, seenInviteReminder,
defaultSubscriptionId, expireMessages,
RegisteredState.fromId(registeredState),
profileKey, systemDisplayName, systemContactPhoto,
systemPhoneLabel, systemContactUri,
signalProfileName, signalProfileAvatar, profileSharing,
notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
forceSmsSelection);
}
public BulkOperationsHandle resetAllSystemContactInfo() {
@@ -263,187 +342,185 @@ public class RecipientDatabase extends Database {
return new BulkOperationsHandle(database);
}
public void setColor(@NonNull Recipient recipient, @NonNull MaterialColor color) {
public void setColor(@NonNull RecipientId id, @NonNull MaterialColor color) {
ContentValues values = new ContentValues();
values.put(COLOR, color.serialize());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setColor(color);
update(id, values);
Recipient.live(id).refresh();
}
public void setDefaultSubscriptionId(@NonNull Recipient recipient, int defaultSubscriptionId) {
public void setDefaultSubscriptionId(@NonNull RecipientId id, int defaultSubscriptionId) {
ContentValues values = new ContentValues();
values.put(DEFAULT_SUBSCRIPTION_ID, defaultSubscriptionId);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setDefaultSubscriptionId(Optional.of(defaultSubscriptionId));
update(id, values);
Recipient.live(id).refresh();
}
public void setForceSmsSelection(@NonNull Recipient recipient, boolean forceSmsSelection) {
public void setForceSmsSelection(@NonNull RecipientId id, boolean forceSmsSelection) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(FORCE_SMS_SELECTION, forceSmsSelection ? 1 : 0);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.resolve().setForceSmsSelection(forceSmsSelection);
update(id, contentValues);
Recipient.live(id).refresh();
}
public void setBlocked(@NonNull Recipient recipient, boolean blocked) {
public void setBlocked(@NonNull RecipientId id, boolean blocked) {
ContentValues values = new ContentValues();
values.put(BLOCK, blocked ? 1 : 0);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setBlocked(blocked);
values.put(BLOCKED, blocked ? 1 : 0);
update(id, values);
Recipient.live(id).refresh();
}
public void setMessageRingtone(@NonNull Recipient recipient, @Nullable Uri notification) {
public void setMessageRingtone(@NonNull RecipientId id, @Nullable Uri notification) {
ContentValues values = new ContentValues();
values.put(NOTIFICATION, notification == null ? null : notification.toString());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setMessageRingtone(notification);
values.put(MESSAGE_RINGTONE, notification == null ? null : notification.toString());
update(id, values);
Recipient.live(id).refresh();
}
public void setCallRingtone(@NonNull Recipient recipient, @Nullable Uri ringtone) {
public void setCallRingtone(@NonNull RecipientId id, @Nullable Uri ringtone) {
ContentValues values = new ContentValues();
values.put(CALL_RINGTONE, ringtone == null ? null : ringtone.toString());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setCallRingtone(ringtone);
update(id, values);
Recipient.live(id).refresh();
}
public void setMessageVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) {
public void setMessageVibrate(@NonNull RecipientId id, @NonNull VibrateState enabled) {
ContentValues values = new ContentValues();
values.put(VIBRATE, enabled.getId());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setMessageVibrate(enabled);
values.put(MESSAGE_VIBRATE, enabled.getId());
update(id, values);
Recipient.live(id).refresh();
}
public void setCallVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) {
public void setCallVibrate(@NonNull RecipientId id, @NonNull VibrateState enabled) {
ContentValues values = new ContentValues();
values.put(CALL_VIBRATE, enabled.getId());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setCallVibrate(enabled);
update(id, values);
Recipient.live(id).refresh();
}
public void setMuted(@NonNull Recipient recipient, long until) {
public void setMuted(@NonNull RecipientId id, long until) {
ContentValues values = new ContentValues();
values.put(MUTE_UNTIL, until);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setMuted(until);
update(id, values);
Recipient.live(id).refresh();
}
public void setSeenInviteReminder(@NonNull Recipient recipient, @SuppressWarnings("SameParameterValue") boolean seen) {
public void setSeenInviteReminder(@NonNull RecipientId id, @SuppressWarnings("SameParameterValue") boolean seen) {
ContentValues values = new ContentValues(1);
values.put(SEEN_INVITE_REMINDER, seen ? 1 : 0);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setHasSeenInviteReminder(seen);
update(id, values);
Recipient.live(id).refresh();
}
public void setExpireMessages(@NonNull Recipient recipient, int expiration) {
recipient.setExpireMessages(expiration);
public void setExpireMessages(@NonNull RecipientId id, int expiration) {
ContentValues values = new ContentValues(1);
values.put(EXPIRE_MESSAGES, expiration);
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setExpireMessages(expiration);
values.put(MESSAGE_EXPIRATION_TIME, expiration);
update(id, values);
Recipient.live(id).refresh();
}
public void setUnidentifiedAccessMode(@NonNull Recipient recipient, @NonNull UnidentifiedAccessMode unidentifiedAccessMode) {
public void setUnidentifiedAccessMode(@NonNull RecipientId id, @NonNull UnidentifiedAccessMode unidentifiedAccessMode) {
ContentValues values = new ContentValues(1);
values.put(UNIDENTIFIED_ACCESS_MODE, unidentifiedAccessMode.getMode());
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setUnidentifiedAccessMode(unidentifiedAccessMode);
update(id, values);
Recipient.live(id).refresh();
}
public void setProfileKey(@NonNull Recipient recipient, @Nullable byte[] profileKey) {
public void setProfileKey(@NonNull RecipientId id, @Nullable byte[] profileKey) {
ContentValues values = new ContentValues(1);
values.put(PROFILE_KEY, profileKey == null ? null : Base64.encodeBytes(profileKey));
updateOrInsert(recipient.getAddress(), values);
recipient.resolve().setProfileKey(profileKey);
update(id, values);
Recipient.live(id).refresh();
}
public void setProfileName(@NonNull Recipient recipient, @Nullable String profileName) {
public void setProfileName(@NonNull RecipientId id, @Nullable String profileName) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(SIGNAL_PROFILE_NAME, profileName);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.resolve().setProfileName(profileName);
update(id, contentValues);
Recipient.live(id).refresh();
}
public void setProfileAvatar(@NonNull Recipient recipient, @Nullable String profileAvatar) {
public void setProfileAvatar(@NonNull RecipientId id, @Nullable String profileAvatar) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(SIGNAL_PROFILE_AVATAR, profileAvatar);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.resolve().setProfileAvatar(profileAvatar);
update(id, contentValues);
Recipient.live(id).refresh();
}
public void setProfileSharing(@NonNull Recipient recipient, @SuppressWarnings("SameParameterValue") boolean enabled) {
public void setProfileSharing(@NonNull RecipientId id, @SuppressWarnings("SameParameterValue") boolean enabled) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(PROFILE_SHARING, enabled ? 1 : 0);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.setProfileSharing(enabled);
update(id, contentValues);
Recipient.live(id).refresh();
}
public void setNotificationChannel(@NonNull Recipient recipient, @Nullable String notificationChannel) {
public void setNotificationChannel(@NonNull RecipientId id, @Nullable String notificationChannel) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(NOTIFICATION_CHANNEL, notificationChannel);
updateOrInsert(recipient.getAddress(), contentValues);
recipient.setNotificationChannel(notificationChannel);
update(id, contentValues);
Recipient.live(id).refresh();
}
public Set<Address> getAllAddresses() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Set<Address> results = new HashSet<>();
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, null, null, null, null, null)) {
try (Cursor cursor = db.query(TABLE_NAME, new String[] { ID, UUID, PHONE, EMAIL, GROUP_ID }, null, null, null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
results.add(Address.fromExternal(context, cursor.getString(0)));
results.add(addressFromCursor(cursor));
}
}
return results;
}
public void setRegistered(@NonNull Recipient recipient, RegisteredState registeredState) {
public void setRegistered(@NonNull RecipientId id, RegisteredState registeredState) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(REGISTERED, registeredState.getId());
updateOrInsert(recipient.getAddress(), contentValues);
recipient.setRegistered(registeredState);
update(id, contentValues);
Recipient.live(id).refresh();
}
public void setRegistered(@NonNull List<Address> activeAddresses,
@NonNull List<Address> inactiveAddresses)
public void setRegistered(@NonNull List<RecipientId> activeIds,
@NonNull List<RecipientId> inactiveIds)
{
for (Address activeAddress : activeAddresses) {
for (RecipientId activeId : activeIds) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
updateOrInsert(activeAddress, contentValues);
Recipient.applyCached(activeAddress, recipient -> recipient.setRegistered(RegisteredState.REGISTERED));
update(activeId, contentValues);
Recipient.live(activeId).refresh();
}
for (Address inactiveAddress : inactiveAddresses) {
for (RecipientId inactiveId : inactiveIds) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(REGISTERED, RegisteredState.NOT_REGISTERED.getId());
updateOrInsert(inactiveAddress, contentValues);
Recipient.applyCached(inactiveAddress, recipient -> recipient.setRegistered(RegisteredState.NOT_REGISTERED));
update(inactiveId, contentValues);
Recipient.live(inactiveId).refresh();
}
}
public List<Address> getRegistered() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
List<Address> results = new LinkedList<>();
public List<RecipientId> getRegistered() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
List<RecipientId> results = new LinkedList<>();
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, REGISTERED + " = ?", new String[] {"1"}, null, null, null)) {
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, REGISTERED + " = ?", new String[] {"1"}, null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
results.add(Address.fromSerialized(cursor.getString(0)));
results.add(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID))));
}
}
return results;
}
public List<Address> getSystemContacts() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
List<Address> results = new LinkedList<>();
public List<RecipientId> getSystemContacts() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
List<RecipientId> results = new LinkedList<>();
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
try (Cursor cursor = db.query(TABLE_NAME, ID_PROJECTION, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
results.add(Address.fromSerialized(cursor.getString(0)));
results.add(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID))));
}
}
@@ -451,93 +528,61 @@ public class RecipientDatabase extends Database {
}
public void updateSystemContactColors(@NonNull ColorUpdater updater) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Map<Address, MaterialColor> updates = new HashMap<>();
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Map<RecipientId, MaterialColor> updates = new HashMap<>();
db.beginTransaction();
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS, COLOR, SYSTEM_DISPLAY_NAME}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ID, COLOR, SYSTEM_DISPLAY_NAME}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
MaterialColor newColor = updater.update(cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME)),
cursor.getString(cursor.getColumnIndexOrThrow(COLOR)));
ContentValues contentValues = new ContentValues(1);
contentValues.put(COLOR, newColor.serialize());
db.update(TABLE_NAME, contentValues, ADDRESS + " = ?", new String[]{address.serialize()});
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] { String.valueOf(id) });
updates.put(address, newColor);
updates.put(RecipientId.from(id), newColor);
}
} finally {
db.setTransactionSuccessful();
db.endTransaction();
Stream.of(updates.entrySet()).forEach(entry -> {
Recipient.applyCached(entry.getKey(), recipient -> {
recipient.setColor(entry.getValue());
});
});
Stream.of(updates.entrySet()).forEach(entry -> Recipient.live(entry.getKey()).refresh());
}
}
// XXX This shouldn't be here, and is just a temporary workaround
public RegisteredState isRegistered(@NonNull Address address) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
try (Cursor cursor = db.query(TABLE_NAME, new String[] {REGISTERED}, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) return RegisteredState.fromId(cursor.getInt(0));
else return RegisteredState.UNKNOWN;
}
}
private void updateOrInsert(Address address, ContentValues contentValues) {
private void update(@NonNull RecipientId id, ContentValues contentValues) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
database.beginTransaction();
int updated = database.update(TABLE_NAME, contentValues, ADDRESS + " = ?",
new String[] {address.serialize()});
if (updated < 1) {
contentValues.put(ADDRESS, address.serialize());
database.insert(TABLE_NAME, null, contentValues);
}
database.setTransactionSuccessful();
database.endTransaction();
database.update(TABLE_NAME, contentValues, ID + " = ?", new String[] { id.serialize() });
}
public class BulkOperationsHandle {
private final SQLiteDatabase database;
private final Map<Address, PendingContactInfo> pendingContactInfoMap = new HashMap<>();
private final Map<RecipientId, PendingContactInfo> pendingContactInfoMap = new HashMap<>();
BulkOperationsHandle(SQLiteDatabase database) {
this.database = database;
}
public void setSystemContactInfo(@NonNull Address address, @Nullable String displayName, @Nullable String photoUri, @Nullable String systemPhoneLabel, @Nullable String systemContactUri) {
public void setSystemContactInfo(@NonNull RecipientId id, @Nullable String displayName, @Nullable String photoUri, @Nullable String systemPhoneLabel, @Nullable String systemContactUri) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(SYSTEM_DISPLAY_NAME, displayName);
contentValues.put(SYSTEM_PHOTO_URI, photoUri);
contentValues.put(SYSTEM_PHONE_LABEL, systemPhoneLabel);
contentValues.put(SYSTEM_CONTACT_URI, systemContactUri);
updateOrInsert(address, contentValues);
pendingContactInfoMap.put(address, new PendingContactInfo(displayName, photoUri, systemPhoneLabel, systemContactUri));
update(id, contentValues);
pendingContactInfoMap.put(id, new PendingContactInfo(displayName, photoUri, systemPhoneLabel, systemContactUri));
}
public void finish() {
database.setTransactionSuccessful();
database.endTransaction();
Stream.of(pendingContactInfoMap.entrySet())
.forEach(entry -> Recipient.applyCached(entry.getKey(), recipient -> {
recipient.setName(entry.getValue().displayName);
recipient.setSystemContactPhoto(Util.uri(entry.getValue().photoUri));
recipient.setCustomLabel(entry.getValue().phoneLabel);
recipient.setContactUri(Util.uri(entry.getValue().contactUri));
}));
Stream.of(pendingContactInfoMap.entrySet()).forEach(entry -> Recipient.live(entry.getKey()).refresh());
}
}
@@ -546,6 +591,8 @@ public class RecipientDatabase extends Database {
}
public static class RecipientSettings {
private final RecipientId id;
private final Address address;
private final boolean blocked;
private final long muteUntil;
private final VibrateState messageVibrateState;
@@ -569,7 +616,8 @@ public class RecipientDatabase extends Database {
private final UnidentifiedAccessMode unidentifiedAccessMode;
private final boolean forceSmsSelection;
RecipientSettings(boolean blocked, long muteUntil,
RecipientSettings(@NonNull RecipientId id,
@NonNull Address address, boolean blocked, long muteUntil,
@NonNull VibrateState messageVibrateState,
@NonNull VibrateState callVibrateState,
@Nullable Uri messageRingtone,
@@ -591,6 +639,8 @@ public class RecipientDatabase extends Database {
@NonNull UnidentifiedAccessMode unidentifiedAccessMode,
boolean forceSmsSelection)
{
this.id = id;
this.address = address;
this.blocked = blocked;
this.muteUntil = muteUntil;
this.messageVibrateState = messageVibrateState;
@@ -615,6 +665,14 @@ public class RecipientDatabase extends Database {
this.forceSmsSelection = forceSmsSelection;
}
public RecipientId getId() {
return id;
}
public @NonNull Address getAddress() {
return address;
}
public @Nullable MaterialColor getColor() {
return color;
}
@@ -715,8 +773,8 @@ public class RecipientDatabase extends Database {
}
public @NonNull Recipient getCurrent() {
String serialized = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
return Recipient.from(context, Address.fromSerialized(serialized), false);
RecipientId id = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
return Recipient.live(id).get();
}
public @Nullable Recipient getNext() {