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 01b323c4f3..1e08b54d94 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -1029,9 +1029,14 @@ public class SmsDatabase extends MessageDatabase { groupRecipient = Recipient.resolved(id); } - boolean unread = (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) || - message.isSecureMessage() || message.isGroup() || message.isPreKeyBundle()) && - !message.isIdentityUpdate() && !message.isIdentityDefault() && !message.isIdentityVerified(); + boolean silent = message.isIdentityUpdate() || + message.isIdentityVerified() || + message.isIdentityDefault() || + message.isJustAGroupLeave(); + boolean unread = !silent && (Util.isDefaultSmsProvider(context) || + message.isSecureMessage() || + message.isGroup() || + message.isPreKeyBundle()); long threadId; @@ -1070,7 +1075,7 @@ public class SmsDatabase extends MessageDatabase { DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1); } - if (!message.isIdentityUpdate() && !message.isIdentityVerified() && !message.isIdentityDefault()) { + if (!silent) { DatabaseFactory.getThreadDatabase(context).update(threadId, true); } @@ -1080,7 +1085,7 @@ public class SmsDatabase extends MessageDatabase { notifyConversationListeners(threadId); - if (!message.isIdentityUpdate() && !message.isIdentityVerified() && !message.isIdentityDefault()) { + if (!silent) { ApplicationDependencies.getJobManager().add(new TrimThreadJob(threadId)); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java b/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java index 2aa3ae29f9..3757f3c7a7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/MessageGroupContext.java @@ -163,6 +163,10 @@ public final class MessageGroupContext { return groupMasterKey; } + public @NonNull DecryptedGroupChange getChange() { + return decryptedGroupV2Context.getChange(); + } + public @NonNull List getAllActivePendingAndRemovedMembers() { LinkedList memberUuids = new LinkedList<>(); DecryptedGroup groupState = decryptedGroupV2Context.getGroupState(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingGroupUpdateMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingGroupUpdateMessage.java index 3f526638ea..ad92536fb7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingGroupUpdateMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingGroupUpdateMessage.java @@ -1,7 +1,11 @@ package org.thoughtcrime.securesms.sms; +import androidx.annotation.NonNull; + +import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context; import org.thoughtcrime.securesms.mms.MessageGroupContext; +import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil; import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext; @@ -39,4 +43,28 @@ public final class IncomingGroupUpdateMessage extends IncomingTextMessage { return !groupContext.isV2Group() && groupContext.requireGroupV1Properties().isQuit(); } + @Override + public boolean isJustAGroupLeave() { + if (isGroupV2() && isUpdate()) { + DecryptedGroupChange decryptedGroupChange = groupContext.requireGroupV2Properties() + .getChange(); + + return changeEditorOnlyWasRemoved(decryptedGroupChange) && + noChangesOtherThanDeletes(decryptedGroupChange); + } + + return false; + } + + protected boolean changeEditorOnlyWasRemoved(@NonNull DecryptedGroupChange decryptedGroupChange) { + return decryptedGroupChange.getDeleteMembersCount() == 1 && + decryptedGroupChange.getDeleteMembers(0).equals(decryptedGroupChange.getEditor()); + } + + protected boolean noChangesOtherThanDeletes(@NonNull DecryptedGroupChange decryptedGroupChange) { + DecryptedGroupChange withoutDeletedMembers = decryptedGroupChange.toBuilder() + .clearDeleteMembers() + .build(); + return DecryptedGroupUtil.changeIsEmpty(withoutDeletedMembers); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java index f07ffadd7a..0c978f0935 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java @@ -253,6 +253,13 @@ public class IncomingTextMessage implements Parcelable { return false; } + /** + * @return True iff the message is only a group leave of a single member. + */ + public boolean isJustAGroupLeave() { + return false; + } + public boolean isUnidentified() { return unidentified; }