Improve mention notifications by only showing alerting notifications once.

This commit is contained in:
Cody Henthorne
2020-11-11 14:49:48 -05:00
parent 3bb366ee04
commit 696fffb603
13 changed files with 118 additions and 42 deletions

View File

@@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -335,6 +336,20 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
return false;
}
public void setNotifiedTimestamp(long timestamp, @NonNull List<Long> ids) {
if (ids.isEmpty()) {
return;
}
SQLiteDatabase db = databaseHelper.getWritableDatabase();
SqlUtil.Query where = SqlUtil.buildCollectionQuery(ID, ids);
ContentValues values = new ContentValues();
values.put(NOTIFIED_TIMESTAMP, timestamp);
db.update(getTableName(), values, where.getWhere(), where.getWhereArgs());
}
public void addMismatchedIdentity(long messageId, @NonNull RecipientId recipientId, IdentityKey identityKey) {
try {
addToDocument(messageId, MISMATCHED_IDENTITIES,

View File

@@ -183,7 +183,8 @@ public class MmsDatabase extends MessageDatabase {
REACTIONS_UNREAD + " INTEGER DEFAULT 0, " +
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1, " +
REMOTE_DELETED + " INTEGER DEFAULT 0, " +
MENTIONS_SELF + " INTEGER DEFAULT 0);";
MENTIONS_SELF + " INTEGER DEFAULT 0, " +
NOTIFIED_TIMESTAMP + " INTEGER DEFAULT 0);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
@@ -208,7 +209,7 @@ public class MmsDatabase extends MessageDatabase {
DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID,
EXPIRES_IN, EXPIRE_STARTED, NOTIFIED, QUOTE_ID, QUOTE_AUTHOR, QUOTE_BODY, QUOTE_ATTACHMENT, QUOTE_MISSING, QUOTE_MENTIONS,
SHARED_CONTACTS, LINK_PREVIEWS, UNIDENTIFIED, VIEW_ONCE, REACTIONS, REACTIONS_UNREAD, REACTIONS_LAST_SEEN,
REMOTE_DELETED, MENTIONS_SELF,
REMOTE_DELETED, MENTIONS_SELF, NOTIFIED_TIMESTAMP,
"json_group_array(json_object(" +
"'" + AttachmentDatabase.ROW_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " +
"'" + AttachmentDatabase.UNIQUE_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " +
@@ -1794,7 +1795,8 @@ public class MmsDatabase extends MessageDatabase {
false,
Collections.emptyList(),
false,
false);
false,
0);
}
}
@@ -1892,6 +1894,7 @@ public class MmsDatabase extends MessageDatabase {
boolean remoteDelete = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.REMOTE_DELETED)) == 1;
List<ReactionRecord> reactions = parseReactions(cursor);
boolean mentionsSelf = CursorUtil.requireBoolean(cursor, MENTIONS_SELF);
long notifiedTimestamp = CursorUtil.requireLong(cursor, NOTIFIED_TIMESTAMP);
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
readReceiptCount = 0;
@@ -1913,7 +1916,7 @@ public class MmsDatabase extends MessageDatabase {
threadId, body, slideDeck, partCount, box, mismatches,
networkFailures, subscriptionId, expiresIn, expireStarted,
isViewOnce, readReceiptCount, quote, contacts, previews, unidentified, reactions,
remoteDelete, mentionsSelf);
remoteDelete, mentionsSelf, notifiedTimestamp);
}
private List<IdentityKeyMismatch> getMismatchedIdentities(String document) {

View File

@@ -20,6 +20,7 @@ public interface MmsSmsColumns {
public static final String EXPIRES_IN = "expires_in";
public static final String EXPIRE_STARTED = "expire_started";
public static final String NOTIFIED = "notified";
public static final String NOTIFIED_TIMESTAMP = "notified_timestamp";
public static final String UNIDENTIFIED = "unidentified";
public static final String REACTIONS = "reactions";
public static final String REACTIONS_UNREAD = "reactions_unread";

View File

@@ -100,7 +100,8 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.REACTIONS_UNREAD,
MmsSmsColumns.REACTIONS_LAST_SEEN,
MmsSmsColumns.REMOTE_DELETED,
MmsDatabase.MENTIONS_SELF};
MmsDatabase.MENTIONS_SELF,
MmsSmsColumns.NOTIFIED_TIMESTAMP};
public MmsSmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
@@ -466,6 +467,11 @@ public class MmsSmsDatabase extends Database {
return 0;
}
public void setNotifiedTimestamp(long timestamp, @NonNull List<Long> smsIds, @NonNull List<Long> mmsIds) {
DatabaseFactory.getSmsDatabase(context).setNotifiedTimestamp(timestamp, smsIds);
DatabaseFactory.getMmsDatabase(context).setNotifiedTimestamp(timestamp, mmsIds);
}
public void deleteMessagesInThreadBeforeDate(long threadId, long trimBeforeDate) {
Log.d(TAG, "deleteMessagesInThreadBeforeData(" + threadId + ", " + trimBeforeDate + ")");
DatabaseFactory.getSmsDatabase(context).deleteMessagesInThreadBeforeDate(threadId, trimBeforeDate);
@@ -539,7 +545,8 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.REACTIONS_LAST_SEEN,
MmsSmsColumns.DATE_SERVER,
MmsSmsColumns.REMOTE_DELETED,
MmsDatabase.MENTIONS_SELF };
MmsDatabase.MENTIONS_SELF,
MmsSmsColumns.NOTIFIED_TIMESTAMP };
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
@@ -573,7 +580,8 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.REACTIONS_LAST_SEEN,
MmsSmsColumns.DATE_SERVER,
MmsSmsColumns.REMOTE_DELETED,
MmsDatabase.MENTIONS_SELF };
MmsDatabase.MENTIONS_SELF,
MmsSmsColumns.NOTIFIED_TIMESTAMP };
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
@@ -628,6 +636,7 @@ public class MmsSmsDatabase extends Database {
mmsColumnsPresent.add(MmsDatabase.REACTIONS_LAST_SEEN);
mmsColumnsPresent.add(MmsDatabase.REMOTE_DELETED);
mmsColumnsPresent.add(MmsDatabase.MENTIONS_SELF);
mmsColumnsPresent.add(MmsSmsColumns.NOTIFIED_TIMESTAMP);
Set<String> smsColumnsPresent = new HashSet<>();
smsColumnsPresent.add(MmsSmsColumns.ID);
@@ -654,6 +663,7 @@ public class MmsSmsDatabase extends Database {
smsColumnsPresent.add(SmsDatabase.REACTIONS_UNREAD);
smsColumnsPresent.add(SmsDatabase.REACTIONS_LAST_SEEN);
smsColumnsPresent.add(MmsDatabase.REMOTE_DELETED);
smsColumnsPresent.add(MmsSmsColumns.NOTIFIED_TIMESTAMP);
@SuppressWarnings("deprecation")
String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 4, MMS_TRANSPORT, selection, null, MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID, null);

View File

@@ -53,6 +53,7 @@ import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.tracing.Trace;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.CursorUtil;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -118,7 +119,8 @@ public class SmsDatabase extends MessageDatabase {
REACTIONS + " BLOB DEFAULT NULL, " +
REACTIONS_UNREAD + " INTEGER DEFAULT 0, " +
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1, " +
REMOTE_DELETED + " INTEGER DEFAULT 0);";
REMOTE_DELETED + " INTEGER DEFAULT 0, " +
NOTIFIED_TIMESTAMP + " INTEGER DEFAULT 0);";
public static final String[] CREATE_INDEXS = {
"CREATE INDEX IF NOT EXISTS sms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
@@ -140,7 +142,7 @@ public class SmsDatabase extends MessageDatabase {
REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, DELIVERY_RECEIPT_COUNT,
MISMATCHED_IDENTITIES, SUBSCRIPTION_ID, EXPIRES_IN, EXPIRE_STARTED,
NOTIFIED, READ_RECEIPT_COUNT, UNIDENTIFIED, REACTIONS, REACTIONS_UNREAD, REACTIONS_LAST_SEEN,
REMOTE_DELETED
REMOTE_DELETED, NOTIFIED_TIMESTAMP
};
private final String OUTGOING_INSECURE_MESSAGE_CLAUSE = "(" + TYPE + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE + " AND NOT (" + TYPE + " & " + Types.SECURE_MESSAGE_BIT + ")";
@@ -1271,7 +1273,8 @@ public class SmsDatabase extends MessageDatabase {
0,
false,
Collections.emptyList(),
false);
false,
0);
}
}
@@ -1317,6 +1320,7 @@ public class SmsDatabase extends MessageDatabase {
boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.UNIDENTIFIED)) == 1;
boolean remoteDelete = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.REMOTE_DELETED)) == 1;
List<ReactionRecord> reactions = parseReactions(cursor);
long notifiedTimestamp = CursorUtil.requireLong(cursor, NOTIFIED_TIMESTAMP);
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
readReceiptCount = 0;
@@ -1331,7 +1335,8 @@ public class SmsDatabase extends MessageDatabase {
dateSent, dateReceived, dateServer, deliveryReceiptCount, type,
threadId, status, mismatches, subscriptionId,
expiresIn, expireStarted,
readReceiptCount, unidentified, reactions, remoteDelete);
readReceiptCount, unidentified, reactions, remoteDelete,
notifiedTimestamp);
}
private List<IdentityKeyMismatch> getMismatches(String document) {

View File

@@ -64,7 +64,6 @@ import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Triple;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -159,8 +158,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int REACTION_CLEANUP = 78;
private static final int CAPABILITIES_REFACTOR = 79;
private static final int GV1_MIGRATION = 80;
private static final int NOTIFIED_TIMESTAMP = 81;
private static final int DATABASE_VERSION = 80;
private static final int DATABASE_VERSION = 81;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
@@ -1160,6 +1160,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
Log.i(TAG, "Updated " + count + " GV1 groups with expected GV2 IDs.");
}
if (oldVersion < NOTIFIED_TIMESTAMP) {
db.execSQL("ALTER TABLE sms ADD COLUMN notified_timestamp INTEGER DEFAULT 0");
db.execSQL("ALTER TABLE mms ADD COLUMN notified_timestamp INTEGER DEFAULT 0");
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();

View File

@@ -73,12 +73,13 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
boolean unidentified,
@NonNull List<ReactionRecord> reactions,
boolean remoteDelete,
boolean mentionsSelf)
boolean mentionsSelf,
long notifiedTimestamp)
{
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent,
dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures,
subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck,
readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions, remoteDelete);
readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions, remoteDelete, notifiedTimestamp);
this.partCount = partCount;
this.mentionsSelf = mentionsSelf;
}

