From ff853e01b42f218dd02337734a426b18162ed62c Mon Sep 17 00:00:00 2001 From: Harris Date: Wed, 21 Jul 2021 13:58:07 +1000 Subject: [PATCH] fix: notifications deduplicate based on last message ID, ConversationActivityV2.kt updates notification by thread ID --- .../conversation/v2/ConversationActivityV2.kt | 24 ++++++++--- .../AbstractNotificationBuilder.java | 24 +++++++---- .../notifications/DefaultMessageNotifier.java | 40 ++++++++----------- .../SingleRecipientNotificationBuilder.java | 20 +++++++--- 4 files changed, 67 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index f57726bcb2..b85759f314 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -24,7 +24,6 @@ import android.widget.Toast import androidx.annotation.DimenRes import androidx.appcompat.app.AlertDialog import androidx.core.view.children -import androidx.core.view.get import androidx.core.view.isVisible import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider @@ -53,17 +52,13 @@ import org.session.libsession.messaging.mentions.MentionsManager import org.session.libsession.messaging.messages.control.DataExtractionNotification import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage import org.session.libsession.messaging.messages.signal.OutgoingTextMessage -import org.session.libsession.messaging.messages.visible.LinkPreview.Companion.from import org.session.libsession.messaging.messages.visible.OpenGroupInvitation -import org.session.libsession.messaging.messages.visible.Quote.Companion.from import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel -import org.session.libsession.messaging.utilities.UpdateMessageData -import org.session.libsession.messaging.utilities.UpdateMessageData.Companion.fromJSON import org.session.libsession.utilities.Address import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.MediaTypes @@ -116,6 +111,23 @@ import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.util.* import java.util.* import java.util.concurrent.ExecutionException +import kotlin.collections.List +import kotlin.collections.Set +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.filter +import kotlin.collections.find +import kotlin.collections.first +import kotlin.collections.forEach +import kotlin.collections.indices +import kotlin.collections.isNotEmpty +import kotlin.collections.iterator +import kotlin.collections.listOf +import kotlin.collections.mutableListOf +import kotlin.collections.mutableMapOf +import kotlin.collections.set +import kotlin.collections.sortedBy +import kotlin.collections.toTypedArray import kotlin.math.* // Some things that seemingly belong to the input bar (e.g. the voice message recording UI) are actually @@ -502,7 +514,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } else { MarkReadReceiver.process(this, messages) } - ApplicationContext.getInstance(this).messageNotifier.updateNotification(this) + ApplicationContext.getInstance(this).messageNotifier.updateNotification(this, threadID) } override fun inputBarHeightChanged(newValue: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/AbstractNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/AbstractNotificationBuilder.java index 89296691fa..a359596c91 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/AbstractNotificationBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/AbstractNotificationBuilder.java @@ -4,18 +4,21 @@ import android.app.Notification; import android.content.Context; import android.graphics.Color; import android.net.Uri; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; +import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.TextUtils; -import network.loki.messenger.R; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; + import org.session.libsession.utilities.NotificationPrivacyPreference; -import org.session.libsession.utilities.recipients.Recipient; -import org.session.libsession.utilities.recipients.Recipient.*; import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.Util; +import org.session.libsession.utilities.recipients.Recipient; +import org.session.libsession.utilities.recipients.Recipient.VibrateState; + +import network.loki.messenger.R; public abstract class AbstractNotificationBuilder extends NotificationCompat.Builder { @@ -26,10 +29,11 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui protected Context context; protected NotificationPrivacyPreference privacy; + protected final Bundle extras; public AbstractNotificationBuilder(Context context, NotificationPrivacyPreference privacy) { super(context); - + extras = new Bundle(); this.context = context; this.privacy = privacy; @@ -97,4 +101,10 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui return text.length() <= MAX_DISPLAY_LENGTH ? text : text.subSequence(0, MAX_DISPLAY_LENGTH); } + + @Override + public Notification build() { + addExtras(extras); + return super.build(); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java index e06a1c153c..bdcf916dd4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java @@ -87,6 +87,7 @@ public class DefaultMessageNotifier implements MessageNotifier { private static final String TAG = DefaultMessageNotifier.class.getSimpleName(); public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply"; + public static final String LATEST_MESSAGE_ID_TAG = "extra_latest_message_id"; private static final int FOREGROUND_ID = 313399; private static final int SUMMARY_NOTIFICATION_ID = 1338; @@ -238,14 +239,6 @@ public class DefaultMessageNotifier implements MessageNotifier { return; } - if (recipients != null && recipients.notifyType != RecipientDatabase.NOTIFY_TYPE_ALL) { - // if mentions and no mention then return - if (recipients.notifyType == RecipientDatabase.NOTIFY_TYPE_MENTIONS) { - - } - return; - } - if (isVisible) { sendInThreadNotification(context, threads.getRecipientForThreadId(threadId)); } else if (!homeScreenVisible) { @@ -280,16 +273,9 @@ public class DefaultMessageNotifier implements MessageNotifier { lastAudibleNotification = System.currentTimeMillis(); } - if (notificationState.hasMultipleThreads()) { - if (Build.VERSION.SDK_INT >= 23) { - for (long threadId : notificationState.getThreads()) { - sendSingleThreadNotification(context, new NotificationState(notificationState.getNotificationsForThread(threadId)), false, true); - } - } - - sendMultipleThreadNotification(context, notificationState, signal); - } else if (notificationState.getMessageCount() > 0){ - sendSingleThreadNotification(context, notificationState, signal, false); + boolean hasMultipleThreads = notificationState.hasMultipleThreads(); + for (long threadId : notificationState.getThreads()) { + sendSingleThreadNotification(context, new NotificationState(notificationState.getNotificationsForThread(threadId)), signal, hasMultipleThreads); } cancelOrphanedNotifications(context, notificationState); @@ -320,7 +306,20 @@ public class DefaultMessageNotifier implements MessageNotifier { List notifications = notificationState.getNotifications(); Recipient recipient = notifications.get(0).getRecipient(); int notificationId = (int) (SUMMARY_NOTIFICATION_ID + (bundled ? notifications.get(0).getThreadId() : 0)); + String messageIdTag = String.valueOf(notifications.get(0).getId()); + NotificationManager notificationManager = ServiceUtil.getNotificationManager(context); + for (StatusBarNotification notification: notificationManager.getActiveNotifications()) { + + if (messageIdTag.equals(notification.getNotification().extras.getString(LATEST_MESSAGE_ID_TAG))) { + return; + } + } + + long timestamp = notifications.get(0).getTimestamp(); + if (timestamp != 0) builder.setWhen(timestamp); + + builder.putStringExtra(LATEST_MESSAGE_ID_TAG, messageIdTag); builder.setThread(notifications.get(0).getRecipient()); builder.setMessageCount(notificationState.getMessageCount()); @@ -333,11 +332,6 @@ public class DefaultMessageNotifier implements MessageNotifier { builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY); builder.setAutoCancel(true); - long timestamp = notifications.get(0).getTimestamp(); - if (timestamp != 0) builder.setWhen(timestamp); - - long threadID = notifications.get(0).getThreadId(); - ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient); boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient); diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java index 80dd7d2602..7bd4ef4998 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java @@ -15,33 +15,38 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.text.SpannableStringBuilder; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat.Action; import androidx.core.app.RemoteInput; + import com.bumptech.glide.load.engine.DiskCacheStrategy; + import org.session.libsession.avatars.ContactColors; import org.session.libsession.avatars.ContactPhoto; import org.session.libsession.avatars.GeneratedContactPhoto; import org.session.libsession.messaging.contacts.Contact; +import org.session.libsession.utilities.NotificationPrivacyPreference; +import org.session.libsession.utilities.TextSecurePreferences; +import org.session.libsession.utilities.Util; +import org.session.libsession.utilities.recipients.Recipient; import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.SessionContactDatabase; -import org.thoughtcrime.securesms.util.AvatarPlaceholderGenerator; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.SlideDeck; -import org.session.libsession.utilities.NotificationPrivacyPreference; -import org.session.libsession.utilities.recipients.Recipient; +import org.thoughtcrime.securesms.util.AvatarPlaceholderGenerator; import org.thoughtcrime.securesms.util.BitmapUtil; -import org.session.libsession.utilities.TextSecurePreferences; -import org.session.libsession.utilities.Util; + import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; + import network.loki.messenger.R; public class SingleRecipientNotificationBuilder extends AbstractNotificationBuilder { @@ -58,6 +63,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil { super(context, privacy); + setSmallIcon(R.drawable.ic_notification); setColor(context.getResources().getColor(R.color.textsecure_primary)); setCategory(NotificationCompat.CATEGORY_MESSAGE); @@ -198,6 +204,10 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil return R.string.MessageNotifier_reply; } + public void putStringExtra(String key, String value) { + extras.putString(key,value); + } + public void addMessageBody(@NonNull Recipient threadRecipient, @NonNull Recipient individualRecipient, @Nullable CharSequence messageBody)