From f2da047720404da59c911d66db1e3b45924c5392 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 13 Oct 2021 15:36:37 +0100 Subject: [PATCH] keeping an inmemory cache of the seen ids, fixes delayed sync responses causing already dismissed notifications from being shown again - uses a simple circular buffer to limit the memory usage --- .../notifications/CircularStringCache.kt | 36 +++++++++++++++++++ .../NotificationDrawerManager.kt | 19 ++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/notifications/CircularStringCache.kt diff --git a/vector/src/main/java/im/vector/app/features/notifications/CircularStringCache.kt b/vector/src/main/java/im/vector/app/features/notifications/CircularStringCache.kt new file mode 100644 index 0000000000..97b40daf46 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/notifications/CircularStringCache.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.notifications + +/** + * A FIFO circular buffer of strings + */ +class CircularStringCache(cacheSize: Int) { + + private val cache = Array(cacheSize) { "" } + private var writeIndex = 0 + + fun contains(key: String): Boolean = cache.contains(key) + + fun put(key: String) { + if (writeIndex == cache.size - 1) { + writeIndex = 0 + } + cache[writeIndex] = key + writeIndex++ + } +} diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt index ecb1268892..2df093b615 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt @@ -84,6 +84,13 @@ class NotificationDrawerManager @Inject constructor(private val context: Context private var useCompleteNotificationFormat = vectorPreferences.useCompleteNotificationFormat() + /** + * An in memory FIFO cache of the seen events. + * Acts as a notification debouncer to stop already dismissed push notifications from + * displaying again when the /sync response is delayed. + */ + private val seenEventIds = CircularStringCache(cacheSize = 25) + /** Should be called as soon as a new event is ready to be displayed. The notification corresponding to this event will not be displayed until @@ -140,8 +147,14 @@ class NotificationDrawerManager @Inject constructor(private val context: Context // Ignore an edit of a not displayed event in the notification drawer } } else { - // Not an edit - eventList.add(notifiableEvent) + if (seenEventIds.contains(notifiableEvent.eventId)) { + // we've already seen the event, lets' skip + Timber.d("onNotifiableEventReceived(): skipping event, already seen}") + } else { + // Not an edit + seenEventIds.put(notifiableEvent.eventId) + eventList.add(notifiableEvent) + } } } } @@ -266,7 +279,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context is InviteNotifiableEvent -> { if (autoAcceptInvites.hideInvites) { // Forget this event - eventIterator.remove() + eventIterator.remove() } else { invitationEvents.add(event) }