View File

@@ -80,6 +80,7 @@ public abstract class MessageRecord extends DisplayRecord {
private final List<ReactionRecord> reactions;
private final long serverTimestamp;
private final boolean remoteDelete;
private final long notifiedTimestamp;
MessageRecord(long id, String body, Recipient conversationRecipient,
Recipient individualRecipient, int recipientDeviceId,
@@ -89,7 +90,7 @@ public abstract class MessageRecord extends DisplayRecord {
List<NetworkFailure> networkFailures,
int subscriptionId, long expiresIn, long expireStarted,
int readReceiptCount, boolean unidentified,
@NonNull List<ReactionRecord> reactions, boolean remoteDelete)
@NonNull List<ReactionRecord> reactions, boolean remoteDelete, long notifiedTimestamp)
{
super(body, conversationRecipient, dateSent, dateReceived,
threadId, deliveryStatus, deliveryReceiptCount, type, readReceiptCount);
@@ -105,6 +106,7 @@ public abstract class MessageRecord extends DisplayRecord {
this.reactions = reactions;
this.serverTimestamp = dateServer;
this.remoteDelete = remoteDelete;
this.notifiedTimestamp = notifiedTimestamp;
}
public abstract boolean isMms();
@@ -455,6 +457,10 @@ public abstract class MessageRecord extends DisplayRecord {
return false;
}
public long getNotifiedTimestamp() {
return notifiedTimestamp;
}
public static final class InviteAddState {
private final boolean invited;

View File

@@ -33,9 +33,9 @@ public abstract class MmsMessageRecord extends MessageRecord {
@NonNull SlideDeck slideDeck, int readReceiptCount,
@Nullable Quote quote, @NonNull List<Contact> contacts,
@NonNull List<LinkPreview> linkPreviews, boolean unidentified,
@NonNull List<ReactionRecord> reactions, boolean remoteDelete)
@NonNull List<ReactionRecord> reactions, boolean remoteDelete, long notifiedTimestamp)
{
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, dateServer, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, reactions, remoteDelete);
super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, dateServer, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, reactions, remoteDelete, notifiedTimestamp);
this.slideDeck = slideDeck;
this.quote = quote;

View File

@@ -23,8 +23,6 @@ import android.text.SpannableString;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
@@ -58,7 +56,7 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord {
dateSent, dateReceived, -1, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox,
new LinkedList<>(), new LinkedList<>(), subscriptionId,
0, 0, false, slideDeck, readReceiptCount, null, Collections.emptyList(), Collections.emptyList(), false,
Collections.emptyList(), false);
Collections.emptyList(), false, 0);
this.contentLocation = contentLocation;
this.messageSize = messageSize;

