From 0d0c74f358e6936afbd25f9f57d7197ccb95e177 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Mon, 3 Jan 2022 18:46:10 -0500 Subject: [PATCH] Fix in-memory message updates. We can also switch to using the message-specific update route for receipts too. --- .../securesms/database/Database.java | 4 -- .../securesms/database/MessageDatabase.java | 25 +++++---- .../securesms/database/MmsDatabase.java | 12 ++--- .../securesms/database/MmsSmsDatabase.java | 52 ++++++++----------- .../securesms/database/SmsDatabase.java | 18 +++---- .../paging/FixedSizePagingController.java | 13 ++++- 6 files changed, 61 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Database.java b/app/src/main/java/org/thoughtcrime/securesms/database/Database.java index 38924d8a9..2a43a63f2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Database.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Database.java @@ -51,10 +51,6 @@ public abstract class Database { ApplicationDependencies.getDatabaseObserver().notifyVerboseConversationListeners(threadIds); } - protected void notifyVerboseConversationListeners(long threadId) { - ApplicationDependencies.getDatabaseObserver().notifyVerboseConversationListeners(threadId); - } - protected void notifyConversationListListeners() { ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java index 67269a4ca..cd3e27693 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java @@ -120,7 +120,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns public abstract void markDownloadState(long messageId, long state); public abstract void markIncomingNotificationReceived(long threadId); - public abstract Set incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType); + public abstract Set incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType); abstract @NonNull MmsSmsDatabase.TimestampReadResult setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map threadToLatestRead); public abstract List setEntireThreadRead(long threadId); public abstract List setMessagesReadSince(long threadId, long timestamp); @@ -647,35 +647,34 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns } } - static class ThreadUpdate { - private final long threadId; - private final boolean verbose; + static class MessageUpdate { + private final long threadId; + private final MessageId messageId; - ThreadUpdate(long threadId, boolean verbose) { - this.threadId = threadId; - this.verbose = verbose; + MessageUpdate(long threadId, @NonNull MessageId messageId) { + this.threadId = threadId; + this.messageId = messageId; } public long getThreadId() { return threadId; } - public boolean isVerbose() { - return verbose; + public @NonNull MessageId getMessageId() { + return messageId; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - ThreadUpdate that = (ThreadUpdate) o; - return threadId == that.threadId && - verbose == that.verbose; + final MessageUpdate that = (MessageUpdate) o; + return threadId == that.threadId && messageId.equals(that.messageId); } @Override public int hashCode() { - return Objects.hash(threadId, verbose); + return Objects.hash(threadId, messageId); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java index 0cf1c7a01..130f24f43 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -607,9 +607,9 @@ public class MmsDatabase extends MessageDatabase { } @Override - public Set incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType) { - SQLiteDatabase database = databaseHelper.getSignalWritableDatabase(); - Set threadUpdates = new HashSet<>(); + public Set incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType) { + SQLiteDatabase database = databaseHelper.getSignalWritableDatabase(); + Set messageUpdates = new HashSet<>(); try (Cursor cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, RECIPIENT_ID, receiptType.getColumnName(), RECEIPT_TIMESTAMP}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, @@ -637,16 +637,16 @@ public class MmsDatabase extends MessageDatabase { SignalDatabase.groupReceipts().update(ourRecipientId, id, status, timestamp); - threadUpdates.add(new ThreadUpdate(threadId, !isFirstIncrement)); + messageUpdates.add(new MessageUpdate(threadId, new MessageId(id, true))); } } } - if (threadUpdates.size() > 0 && receiptType == ReceiptType.DELIVERY) { + if (messageUpdates.size() > 0 && receiptType == ReceiptType.DELIVERY) { earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getRecipientId(), timestamp); } - return threadUpdates; + return messageUpdates; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java index bc8a59e56..6a2c96b40 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java @@ -29,7 +29,7 @@ import net.zetetic.database.sqlcipher.SQLiteQueryBuilder; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId; -import org.thoughtcrime.securesms.database.MessageDatabase.ThreadUpdate; +import org.thoughtcrime.securesms.database.MessageDatabase.MessageUpdate; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.notifications.v2.MessageNotifierV2; @@ -405,32 +405,28 @@ public class MmsSmsDatabase extends Database { * @return Whether or not some thread was updated. */ private boolean incrementReceiptCount(SyncMessageId syncMessageId, long timestamp, @NonNull MessageDatabase.ReceiptType receiptType) { - SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); - ThreadDatabase threadDatabase = SignalDatabase.threads(); - Set threadUpdates = new HashSet<>(); + SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); + ThreadDatabase threadDatabase = SignalDatabase.threads(); + Set messageUpdates = new HashSet<>(); db.beginTransaction(); try { - threadUpdates = incrementReceiptCountInternal(syncMessageId, timestamp, receiptType); + messageUpdates = incrementReceiptCountInternal(syncMessageId, timestamp, receiptType); - for (ThreadUpdate threadUpdate : threadUpdates) { - threadDatabase.update(threadUpdate.getThreadId(), false); + for (MessageUpdate messageUpdate : messageUpdates) { + threadDatabase.update(messageUpdate.getThreadId(), false); } db.setTransactionSuccessful(); } finally { db.endTransaction(); - for (ThreadUpdate threadUpdate : threadUpdates) { - if (threadUpdate.isVerbose()) { - notifyVerboseConversationListeners(threadUpdate.getThreadId()); - } else { - notifyConversationListeners(threadUpdate.getThreadId()); - } + for (MessageUpdate threadUpdate : messageUpdates) { + ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(threadUpdate.getMessageId()); } } - return threadUpdates.size() > 0; + return messageUpdates.size() > 0; } /** @@ -441,22 +437,22 @@ public class MmsSmsDatabase extends Database { private @NonNull Collection incrementReceiptCounts(@NonNull List syncMessageIds, long timestamp, @NonNull MessageDatabase.ReceiptType receiptType) { SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); ThreadDatabase threadDatabase = SignalDatabase.threads(); - Set threadUpdates = new HashSet<>(); + Set messageUpdates = new HashSet<>(); Collection unhandled = new HashSet<>(); db.beginTransaction(); try { for (SyncMessageId id : syncMessageIds) { - Set updates = incrementReceiptCountInternal(id, timestamp, receiptType); + Set updates = incrementReceiptCountInternal(id, timestamp, receiptType); if (updates.size() > 0) { - threadUpdates.addAll(updates); + messageUpdates.addAll(updates); } else { unhandled.add(id); } } - for (ThreadUpdate update : threadUpdates) { + for (MessageUpdate update : messageUpdates) { threadDatabase.updateSilently(update.getThreadId(), false); } @@ -464,15 +460,11 @@ public class MmsSmsDatabase extends Database { } finally { db.endTransaction(); - for (ThreadUpdate threadUpdate : threadUpdates) { - if (threadUpdate.isVerbose()) { - notifyVerboseConversationListeners(threadUpdate.getThreadId()); - } else { - notifyConversationListeners(threadUpdate.getThreadId()); - } + for (MessageUpdate messageUpdate : messageUpdates) { + ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(messageUpdate.getMessageId()); } - if (threadUpdates.size() > 0) { + if (messageUpdates.size() > 0) { notifyConversationListListeners(); } } @@ -484,13 +476,13 @@ public class MmsSmsDatabase extends Database { /** * Doesn't do any transactions or updates, so we can re-use the method safely. */ - private @NonNull Set incrementReceiptCountInternal(SyncMessageId syncMessageId, long timestamp, MessageDatabase.ReceiptType receiptType) { - Set threadUpdates = new HashSet<>(); + private @NonNull Set incrementReceiptCountInternal(SyncMessageId syncMessageId, long timestamp, MessageDatabase.ReceiptType receiptType) { + Set messageUpdates = new HashSet<>(); - threadUpdates.addAll(SignalDatabase.sms().incrementReceiptCount(syncMessageId, timestamp, receiptType)); - threadUpdates.addAll(SignalDatabase.mms().incrementReceiptCount(syncMessageId, timestamp, receiptType)); + messageUpdates.addAll(SignalDatabase.sms().incrementReceiptCount(syncMessageId, timestamp, receiptType)); + messageUpdates.addAll(SignalDatabase.mms().incrementReceiptCount(syncMessageId, timestamp, receiptType)); - return threadUpdates; + return messageUpdates; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 3326f9415..477393748 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -481,18 +481,18 @@ public class SmsDatabase extends MessageDatabase { } @Override - public @NonNull Set incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType) { + public @NonNull Set incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType) { if (receiptType == ReceiptType.VIEWED) { return Collections.emptySet(); } - SQLiteDatabase database = databaseHelper.getSignalWritableDatabase(); - Set threadUpdates = new HashSet<>(); + SQLiteDatabase database = databaseHelper.getSignalWritableDatabase(); + Set messageUpdates = new HashSet<>(); try (Cursor cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, RECIPIENT_ID, TYPE, DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, RECEIPT_TIMESTAMP}, - DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, - null, null, null, null)) { - + DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, + null, null, null, null)) + { while (cursor.moveToNext()) { if (Types.isOutgoingMessageType(CursorUtil.requireLong(cursor, TYPE))) { RecipientId theirRecipientId = messageId.getRecipientId(); @@ -512,16 +512,16 @@ public class SmsDatabase extends MessageDatabase { ID + " = ?", SqlUtil.buildArgs(updatedTimestamp, id)); - threadUpdates.add(new ThreadUpdate(threadId, !isFirstIncrement)); + messageUpdates.add(new MessageUpdate(threadId, new MessageId(id, false))); } } } - if (threadUpdates.isEmpty() && receiptType == ReceiptType.DELIVERY) { + if (messageUpdates.isEmpty() && receiptType == ReceiptType.DELIVERY) { earlyDeliveryReceiptCache.increment(messageId.getTimetamp(), messageId.getRecipientId(), timestamp); } - return threadUpdates; + return messageUpdates; } } diff --git a/paging/lib/src/main/java/org/signal/paging/FixedSizePagingController.java b/paging/lib/src/main/java/org/signal/paging/FixedSizePagingController.java index d799ddb53..e2fe5d601 100644 --- a/paging/lib/src/main/java/org/signal/paging/FixedSizePagingController.java +++ b/paging/lib/src/main/java/org/signal/paging/FixedSizePagingController.java @@ -195,13 +195,24 @@ class FixedSizePagingController implements PagingController { List updatedList = new CompressedList<>(data); updatedList.add(position, item); - keyToPosition.put(dataSource.getKey(item), position); + rebuildKeyToPositionMap(keyToPosition, updatedList, dataSource); data = updatedList; liveData.postValue(updatedList); }); } + private void rebuildKeyToPositionMap(@NonNull Map map, @NonNull List dataList, @NonNull PagedDataSource dataSource) { + map.clear(); + + for (int i = 0, len = dataList.size(); i < len; i++) { + Data item = dataList.get(i); + if (item != null) { + map.put(dataSource.getKey(item), i); + } + } + } + private static String buildLog(int aroundIndex, String message) { return "onDataNeededAroundIndex(" + aroundIndex + ") " + message; }