fix: notifications deduplicate based on last message ID, ConversationActivityV2.kt updates notification by thread ID

This commit is contained in:
Harris 2021-07-21 13:58:07 +10:00
parent 7f047f1c2b
commit ff853e01b4
4 changed files with 67 additions and 41 deletions

View File

@ -24,7 +24,6 @@ import android.widget.Toast
import androidx.annotation.DimenRes import androidx.annotation.DimenRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.get
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider 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.control.DataExtractionNotification
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage 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.OpenGroupInvitation
import org.session.libsession.messaging.messages.visible.Quote.Companion.from
import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.sending_receiving.attachments.Attachment 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.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel 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
import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.MediaTypes import org.session.libsession.utilities.MediaTypes
@ -116,6 +111,23 @@ import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.util.* import org.thoughtcrime.securesms.util.*
import java.util.* import java.util.*
import java.util.concurrent.ExecutionException 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.* import kotlin.math.*
// Some things that seemingly belong to the input bar (e.g. the voice message recording UI) are actually // 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 { } else {
MarkReadReceiver.process(this, messages) MarkReadReceiver.process(this, messages)
} }
ApplicationContext.getInstance(this).messageNotifier.updateNotification(this) ApplicationContext.getInstance(this).messageNotifier.updateNotification(this, threadID)
} }
override fun inputBarHeightChanged(newValue: Int) { override fun inputBarHeightChanged(newValue: Int) {

View File

@ -4,18 +4,21 @@ import android.app.Notification;
import android.content.Context; import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.NonNull; import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.TextUtils; 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.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.TextSecurePreferences;
import org.session.libsession.utilities.Util; 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 { public abstract class AbstractNotificationBuilder extends NotificationCompat.Builder {
@ -26,10 +29,11 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui
protected Context context; protected Context context;
protected NotificationPrivacyPreference privacy; protected NotificationPrivacyPreference privacy;
protected final Bundle extras;
public AbstractNotificationBuilder(Context context, NotificationPrivacyPreference privacy) { public AbstractNotificationBuilder(Context context, NotificationPrivacyPreference privacy) {
super(context); super(context);
extras = new Bundle();
this.context = context; this.context = context;
this.privacy = privacy; this.privacy = privacy;
@ -97,4 +101,10 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui
return text.length() <= MAX_DISPLAY_LENGTH ? text return text.length() <= MAX_DISPLAY_LENGTH ? text
: text.subSequence(0, MAX_DISPLAY_LENGTH); : text.subSequence(0, MAX_DISPLAY_LENGTH);
} }
@Override
public Notification build() {
addExtras(extras);
return super.build();
}
} }

View File

@ -87,6 +87,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
private static final String TAG = DefaultMessageNotifier.class.getSimpleName(); private static final String TAG = DefaultMessageNotifier.class.getSimpleName();
public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply"; 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 FOREGROUND_ID = 313399;
private static final int SUMMARY_NOTIFICATION_ID = 1338; private static final int SUMMARY_NOTIFICATION_ID = 1338;
@ -238,14 +239,6 @@ public class DefaultMessageNotifier implements MessageNotifier {
return; 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) { if (isVisible) {
sendInThreadNotification(context, threads.getRecipientForThreadId(threadId)); sendInThreadNotification(context, threads.getRecipientForThreadId(threadId));
} else if (!homeScreenVisible) { } else if (!homeScreenVisible) {
@ -280,16 +273,9 @@ public class DefaultMessageNotifier implements MessageNotifier {
lastAudibleNotification = System.currentTimeMillis(); lastAudibleNotification = System.currentTimeMillis();
} }
if (notificationState.hasMultipleThreads()) { boolean hasMultipleThreads = notificationState.hasMultipleThreads();
if (Build.VERSION.SDK_INT >= 23) { for (long threadId : notificationState.getThreads()) {
for (long threadId : notificationState.getThreads()) { sendSingleThreadNotification(context, new NotificationState(notificationState.getNotificationsForThread(threadId)), signal, hasMultipleThreads);
sendSingleThreadNotification(context, new NotificationState(notificationState.getNotificationsForThread(threadId)), false, true);
}
}
sendMultipleThreadNotification(context, notificationState, signal);
} else if (notificationState.getMessageCount() > 0){
sendSingleThreadNotification(context, notificationState, signal, false);
} }
cancelOrphanedNotifications(context, notificationState); cancelOrphanedNotifications(context, notificationState);
@ -320,7 +306,20 @@ public class DefaultMessageNotifier implements MessageNotifier {
List<NotificationItem> notifications = notificationState.getNotifications(); List<NotificationItem> notifications = notificationState.getNotifications();
Recipient recipient = notifications.get(0).getRecipient(); Recipient recipient = notifications.get(0).getRecipient();
int notificationId = (int) (SUMMARY_NOTIFICATION_ID + (bundled ? notifications.get(0).getThreadId() : 0)); 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.setThread(notifications.get(0).getRecipient());
builder.setMessageCount(notificationState.getMessageCount()); builder.setMessageCount(notificationState.getMessageCount());
@ -333,11 +332,6 @@ public class DefaultMessageNotifier implements MessageNotifier {
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY); builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
builder.setAutoCancel(true); 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); ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient);
boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient); boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient);

View File

@ -15,33 +15,38 @@ import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationCompat.Action; import androidx.core.app.NotificationCompat.Action;
import androidx.core.app.RemoteInput; import androidx.core.app.RemoteInput;
import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.session.libsession.avatars.ContactColors; import org.session.libsession.avatars.ContactColors;
import org.session.libsession.avatars.ContactPhoto; import org.session.libsession.avatars.ContactPhoto;
import org.session.libsession.avatars.GeneratedContactPhoto; import org.session.libsession.avatars.GeneratedContactPhoto;
import org.session.libsession.messaging.contacts.Contact; 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.session.libsignal.utilities.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.SessionContactDatabase; import org.thoughtcrime.securesms.database.SessionContactDatabase;
import org.thoughtcrime.securesms.util.AvatarPlaceholderGenerator;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.mms.SlideDeck;
import org.session.libsession.utilities.NotificationPrivacyPreference; import org.thoughtcrime.securesms.util.AvatarPlaceholderGenerator;
import org.session.libsession.utilities.recipients.Recipient;
import org.thoughtcrime.securesms.util.BitmapUtil; 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.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import network.loki.messenger.R; import network.loki.messenger.R;
public class SingleRecipientNotificationBuilder extends AbstractNotificationBuilder { public class SingleRecipientNotificationBuilder extends AbstractNotificationBuilder {
@ -58,6 +63,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
{ {
super(context, privacy); super(context, privacy);
setSmallIcon(R.drawable.ic_notification); setSmallIcon(R.drawable.ic_notification);
setColor(context.getResources().getColor(R.color.textsecure_primary)); setColor(context.getResources().getColor(R.color.textsecure_primary));
setCategory(NotificationCompat.CATEGORY_MESSAGE); setCategory(NotificationCompat.CATEGORY_MESSAGE);
@ -198,6 +204,10 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
return R.string.MessageNotifier_reply; return R.string.MessageNotifier_reply;
} }
public void putStringExtra(String key, String value) {
extras.putString(key,value);
}
public void addMessageBody(@NonNull Recipient threadRecipient, public void addMessageBody(@NonNull Recipient threadRecipient,
@NonNull Recipient individualRecipient, @NonNull Recipient individualRecipient,
@Nullable CharSequence messageBody) @Nullable CharSequence messageBody)