View File

@@ -49,12 +49,13 @@ public class SmsMessageRecord extends MessageRecord {
int status, List<IdentityKeyMismatch> mismatches,
int subscriptionId, long expiresIn, long expireStarted,
int readReceiptCount, boolean unidentified,
@NonNull List<ReactionRecord> reactions, boolean remoteDelete)
@NonNull List<ReactionRecord> reactions, boolean remoteDelete,
long notifiedTimestamp)
{
super(id, body, recipient, individualRecipient, recipientDeviceId,
dateSent, dateReceived, dateServer, threadId, status, deliveryReceiptCount, type,
mismatches, new LinkedList<>(), subscriptionId,
expiresIn, expireStarted, readReceiptCount, unidentified, reactions, remoteDelete);
expiresIn, expireStarted, readReceiptCount, unidentified, reactions, remoteDelete, notifiedTimestamp);
}
public long getType() {

View File

@@ -39,6 +39,8 @@ import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.contactshare.ContactUtil;
@@ -71,6 +73,7 @@ import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder;
import org.whispersystems.signalservice.internal.util.Util;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
@@ -281,8 +284,9 @@ public class DefaultMessageNotifier implements MessageNotifier {
boolean signal,
int reminderCount)
{
Cursor telcoCursor = null;
Cursor pushCursor = null;
boolean isReminder = reminderCount > 0;
Cursor telcoCursor = null;
Cursor pushCursor = null;
try {
telcoCursor = DatabaseFactory.getMmsSmsDatabase(context).getUnread();
@@ -305,6 +309,8 @@ public class DefaultMessageNotifier implements MessageNotifier {
lastAudibleNotification = System.currentTimeMillis();
}
boolean shouldScheduleReminder = signal;
if (notificationState.hasMultipleThreads()) {
if (Build.VERSION.SDK_INT >= 23) {
for (long threadId : notificationState.getThreads()) {
@@ -312,14 +318,15 @@ public class DefaultMessageNotifier implements MessageNotifier {
sendSingleThreadNotification(context,
new NotificationState(notificationState.getNotificationsForThread(threadId)),
signal && (threadId == targetThread),
true);
true,
isReminder);
}
}
}
sendMultipleThreadNotification(context, notificationState, signal && (Build.VERSION.SDK_INT < 23));
} else {
sendSingleThreadNotification(context, notificationState, signal, false);
shouldScheduleReminder = sendSingleThreadNotification(context, notificationState, signal, false, isReminder);
if (isDisplayingSummaryNotification(context)) {
sendMultipleThreadNotification(context, notificationState, false);
@@ -329,7 +336,18 @@ public class DefaultMessageNotifier implements MessageNotifier {
cancelOrphanedNotifications(context, notificationState);
updateBadge(context, notificationState.getMessageCount());
if (signal) {
List<Long> smsIds = new LinkedList<>();
List<Long> mmsIds = new LinkedList<>();
for (NotificationItem item : notificationState.getNotifications()) {
if (item.isMms()) {
mmsIds.add(item.getId());
} else {
smsIds.add(item.getId());
}
}
DatabaseFactory.getMmsSmsDatabase(context).setNotifiedTimestamp(System.currentTimeMillis(), smsIds, mmsIds);
if (shouldScheduleReminder) {
scheduleReminder(context, reminderCount);
}
} finally {
@@ -338,23 +356,25 @@ public class DefaultMessageNotifier implements MessageNotifier {
}
}
private static void sendSingleThreadNotification(@NonNull Context context,
@NonNull NotificationState notificationState,
boolean signal,
boolean bundled)
private static boolean sendSingleThreadNotification(@NonNull Context context,
@NonNull NotificationState notificationState,
boolean signal,
boolean bundled,
boolean isReminder)
{
Log.i(TAG, "sendSingleThreadNotification() signal: " + signal + " bundled: " + bundled);
if (notificationState.getNotifications().isEmpty()) {
if (!bundled) cancelActiveNotifications(context);
Log.i(TAG, "[sendSingleThreadNotification] Empty notification state. Skipping.");
return;
return false;
}
NotificationPrivacyPreference notificationPrivacy = TextSecurePreferences.getNotificationPrivacy(context);
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, notificationPrivacy);
List<NotificationItem> notifications = notificationState.getNotifications();
Recipient recipient = notifications.get(0).getRecipient();
boolean shouldAlert = signal && (isReminder || Stream.of(notifications).anyMatch(item -> item.getNotifiedTimestamp() == 0));
int notificationId;
if (Build.VERSION.SDK_INT >= 23) {
@@ -369,7 +389,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
notifications.get(0).getText(), notifications.get(0).getSlideDeck());
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
builder.setDeleteIntent(notificationState.getDeleteIntent(context));
builder.setOnlyAlertOnce(!signal);
builder.setOnlyAlertOnce(!shouldAlert);
builder.setSortKey(String.valueOf(Long.MAX_VALUE - notifications.get(0).getTimestamp()));
long timestamp = notifications.get(0).getTimestamp();
@@ -418,6 +438,8 @@ public class DefaultMessageNotifier implements MessageNotifier {
Notification notification = builder.build();
NotificationManagerCompat.from(context).notify(notificationId, notification);
Log.i(TAG, "Posted notification.");
return shouldAlert;
}
private static void sendMultipleThreadNotification(@NonNull Context context,
@@ -434,11 +456,12 @@ public class DefaultMessageNotifier implements MessageNotifier {
NotificationPrivacyPreference notificationPrivacy = TextSecurePreferences.getNotificationPrivacy(context);
MultipleRecipientNotificationBuilder builder = new MultipleRecipientNotificationBuilder(context, notificationPrivacy);
List<NotificationItem> notifications = notificationState.getNotifications();
boolean shouldAlert = signal && Stream.of(notifications).anyMatch(item -> item.getNotifiedTimestamp() == 0);
builder.setMessageCount(notificationState.getMessageCount(), notificationState.getThreadCount());
builder.setMostRecentSender(notifications.get(0).getIndividualRecipient());
builder.setDeleteIntent(notificationState.getDeleteIntent(context));
builder.setOnlyAlertOnce(!signal);
builder.setOnlyAlertOnce(!shouldAlert);
if (Build.VERSION.SDK_INT >= 23) {
builder.setGroup(NOTIFICATION_GROUP);
@@ -531,6 +554,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
boolean isUnreadMessage = cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.READ)) == 0;
boolean hasUnreadReactions = cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.REACTIONS_UNREAD)) == 1;
long lastReactionRead = cursor.getLong(cursor.getColumnIndexOrThrow(MmsSmsColumns.REACTIONS_LAST_SEEN));
long notifiedTimestamp = record.getNotifiedTimestamp();
if (threadId != -1) {
threadRecipients = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
@@ -564,7 +588,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
}
if (threadRecipients == null || includeMessage) {
notificationState.addNotification(new NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, receivedTimestamp, slideDeck, false, record.isJoined(), canReply));
notificationState.addNotification(new NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, receivedTimestamp, slideDeck, false, record.isJoined(), canReply, notifiedTimestamp));
}
}
@@ -599,7 +623,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
}
if (threadRecipients == null || !threadRecipients.isMuted()) {
notificationState.addNotification(new NotificationItem(id, mms, reactionSender, conversationRecipient, threadRecipients, threadId, body, reaction.getDateReceived(), receivedTimestamp, null, true, record.isJoined(), false));
notificationState.addNotification(new NotificationItem(id, mms, reactionSender, conversationRecipient, threadRecipients, threadId, body, reaction.getDateReceived(), receivedTimestamp, null, true, record.isJoined(), false, 0));
}
}
}

