mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 10:20:25 +01:00
Add storage support for the AccountRecord.
This commit is contained in:
@@ -39,6 +39,7 @@ import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
|
||||
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
|
||||
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
|
||||
import org.whispersystems.signalservice.api.storage.StorageId;
|
||||
@@ -216,7 +217,7 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
enum DirtyState {
|
||||
public enum DirtyState {
|
||||
CLEAN(0), UPDATE(1), INSERT(2), DELETE(3);
|
||||
|
||||
private final int id;
|
||||
@@ -228,6 +229,10 @@ public class RecipientDatabase extends Database {
|
||||
int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static DirtyState fromId(int id) {
|
||||
return values()[id];
|
||||
}
|
||||
}
|
||||
|
||||
public enum GroupType {
|
||||
@@ -401,23 +406,35 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull DirtyState getDirtyState(@NonNull RecipientId recipientId) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] { DIRTY }, ID_WHERE, new String[] { recipientId.serialize() }, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return DirtyState.fromId(cursor.getInt(cursor.getColumnIndexOrThrow(DIRTY)));
|
||||
}
|
||||
}
|
||||
|
||||
return DirtyState.CLEAN;
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientSettings> getPendingRecipientSyncUpdates() {
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_ID + " NOT NULL";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.UPDATE.getId()) };
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_ID + " NOT NULL AND " + TABLE_NAME + "." + ID + " != ?";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.UPDATE.getId()), Recipient.self().getId().serialize() };
|
||||
|
||||
return getRecipientSettings(query, args);
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientSettings> getPendingRecipientSyncInsertions() {
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_ID + " NOT NULL";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.INSERT.getId()) };
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_ID + " NOT NULL AND " + TABLE_NAME + "." + ID + " != ?";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.INSERT.getId()), Recipient.self().getId().serialize() };
|
||||
|
||||
return getRecipientSettings(query, args);
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientSettings> getPendingRecipientSyncDeletions() {
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_ID + " NOT NULL";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.DELETE.getId()) };
|
||||
String query = DIRTY + " = ? AND " + STORAGE_SERVICE_ID + " NOT NULL AND " + TABLE_NAME + "." + ID + " != ?";
|
||||
String[] args = new String[] { String.valueOf(DirtyState.DELETE.getId()), Recipient.self().getId().serialize() };
|
||||
|
||||
return getRecipientSettings(query, args);
|
||||
}
|
||||
@@ -432,6 +449,10 @@ public class RecipientDatabase extends Database {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void markNeedsSync(@NonNull RecipientId recipientId) {
|
||||
markDirty(recipientId, DirtyState.UPDATE);
|
||||
}
|
||||
|
||||
public void applyStorageIdUpdates(@NonNull Map<RecipientId, StorageId> storageIds) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
@@ -459,6 +480,7 @@ public class RecipientDatabase extends Database {
|
||||
{
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||
|
||||
db.beginTransaction();
|
||||
|
||||
@@ -492,9 +514,8 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
if (Recipient.self().getId().equals(recipientId)) {
|
||||
TextSecurePreferences.setProfileName(context, ProfileName.fromParts(insert.getGivenName().orNull(), insert.getFamilyName().orNull()));
|
||||
}
|
||||
threadDatabase.setArchived(recipientId, insert.isArchived());
|
||||
Recipient.live(recipientId).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,10 +555,18 @@ public class RecipientDatabase extends Database {
|
||||
} catch (InvalidKeyException e) {
|
||||
Log.w(TAG, "Failed to process identity key during update! Skipping.", e);
|
||||
}
|
||||
|
||||
threadDatabase.setArchived(recipientId, update.getNew().isArchived());
|
||||
Recipient.live(recipientId).refresh();
|
||||
}
|
||||
|
||||
for (SignalGroupV1Record insert : groupV1Inserts) {
|
||||
db.insertOrThrow(TABLE_NAME, null, getValuesForStorageGroupV1(insert));
|
||||
|
||||
Recipient recipient = Recipient.externalGroup(context, GroupUtil.getEncodedId(insert.getGroupId(), false));
|
||||
|
||||
threadDatabase.setArchived(recipient.getId(), insert.isArchived());
|
||||
recipient.live().refresh();
|
||||
}
|
||||
|
||||
for (RecordUpdate<SignalGroupV1Record> update : groupV1Updates) {
|
||||
@@ -547,6 +576,11 @@ public class RecipientDatabase extends Database {
|
||||
if (updateCount < 1) {
|
||||
throw new AssertionError("Had an update, but it didn't match any rows!");
|
||||
}
|
||||
|
||||
Recipient recipient = Recipient.externalGroup(context, GroupUtil.getEncodedId(update.getOld().getGroupId(), false));
|
||||
|
||||
threadDatabase.setArchived(recipient.getId(), update.getNew().isArchived());
|
||||
recipient.live().refresh();
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
@@ -555,6 +589,27 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public void applyStorageSyncUpdates(@NonNull StorageId storageId, SignalAccountRecord update) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
ProfileName profileName = ProfileName.fromParts(update.getGivenName().orNull(), update.getFamilyName().orNull());
|
||||
|
||||
values.put(PROFILE_GIVEN_NAME, profileName.getGivenName());
|
||||
values.put(PROFILE_FAMILY_NAME, profileName.getFamilyName());
|
||||
values.put(PROFILE_JOINED_NAME, profileName.toString());
|
||||
values.put(PROFILE_KEY, update.getProfileKey().transform(Base64::encodeBytes).orNull());
|
||||
values.put(STORAGE_SERVICE_ID, Base64.encodeBytes(update.getId().getRaw()));
|
||||
values.put(DIRTY, DirtyState.CLEAN.getId());
|
||||
|
||||
int updateCount = db.update(TABLE_NAME, values, STORAGE_SERVICE_ID + " = ?", new String[]{Base64.encodeBytes(storageId.getRaw())});
|
||||
if (updateCount < 1) {
|
||||
throw new AssertionError("Account update didn't match any rows!");
|
||||
}
|
||||
|
||||
Recipient.self().live().refresh();
|
||||
}
|
||||
|
||||
public void updatePhoneNumbers(@NonNull Map<String, String> mapping) {
|
||||
if (mapping.isEmpty()) return;
|
||||
|
||||
@@ -641,19 +696,19 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All storage keys, excluding the ones that need to be deleted.
|
||||
* @return All storage ids for ContactRecords, excluding the ones that need to be deleted.
|
||||
*/
|
||||
public List<StorageId> getAllStorageSyncKeys() {
|
||||
return new ArrayList<>(getAllStorageSyncKeysMap().values());
|
||||
public List<StorageId> getContactStorageSyncIds() {
|
||||
return new ArrayList<>(getContactStorageSyncIdsMap().values());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All storage keys, excluding the ones that need to be deleted.
|
||||
* @return All storage IDs for ContactRecords, excluding the ones that need to be deleted.
|
||||
*/
|
||||
public @NonNull Map<RecipientId, StorageId> getAllStorageSyncKeysMap() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String query = STORAGE_SERVICE_ID + " NOT NULL AND " + DIRTY + " != ?";
|
||||
String[] args = new String[]{String.valueOf(DirtyState.DELETE)};
|
||||
public @NonNull Map<RecipientId, StorageId> getContactStorageSyncIdsMap() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String query = STORAGE_SERVICE_ID + " NOT NULL AND " + DIRTY + " != ? AND " + ID + " != ?";
|
||||
String[] args = new String[]{String.valueOf(DirtyState.DELETE), Recipient.self().getId().serialize() };
|
||||
Map<RecipientId, StorageId> out = new HashMap<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] { ID, STORAGE_SERVICE_ID, GROUP_TYPE }, query, args, null, null, null)) {
|
||||
@@ -920,7 +975,7 @@ public class RecipientDatabase extends Database {
|
||||
if (update(updateQuery, valuesToSet)) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
Recipient.live(id).refresh();
|
||||
ApplicationDependencies.getJobManager().add(new StorageSyncJob());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -966,7 +1021,7 @@ public class RecipientDatabase extends Database {
|
||||
if (update(id, contentValues)) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
Recipient.live(id).refresh();
|
||||
ApplicationDependencies.getJobManager().add(new StorageSyncJob());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,6 +1030,11 @@ public class RecipientDatabase extends Database {
|
||||
contentValues.put(SIGNAL_PROFILE_AVATAR, profileAvatar);
|
||||
if (update(id, contentValues)) {
|
||||
Recipient.live(id).refresh();
|
||||
|
||||
if (id.equals(Recipient.self().getId())) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -984,7 +1044,7 @@ public class RecipientDatabase extends Database {
|
||||
if (update(id, contentValues)) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
Recipient.live(id).refresh();
|
||||
ApplicationDependencies.getJobManager().add(new StorageSyncJob());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1002,6 +1062,7 @@ public class RecipientDatabase extends Database {
|
||||
if (update(id, contentValues)) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
Recipient.live(id).refresh();
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,8 +1078,10 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(USERNAME, username);
|
||||
update(id, contentValues);
|
||||
Recipient.live(id).refresh();
|
||||
if (update(id, contentValues)) {
|
||||
Recipient.live(id).refresh();
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearUsernameIfExists(@NonNull String username) {
|
||||
@@ -1601,7 +1664,7 @@ public class RecipientDatabase extends Database {
|
||||
private final Recipient.Capability uuidCapability;
|
||||
private final Recipient.Capability groupsV2Capability;
|
||||
private final InsightsBannerTier insightsBannerTier;
|
||||
private final byte[] storageKey;
|
||||
private final byte[] storageId;
|
||||
private final byte[] identityKey;
|
||||
private final IdentityDatabase.VerifiedStatus identityStatus;
|
||||
|
||||
@@ -1637,7 +1700,7 @@ public class RecipientDatabase extends Database {
|
||||
Recipient.Capability uuidCapability,
|
||||
Recipient.Capability groupsV2Capability,
|
||||
@NonNull InsightsBannerTier insightsBannerTier,
|
||||
@Nullable byte[] storageKey,
|
||||
@Nullable byte[] storageId,
|
||||
@Nullable byte[] identityKey,
|
||||
@NonNull IdentityDatabase.VerifiedStatus identityStatus)
|
||||
{
|
||||
@@ -1673,7 +1736,7 @@ public class RecipientDatabase extends Database {
|
||||
this.uuidCapability = uuidCapability;
|
||||
this.groupsV2Capability = groupsV2Capability;
|
||||
this.insightsBannerTier = insightsBannerTier;
|
||||
this.storageKey = storageKey;
|
||||
this.storageId = storageId;
|
||||
this.identityKey = identityKey;
|
||||
this.identityStatus = identityStatus;
|
||||
}
|
||||
@@ -1806,8 +1869,8 @@ public class RecipientDatabase extends Database {
|
||||
return groupsV2Capability;
|
||||
}
|
||||
|
||||
public @Nullable byte[] getStorageKey() {
|
||||
return storageKey;
|
||||
public @Nullable byte[] getStorageId() {
|
||||
return storageId;
|
||||
}
|
||||
|
||||
public @Nullable byte[] getIdentityKey() {
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -53,6 +54,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
@@ -422,10 +424,48 @@ public class ThreadDatabase extends Database {
|
||||
return getConversationList("1");
|
||||
}
|
||||
|
||||
public boolean isArchived(@NonNull RecipientId recipientId) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String query = RECIPIENT_ID + " = ?";
|
||||
String[] args = new String[]{ recipientId.serialize() };
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] { ARCHIVED }, query, args, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getInt(cursor.getColumnIndexOrThrow(ARCHIVED)) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setArchived(@NonNull RecipientId recipientId, boolean status) {
|
||||
setArchived(Collections.singletonMap(recipientId, status));
|
||||
}
|
||||
|
||||
public void setArchived(@NonNull Map<RecipientId, Boolean> status) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
String query = RECIPIENT_ID + " = ?";
|
||||
|
||||
for (Map.Entry<RecipientId, Boolean> entry : status.entrySet()) {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(ARCHIVED, entry.getValue() ? "1" : "0");
|
||||
db.update(TABLE_NAME, values, query, new String[] { entry.getKey().serialize() });
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull Set<RecipientId> getArchivedRecipients() {
|
||||
Set<RecipientId> archived = new HashSet<>();
|
||||
|
||||
try (Cursor cursor = DatabaseFactory.getThreadDatabase(context).getArchivedConversationList()) {
|
||||
try (Cursor cursor = getArchivedConversationList()) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
archived.add(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_ID))));
|
||||
}
|
||||
@@ -488,6 +528,12 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId + ""});
|
||||
notifyConversationListListeners();
|
||||
|
||||
Recipient recipient = getRecipientForThreadId(threadId);
|
||||
if (recipient != null) {
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(recipient.getId());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
public void unarchiveConversation(long threadId) {
|
||||
@@ -497,6 +543,12 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId + ""});
|
||||
notifyConversationListListeners();
|
||||
|
||||
Recipient recipient = getRecipientForThreadId(threadId);
|
||||
if (recipient != null) {
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(recipient.getId());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
public void setLastSeen(long threadId) {
|
||||
|
||||
Reference in New Issue
Block a user