From ec63dd704abdff8943c37176a2c1c63c52c26edf Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Wed, 14 Apr 2021 15:42:34 -0400 Subject: [PATCH] Mark previous messages in thread as read when receiving a read sync message. --- .../securesms/database/MessageDatabase.java | 3 ++- .../securesms/database/MmsDatabase.java | 6 ++++- .../securesms/database/SmsDatabase.java | 6 ++++- .../securesms/database/ThreadDatabase.java | 22 +++++++++++-------- .../messages/MessageContentProcessor.java | 19 ++++++++++++---- 5 files changed, 40 insertions(+), 16 deletions(-) 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 a5dcb7b151..e4c22da3ab 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java @@ -49,6 +49,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -120,7 +121,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns public abstract void markIncomingNotificationReceived(long threadId); public abstract Set incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType); - public abstract List> setTimestampRead(SyncMessageId messageId, long proposedExpireStarted); + public abstract List> setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map threadToLatestRead); public abstract List setEntireThreadRead(long threadId); public abstract List setMessagesReadSince(long threadId, long timestamp); public abstract List setAllMessagesRead(); 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 39369710b7..e789d64fbf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -66,6 +66,7 @@ import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage; import org.thoughtcrime.securesms.mms.QuoteModel; import org.thoughtcrime.securesms.mms.SlideDeck; +import org.thoughtcrime.securesms.notifications.MarkReadReceiver; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo; @@ -951,7 +952,7 @@ public class MmsDatabase extends MessageDatabase { } @Override - public List> setTimestampRead(SyncMessageId messageId, long proposedExpireStarted) { + public List> setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map threadToLatestRead) { SQLiteDatabase database = databaseHelper.getWritableDatabase(); List> expiring = new LinkedList<>(); Cursor cursor = null; @@ -986,6 +987,9 @@ public class MmsDatabase extends MessageDatabase { DatabaseFactory.getThreadDatabase(context).updateReadState(threadId); DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId); notifyConversationListeners(threadId); + + Long latest = threadToLatestRead.get(threadId); + threadToLatestRead.put(threadId, (latest != null) ? Math.max(latest, messageId.getTimetamp()) : messageId.getTimetamp()); } } } finally { 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 b3d2ee38fe..8a8b81ef2b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -47,6 +47,7 @@ import org.thoughtcrime.securesms.jobs.TrimThreadJob; import org.thoughtcrime.securesms.mms.IncomingMediaMessage; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; +import org.thoughtcrime.securesms.notifications.MarkReadReceiver; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo; @@ -510,7 +511,7 @@ public class SmsDatabase extends MessageDatabase { } @Override - public List> setTimestampRead(SyncMessageId messageId, long proposedExpireStarted) { + public List> setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map threadToLatestRead) { SQLiteDatabase database = databaseHelper.getWritableDatabase(); List> expiring = new LinkedList<>(); Cursor cursor = null; @@ -547,6 +548,9 @@ public class SmsDatabase extends MessageDatabase { DatabaseFactory.getThreadDatabase(context).updateReadState(threadId); DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId); notifyConversationListeners(threadId); + + Long latest = threadToLatestRead.get(threadId); + threadToLatestRead.put(threadId, (latest != null) ? Math.max(latest, messageId.getTimetamp()) : messageId.getTimetamp()); } } } finally { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index e387c1610a..8e197d3c26 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -26,6 +26,7 @@ import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.annimon.stream.Collectors; import com.annimon.stream.Stream; import com.fasterxml.jackson.annotation.JsonProperty; @@ -368,18 +369,18 @@ public class ThreadDatabase extends Database { } public List setRead(long threadId, boolean lastSeen) { - return setReadInternal(Collections.singletonList(threadId), lastSeen, -1); + return setReadSince(Collections.singletonMap(threadId, -1L), lastSeen); } public List setReadSince(long threadId, boolean lastSeen, long sinceTimestamp) { - return setReadInternal(Collections.singletonList(threadId), lastSeen, sinceTimestamp); + return setReadSince(Collections.singletonMap(threadId, sinceTimestamp), lastSeen); } public List setRead(Collection threadIds, boolean lastSeen) { - return setReadInternal(threadIds, lastSeen, -1); + return setReadSince(Stream.of(threadIds).collect(Collectors.toMap(t -> t, t -> -1L)), lastSeen); } - private List setReadInternal(Collection threadIds, boolean lastSeen, long sinceTimestamp) { + public List setReadSince(Map threadIdToSinceTimestamp, boolean lastSeen) { SQLiteDatabase db = databaseHelper.getWritableDatabase(); List smsRecords = new LinkedList<>(); @@ -392,11 +393,14 @@ public class ThreadDatabase extends Database { ContentValues contentValues = new ContentValues(2); contentValues.put(READ, ReadStatus.READ.serialize()); - if (lastSeen) { - contentValues.put(LAST_SEEN, sinceTimestamp == -1 ? System.currentTimeMillis() : sinceTimestamp); - } + for (Map.Entry entry : threadIdToSinceTimestamp.entrySet()) { + long threadId = entry.getKey(); + long sinceTimestamp = entry.getValue(); + + if (lastSeen) { + contentValues.put(LAST_SEEN, sinceTimestamp == -1 ? System.currentTimeMillis() : sinceTimestamp); + } - for (long threadId : threadIds) { ThreadRecord previous = getThreadRecord(threadId); smsRecords.addAll(DatabaseFactory.getSmsDatabase(context).setMessagesReadSince(threadId, sinceTimestamp)); @@ -422,7 +426,7 @@ public class ThreadDatabase extends Database { db.endTransaction(); } - notifyConversationListeners(new HashSet<>(threadIds)); + notifyConversationListeners(threadIdToSinceTimestamp.keySet()); notifyConversationListListeners(); if (needsSync) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index eebdea3c81..e071832ad5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -14,13 +14,11 @@ import com.annimon.stream.Stream; import org.signal.core.util.logging.Log; import org.signal.ringrtc.CallId; import org.signal.zkgroup.profiles.ProfileKey; -import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.attachments.PointerAttachment; import org.thoughtcrime.securesms.attachments.TombstoneAttachment; import org.thoughtcrime.securesms.attachments.UriAttachment; -import org.thoughtcrime.securesms.components.emoji.Emoji; import org.thoughtcrime.securesms.components.emoji.EmojiUtil; import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.contactshare.ContactModelMapper; @@ -84,6 +82,7 @@ import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage; import org.thoughtcrime.securesms.mms.QuoteModel; import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.mms.StickerSlide; +import org.thoughtcrime.securesms.notifications.MarkReadReceiver; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.payments.MobileCoinPublicAddress; import org.thoughtcrime.securesms.recipients.Recipient; @@ -143,6 +142,7 @@ import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -987,9 +987,14 @@ public final class MessageContentProcessor { private void handleSynchronizeReadMessage(@NonNull List readMessages, long envelopeTimestamp) { + Map threadToLatestRead = new HashMap<>(); for (ReadMessage readMessage : readMessages) { - List> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.externalPush(context, readMessage.getSender()).getId(), readMessage.getTimestamp()), envelopeTimestamp); - List> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.externalPush(context, readMessage.getSender()).getId(), readMessage.getTimestamp()), envelopeTimestamp); + List> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.externalPush(context, readMessage.getSender()).getId(), readMessage.getTimestamp()), + envelopeTimestamp, + threadToLatestRead); + List> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(Recipient.externalPush(context, readMessage.getSender()).getId(), readMessage.getTimestamp()), + envelopeTimestamp, + threadToLatestRead); for (Pair expiringMessage : expiringText) { ApplicationDependencies.getExpiringMessageManager() @@ -1002,6 +1007,12 @@ public final class MessageContentProcessor { } } + List markedMessages = DatabaseFactory.getThreadDatabase(context).setReadSince(threadToLatestRead, false); + if (Util.hasItems(markedMessages)) { + Log.i(TAG, "Updating past messages: " + markedMessages.size()); + MarkReadReceiver.process(context, markedMessages); + } + MessageNotifier messageNotifier = ApplicationDependencies.getMessageNotifier(); messageNotifier.setLastDesktopActivityTimestamp(envelopeTimestamp); messageNotifier.cancelDelayedNotifications();