Do not re-notify dismissed notifications

Stephen Paul Weber created

Change summary

src/main/java/eu/siacs/conversations/entities/Conversation.java          |  4 
src/main/java/eu/siacs/conversations/entities/Message.java               | 12 
src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java    |  8 
src/main/java/eu/siacs/conversations/services/NotificationService.java   | 12 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 12 
5 files changed, 45 insertions(+), 3 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/Conversation.java 🔗

@@ -385,11 +385,11 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
         }
     }
 
-    public void findUnreadMessagesAndCalls(OnMessageFound onMessageFound) {
+    public void findMessagesAndCallsToNotify(OnMessageFound onMessageFound) {
         final ArrayList<Message> results = new ArrayList<>();
         synchronized (this.messages) {
             for (final Message message : this.messages) {
-                if (message.isRead()) {
+                if (message.isRead() || message.notificationWasDismissed()) {
                     continue;
                 }
                 results.add(message);

src/main/java/eu/siacs/conversations/entities/Message.java 🔗

@@ -152,6 +152,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
     protected List<Edit> edits = new ArrayList<>();
     protected String relativeFilePath;
     protected boolean read = true;
+    protected boolean notificationDismissed = false;
     protected String remoteMsgId = null;
     private String bodyLanguage = null;
     protected String serverMsgId = null;
@@ -329,6 +330,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
         );
         final var legacyOccupant = cursor.getString(cursor.getColumnIndex("occupant_id"));
         if (legacyOccupant != null) m.setOccupantId(legacyOccupant);
+        if (cursor.getInt(cursor.getColumnIndex("notificationDismissed")) > 0) m.markNotificationDismissed();
         return m;
     }
 
@@ -374,6 +376,8 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
         }
         values.put("payloads", payloads.size() < 1 ? null : payloads.stream().map(Object::toString).collect(Collectors.joining()));
         values.put("occupant_id", occupantId);
+        values.put("timeReceived", timeReceived);
+        values.put("notificationDismissed", notificationDismissed ? 1 : 0);
         return values;
     }
 
@@ -770,6 +774,10 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
         return this.read;
     }
 
+    public boolean notificationWasDismissed() {
+        return this.notificationDismissed;
+    }
+
     public boolean isDeleted() {
         return this.deleted;
     }
@@ -798,6 +806,10 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
         this.read = false;
     }
 
+    public void markNotificationDismissed() {
+        this.notificationDismissed = true;
+	}
+
     public void setTime(long time) {
         this.timeSent = time;
     }

src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java 🔗

@@ -363,6 +363,14 @@ public class DatabaseBackend extends SQLiteOpenHelper {
                 db.execSQL("PRAGMA cheogram.user_version = 11");
             }
 
+            if(cheogramVersion < 12) {
+                db.execSQL(
+                    "ALTER TABLE cheogram." + Message.TABLENAME + " " +
+                    "ADD COLUMN notificationDismissed NUMBER DEFAULT 0"
+                );
+                db.execSQL("PRAGMA cheogram.user_version = 12");
+            }
+
             db.setTransactionSuccessful();
         } finally {
             db.endTransaction();

src/main/java/eu/siacs/conversations/services/NotificationService.java 🔗

@@ -874,6 +874,7 @@ public class NotificationService {
         synchronized (notifications) {
             for (ArrayList<Message> messages : notifications.values()) {
                 markAsReadIfHasDirectReply(messages);
+                markAsNotificationDismissed(messages);
             }
             notifications.clear();
             updateNotification(false);
@@ -886,6 +887,7 @@ public class NotificationService {
         }
         synchronized (notifications) {
             markAsReadIfHasDirectReply(conversation);
+            markAsNotificationDismissed(conversation);
             if (notifications.remove(conversation.getUuid()) != null) {
                 cancel(conversation.getUuid(), NOTIFICATION_ID);
                 updateNotification(false, null, true);
@@ -950,6 +952,16 @@ public class NotificationService {
         }
     }
 
+    private void markAsNotificationDismissed(final Conversation conversation) {
+        markAsNotificationDismissed(notifications.get(conversation.getUuid()));
+    }
+
+    private void markAsNotificationDismissed(final ArrayList<Message> messages) {
+        if (messages != null && !messages.isEmpty()) {
+            mXmppConnectionService.markNotificationDismissed(messages);
+        }
+    }
+
     private void setNotificationColor(final Builder mBuilder, Account account) {
         int color;
         if (account != null && mXmppConnectionService.getAccounts().size() > 1) {

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -2596,7 +2596,7 @@ public class XmppConnectionService extends Service {
     private void restoreMessages(Conversation conversation) {
         conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE));
         conversation.findUnsentTextMessages(message -> markMessage(message, Message.STATUS_WAITING));
-        conversation.findUnreadMessagesAndCalls(mNotificationService::pushFromBacklog);
+        conversation.findMessagesAndCallsToNotify(mNotificationService::pushFromBacklog);
     }
 
     public void loadPhoneContacts() {
@@ -5187,6 +5187,16 @@ public class XmppConnectionService extends Service {
         }
     }
 
+    public void markNotificationDismissed(final List<Message> messages) {
+        Runnable runnable = () -> {
+            for (final var message : messages) {
+                message.markNotificationDismissed();
+                databaseBackend.updateMessage(message, false);
+            }
+        };
+        mDatabaseWriterExecutor.execute(runnable);
+    }
+
     public synchronized void updateUnreadCountBadge() {
         int count = unreadCount();
         if (unreadCount != count) {