View File

@@ -23,12 +23,13 @@ public class NotificationItem {
@Nullable private final Recipient threadRecipient;
private final long threadId;
@Nullable private final CharSequence text;
private final long notificationTimestamp;
private final long timestamp;
private final long messageReceivedTimestamp;
@Nullable private final SlideDeck slideDeck;
private final boolean jumpToMessage;
private final boolean isJoin;
private final boolean canReply;
private final long notifiedTimestamp;
public NotificationItem(long id,
boolean mms,
@@ -37,12 +38,13 @@ public class NotificationItem {
@Nullable Recipient threadRecipient,
long threadId,
@Nullable CharSequence text,
long notificationTimestamp,
long timestamp,
long messageReceivedTimestamp,
@Nullable SlideDeck slideDeck,
boolean jumpToMessage,
boolean isJoin,
boolean canReply)
boolean canReply,
long notifiedTimestamp)
{
this.id = id;
this.mms = mms;
@@ -51,12 +53,13 @@ public class NotificationItem {
this.threadRecipient = threadRecipient;
this.text = text;
this.threadId = threadId;
this.notificationTimestamp = notificationTimestamp;
this.timestamp = timestamp;
this.messageReceivedTimestamp = messageReceivedTimestamp;
this.slideDeck = slideDeck;
this.jumpToMessage = jumpToMessage;
this.isJoin = isJoin;
this.canReply = canReply;
this.notifiedTimestamp = notifiedTimestamp;
}
public @NonNull Recipient getRecipient() {
@@ -72,7 +75,7 @@ public class NotificationItem {
}
public long getTimestamp() {
return notificationTimestamp;
return timestamp;
}
public long getThreadId() {
@@ -119,4 +122,8 @@ public class NotificationItem {
public boolean canReply() {
return canReply;
}
public long getNotifiedTimestamp() {
return notifiedTimestamp;
}
}