mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 09:49:30 +01:00
Add support for syncing forced unread status.
This commit is contained in:
@@ -668,6 +668,20 @@ public class RecipientDatabase extends Database {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void markNeedsSync(@NonNull Collection<RecipientId> recipientIds) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
for (RecipientId recipientId : recipientIds) {
|
||||
markDirty(recipientId, DirtyState.UPDATE);
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public void markNeedsSync(@NonNull RecipientId recipientId) {
|
||||
markDirty(recipientId, DirtyState.UPDATE);
|
||||
}
|
||||
@@ -768,7 +782,7 @@ public class RecipientDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
threadDatabase.setArchived(recipientId, insert.isArchived());
|
||||
threadDatabase.applyStorageSyncUpdate(recipientId, insert);
|
||||
needsRefresh.add(recipientId);
|
||||
}
|
||||
|
||||
@@ -821,7 +835,7 @@ public class RecipientDatabase extends Database {
|
||||
Log.w(TAG, "Failed to process identity key during update! Skipping.", e);
|
||||
}
|
||||
|
||||
threadDatabase.setArchived(recipientId, update.getNew().isArchived());
|
||||
threadDatabase.applyStorageSyncUpdate(recipientId, update.getNew());
|
||||
needsRefresh.add(recipientId);
|
||||
}
|
||||
|
||||
@@ -830,7 +844,7 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
Recipient recipient = Recipient.externalGroup(context, GroupId.v1orThrow(insert.getGroupId()));
|
||||
|
||||
threadDatabase.setArchived(recipient.getId(), insert.isArchived());
|
||||
threadDatabase.applyStorageSyncUpdate(recipient.getId(), insert);
|
||||
needsRefresh.add(recipient.getId());
|
||||
}
|
||||
|
||||
@@ -844,7 +858,7 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
Recipient recipient = Recipient.externalGroup(context, GroupId.v1orThrow(update.getOld().getGroupId()));
|
||||
|
||||
threadDatabase.setArchived(recipient.getId(), update.getNew().isArchived());
|
||||
threadDatabase.applyStorageSyncUpdate(recipient.getId(), update.getNew());
|
||||
needsRefresh.add(recipient.getId());
|
||||
}
|
||||
|
||||
@@ -872,7 +886,7 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
ApplicationDependencies.getJobManager().add(new RequestGroupV2InfoJob(groupId));
|
||||
|
||||
threadDatabase.setArchived(recipient.getId(), insert.isArchived());
|
||||
threadDatabase.applyStorageSyncUpdate(recipient.getId(), insert);
|
||||
needsRefresh.add(recipient.getId());
|
||||
}
|
||||
|
||||
@@ -887,7 +901,7 @@ public class RecipientDatabase extends Database {
|
||||
GroupMasterKey masterKey = update.getOld().getMasterKeyOrThrow();
|
||||
Recipient recipient = Recipient.externalGroup(context, GroupId.v2(masterKey));
|
||||
|
||||
threadDatabase.setArchived(recipient.getId(), update.getNew().isArchived());
|
||||
threadDatabase.applyStorageSyncUpdate(recipient.getId(), update.getNew());
|
||||
needsRefresh.add(recipient.getId());
|
||||
}
|
||||
|
||||
@@ -936,6 +950,8 @@ public class RecipientDatabase extends Database {
|
||||
ApplicationDependencies.getJobManager().add(new RefreshAttributesJob());
|
||||
}
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).applyStorageSyncUpdate(Recipient.self().getId(), update);
|
||||
|
||||
Recipient.self().live().refresh();
|
||||
}
|
||||
|
||||
@@ -1236,12 +1252,13 @@ public class RecipientDatabase extends Database {
|
||||
String storageProtoRaw = CursorUtil.getString(cursor, STORAGE_PROTO).orNull();
|
||||
byte[] storageProto = storageProtoRaw != null ? Base64.decodeOrThrow(storageProtoRaw) : null;
|
||||
boolean archived = CursorUtil.getBoolean(cursor, ThreadDatabase.ARCHIVED).or(false);
|
||||
boolean forcedUnread = CursorUtil.getInt(cursor, ThreadDatabase.READ).transform(status -> status == ThreadDatabase.ReadStatus.FORCED_UNREAD.serialize()).or(false);
|
||||
GroupMasterKey groupMasterKey = CursorUtil.getBlob(cursor, GroupDatabase.V2_MASTER_KEY).transform(GroupUtil::requireMasterKey).orNull();
|
||||
byte[] identityKey = CursorUtil.getString(cursor, IDENTITY_KEY).transform(Base64::decodeOrThrow).orNull();
|
||||
VerifiedStatus identityStatus = CursorUtil.getInt(cursor, IDENTITY_STATUS).transform(VerifiedStatus::forState).or(VerifiedStatus.DEFAULT);
|
||||
|
||||
|
||||
return new RecipientSettings.SyncExtras(storageProto, groupMasterKey, identityKey, identityStatus, archived);
|
||||
return new RecipientSettings.SyncExtras(storageProto, groupMasterKey, identityKey, identityStatus, archived, forcedUnread);
|
||||
}
|
||||
|
||||
public BulkOperationsHandle beginBulkSystemContactUpdate() {
|
||||
@@ -1422,7 +1439,7 @@ public class RecipientDatabase extends Database {
|
||||
valuesToSet.putNull(PROFILE_KEY_CREDENTIAL);
|
||||
valuesToSet.put(UNIDENTIFIED_ACCESS_MODE, UnidentifiedAccessMode.UNKNOWN.getMode());
|
||||
|
||||
SqlUtil.UpdateQuery updateQuery = SqlUtil.buildTrueUpdateQuery(selection, args, valuesToCompare);
|
||||
SqlUtil.Query updateQuery = SqlUtil.buildTrueUpdateQuery(selection, args, valuesToCompare);
|
||||
|
||||
if (update(updateQuery, valuesToSet)) {
|
||||
markDirty(id, DirtyState.UPDATE);
|
||||
@@ -1471,7 +1488,7 @@ public class RecipientDatabase extends Database {
|
||||
|
||||
values.put(PROFILE_KEY_CREDENTIAL, Base64.encodeBytes(profileKeyCredential.serialize()));
|
||||
|
||||
SqlUtil.UpdateQuery updateQuery = SqlUtil.buildTrueUpdateQuery(selection, args, values);
|
||||
SqlUtil.Query updateQuery = SqlUtil.buildTrueUpdateQuery(selection, args, values);
|
||||
|
||||
if (update(updateQuery, values)) {
|
||||
// TODO [greyson] If we sync this in future, mark dirty
|
||||
@@ -2250,9 +2267,7 @@ public class RecipientDatabase extends Database {
|
||||
* query such that this will only return true if a row was *actually* updated.
|
||||
*/
|
||||
private boolean update(@NonNull RecipientId id, @NonNull ContentValues contentValues) {
|
||||
String selection = ID + " = ?";
|
||||
String[] args = new String[]{id.serialize()};
|
||||
SqlUtil.UpdateQuery updateQuery = SqlUtil.buildTrueUpdateQuery(selection, args, contentValues);
|
||||
SqlUtil.Query updateQuery = SqlUtil.buildTrueUpdateQuery(ID_WHERE, SqlUtil.buildArgs(id), contentValues);
|
||||
|
||||
return update(updateQuery, contentValues);
|
||||
}
|
||||
@@ -2262,7 +2277,7 @@ public class RecipientDatabase extends Database {
|
||||
* <p>
|
||||
* This will only return true if a row was *actually* updated with respect to the where clause of the {@param updateQuery}.
|
||||
*/
|
||||
private boolean update(@NonNull SqlUtil.UpdateQuery updateQuery, @NonNull ContentValues contentValues) {
|
||||
private boolean update(@NonNull SqlUtil.Query updateQuery, @NonNull ContentValues contentValues) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
return database.update(TABLE_NAME, contentValues, updateQuery.getWhere(), updateQuery.getWhereArgs()) > 0;
|
||||
@@ -2816,18 +2831,21 @@ public class RecipientDatabase extends Database {
|
||||
private final byte[] identityKey;
|
||||
private final VerifiedStatus identityStatus;
|
||||
private final boolean archived;
|
||||
private final boolean forcedUnread;
|
||||
|
||||
public SyncExtras(@Nullable byte[] storageProto,
|
||||
@Nullable GroupMasterKey groupMasterKey,
|
||||
@Nullable byte[] identityKey,
|
||||
@NonNull VerifiedStatus identityStatus,
|
||||
boolean archived)
|
||||
boolean archived,
|
||||
boolean forcedUnread)
|
||||
{
|
||||
this.storageProto = storageProto;
|
||||
this.groupMasterKey = groupMasterKey;
|
||||
this.identityKey = identityKey;
|
||||
this.identityStatus = identityStatus;
|
||||
this.archived = archived;
|
||||
this.forcedUnread = forcedUnread;
|
||||
}
|
||||
|
||||
public @Nullable byte[] getStorageProto() {
|
||||
@@ -2849,6 +2867,10 @@ public class RecipientDatabase extends Database {
|
||||
public @NonNull VerifiedStatus getIdentityStatus() {
|
||||
return identityStatus;
|
||||
}
|
||||
|
||||
public boolean isForcedUnread() {
|
||||
return forcedUnread;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
|
||||
import org.jsoup.helper.StringUtil;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedMember;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.MarkedMessageInfo;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
@@ -56,11 +54,15 @@ import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
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.SignalGroupV2Record;
|
||||
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -70,7 +72,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ThreadDatabase extends Database {
|
||||
|
||||
@@ -102,7 +103,7 @@ public class ThreadDatabase extends Database {
|
||||
public static final String LAST_SEEN = "last_seen";
|
||||
public static final String HAS_SENT = "has_sent";
|
||||
private static final String LAST_SCROLLED = "last_scrolled";
|
||||
private static final String PINNED = "pinned";
|
||||
static final String PINNED = "pinned";
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
||||
DATE + " INTEGER DEFAULT 0, " +
|
||||
@@ -405,6 +406,7 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
List<MarkedMessageInfo> smsRecords = new LinkedList<>();
|
||||
List<MarkedMessageInfo> mmsRecords = new LinkedList<>();
|
||||
boolean needsSync = false;
|
||||
|
||||
db.beginTransaction();
|
||||
|
||||
@@ -417,6 +419,8 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
|
||||
for (long threadId : threadIds) {
|
||||
ThreadRecord previous = getThreadRecord(threadId);
|
||||
|
||||
smsRecords.addAll(DatabaseFactory.getSmsDatabase(context).setMessagesReadSince(threadId, sinceTimestamp));
|
||||
mmsRecords.addAll(DatabaseFactory.getMmsDatabase(context).setMessagesReadSince(threadId, sinceTimestamp));
|
||||
|
||||
@@ -427,7 +431,12 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
contentValues.put(UNREAD_COUNT, unreadCount);
|
||||
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[]{threadId + ""});
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, SqlUtil.buildArgs(threadId));
|
||||
|
||||
if (previous != null && previous.isForcedUnread()) {
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(previous.getRecipient().getId());
|
||||
needsSync = true;
|
||||
}
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
@@ -437,6 +446,11 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
notifyConversationListeners(new HashSet<>(threadIds));
|
||||
notifyConversationListListeners();
|
||||
|
||||
if (needsSync) {
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
|
||||
return Util.concatenatedList(smsRecords, mmsRecords);
|
||||
}
|
||||
|
||||
@@ -445,19 +459,22 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
List<RecipientId> recipientIds = getRecipientIdsForThreadIds(threadIds);
|
||||
SqlUtil.Query query = SqlUtil.buildCollectionQuery(ID, threadIds);
|
||||
ContentValues contentValues = new ContentValues();
|
||||
|
||||
contentValues.put(READ, ReadStatus.FORCED_UNREAD.serialize());
|
||||
|
||||
for (long threadId : threadIds) {
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] { String.valueOf(threadId) });
|
||||
}
|
||||
db.update(TABLE_NAME, contentValues, query.getWhere(), query.getWhereArgs());
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(recipientIds);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
notifyConversationListListeners();
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -949,6 +966,20 @@ public class ThreadDatabase extends Database {
|
||||
return Recipient.resolved(id);
|
||||
}
|
||||
|
||||
public @NonNull List<RecipientId> getRecipientIdsForThreadIds(Collection<Long> threadIds) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
SqlUtil.Query query = SqlUtil.buildCollectionQuery(ID, threadIds);
|
||||
List<RecipientId> ids = new ArrayList<>(threadIds.size());
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] { RECIPIENT_ID }, query.getWhere(), query.getWhereArgs(), null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
ids.add(RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)));
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
public boolean hasThread(@NonNull RecipientId recipientId) {
|
||||
return getThreadIdIfExistsFor(recipientId) > -1;
|
||||
}
|
||||
@@ -964,16 +995,56 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
|
||||
void updateReadState(long threadId) {
|
||||
int unreadCount = DatabaseFactory.getMmsSmsDatabase(context).getUnreadCount(threadId);
|
||||
ThreadRecord previous = getThreadRecord(threadId);
|
||||
int unreadCount = DatabaseFactory.getMmsSmsDatabase(context).getUnreadCount(threadId);
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(READ, unreadCount == 0);
|
||||
contentValues.put(READ, unreadCount == 0 ? ReadStatus.READ.serialize() : ReadStatus.UNREAD.serialize());
|
||||
contentValues.put(UNREAD_COUNT, unreadCount);
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,ID_WHERE,
|
||||
new String[] {String.valueOf(threadId)});
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, ID_WHERE, SqlUtil.buildArgs(threadId));
|
||||
|
||||
notifyConversationListListeners();
|
||||
|
||||
if (previous != null && previous.isForcedUnread()) {
|
||||
DatabaseFactory.getRecipientDatabase(context).markNeedsSync(previous.getRecipient().getId());
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
public void applyStorageSyncUpdate(@NonNull RecipientId recipientId, @NonNull SignalContactRecord record) {
|
||||
applyStorageSyncUpdate(recipientId, record.isArchived(), record.isForcedUnread());
|
||||
}
|
||||
|
||||
public void applyStorageSyncUpdate(@NonNull RecipientId recipientId, @NonNull SignalGroupV1Record record) {
|
||||
applyStorageSyncUpdate(recipientId, record.isArchived(), record.isForcedUnread());
|
||||
}
|
||||
|
||||
public void applyStorageSyncUpdate(@NonNull RecipientId recipientId, @NonNull SignalGroupV2Record record) {
|
||||
applyStorageSyncUpdate(recipientId, record.isArchived(), record.isForcedUnread());
|
||||
}
|
||||
|
||||
public void applyStorageSyncUpdate(@NonNull RecipientId recipientId, @NonNull SignalAccountRecord record) {
|
||||
applyStorageSyncUpdate(recipientId, record.isNoteToSelfArchived(), record.isNoteToSelfForcedUnread());
|
||||
}
|
||||
|
||||
private void applyStorageSyncUpdate(@NonNull RecipientId recipientId, boolean archived, boolean forcedUnread) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(ARCHIVED, archived);
|
||||
|
||||
if (forcedUnread) {
|
||||
values.put(READ, ReadStatus.FORCED_UNREAD.serialize());
|
||||
} else {
|
||||
Long threadId = getThreadIdFor(recipientId);
|
||||
if (threadId != null) {
|
||||
int unreadCount = DatabaseFactory.getMmsSmsDatabase(context).getUnreadCount(threadId);
|
||||
|
||||
values.put(READ, unreadCount == 0 ? ReadStatus.READ.serialize() : ReadStatus.UNREAD.serialize());
|
||||
values.put(UNREAD_COUNT, unreadCount);
|
||||
}
|
||||
}
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, values, RECIPIENT_ID + " = ?", SqlUtil.buildArgs(recipientId));
|
||||
}
|
||||
|
||||
public boolean update(long threadId, boolean unarchive) {
|
||||
@@ -1404,7 +1475,7 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
private enum ReadStatus {
|
||||
enum ReadStatus {
|
||||
READ(1), UNREAD(0), FORCED_UNREAD(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
Reference in New Issue
Block a user