Skip to content

Commit 17cf0ef

Browse files
authored
Merge pull request #6190 from element-hq/feature/bma/fallbackNotificationCleanup
Fallback notification cleanup
2 parents fc6e4e2 + d1d5fb9 commit 17cf0ef

File tree

10 files changed

+375
-73
lines changed

10 files changed

+375
-73
lines changed

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,7 @@ class MessagesPresenterTest {
12381238
}
12391239

12401240
@Test
1241-
fun `present - shows a "world_readable" icon if the room is encrypted and history is world_readable`() = runTest {
1241+
fun `present - shows a 'world_readable' icon if the room is encrypted and history is world_readable`() = runTest {
12421242
val presenter = createMessagesPresenter(
12431243
joinedRoom = FakeJoinedRoom(
12441244
baseRoom = FakeBaseRoom(

libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@ import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
2222
import io.element.android.libraries.push.api.notifications.NotificationCleaner
2323
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
2424
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
25+
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
26+
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
2527
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
26-
import io.element.android.libraries.push.impl.notifications.model.shouldIgnoreEventInRoom
28+
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
29+
import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent
30+
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
2731
import io.element.android.libraries.sessionstorage.api.observer.SessionListener
2832
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
33+
import io.element.android.services.appnavstate.api.AppNavigationState
2934
import io.element.android.services.appnavstate.api.AppNavigationStateService
3035
import io.element.android.services.appnavstate.api.NavigationState
36+
import io.element.android.services.appnavstate.api.currentRoomId
37+
import io.element.android.services.appnavstate.api.currentSessionId
38+
import io.element.android.services.appnavstate.api.currentThreadId
3139
import kotlinx.coroutines.CoroutineScope
3240
import kotlinx.coroutines.launch
3341

@@ -71,7 +79,10 @@ class DefaultNotificationDrawerManager(
7179
private fun onAppNavigationStateChange(navigationState: NavigationState) {
7280
when (navigationState) {
7381
NavigationState.Root -> {}
74-
is NavigationState.Session -> {}
82+
is NavigationState.Session -> {
83+
// Cleanup the fallback notification
84+
clearFallbackForSession(navigationState.sessionId)
85+
}
7586
is NavigationState.Room -> {
7687
// Cleanup notification for current room
7788
clearMessagesForRoom(
@@ -94,14 +105,11 @@ class DefaultNotificationDrawerManager(
94105
* Events might be grouped and there might not be one notification per event!
95106
*/
96107
suspend fun onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
97-
if (notifiableEvent.shouldIgnoreEventInRoom(appNavigationStateService.appNavigationState.value)) {
98-
return
99-
}
100-
renderEvents(listOf(notifiableEvent))
108+
onNotifiableEventsReceived(listOf(notifiableEvent))
101109
}
102110

103111
suspend fun onNotifiableEventsReceived(notifiableEvents: List<NotifiableEvent>) {
104-
val eventsToNotify = notifiableEvents.filter { !it.shouldIgnoreEventInRoom(appNavigationStateService.appNavigationState.value) }
112+
val eventsToNotify = notifiableEvents.filter { !appNavigationStateService.appNavigationState.value.shouldIgnoreEvent(it) }
105113
renderEvents(eventsToNotify)
106114
}
107115

@@ -121,6 +129,17 @@ class DefaultNotificationDrawerManager(
121129
.forEach { notificationDisplayer.cancelNotification(it.tag, it.id) }
122130
}
123131

132+
/**
133+
* Remove the fallback notification for the session.
134+
*/
135+
fun clearFallbackForSession(sessionId: SessionId) {
136+
notificationDisplayer.cancelNotification(
137+
DefaultNotificationDataFactory.FALLBACK_NOTIFICATION_TAG,
138+
NotificationIdProvider.getFallbackNotificationId(sessionId),
139+
)
140+
clearSummaryNotificationIfNeeded(sessionId)
141+
}
142+
124143
/**
125144
* Should be called when the application is currently opened and showing timeline for the given [roomId].
126145
* Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room.
@@ -192,3 +211,30 @@ class DefaultNotificationDrawerManager(
192211
}
193212
}
194213
}
214+
215+
/**
216+
* Used to check if a notifiableEvent should be ignored based on the current application navigation state.
217+
*/
218+
private fun AppNavigationState.shouldIgnoreEvent(event: NotifiableEvent): Boolean {
219+
if (!isInForeground) return false
220+
return navigationState.currentSessionId() == event.sessionId &&
221+
when (event) {
222+
is NotifiableRingingCallEvent -> {
223+
// Never ignore ringing call notifications
224+
// Note that NotifiableRingingCallEvent are not handled by DefaultNotificationDrawerManager
225+
false
226+
}
227+
is FallbackNotifiableEvent -> {
228+
// Ignore if the room list is currently displayed
229+
navigationState is NavigationState.Session
230+
}
231+
is InviteNotifiableEvent,
232+
is SimpleNotifiableEvent -> {
233+
event.roomId == navigationState.currentRoomId()
234+
}
235+
is NotifiableMessageEvent -> {
236+
event.roomId == navigationState.currentRoomId() &&
237+
event.threadId == navigationState.currentThreadId()
238+
}
239+
}
240+
}

libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDataFactory.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,12 @@ class DefaultNotificationDataFactory(
144144
.getFallbackNotification(notificationAccountParams.user.userId)
145145
?.notification
146146
val notification = notificationCreator.createFallbackNotification(
147-
existingNotification,
148-
notificationAccountParams,
149-
fallback,
147+
existingNotification = existingNotification,
148+
notificationAccountParams = notificationAccountParams,
149+
fallbackNotifiableEvents = fallback,
150150
)
151151
return OneShotNotification(
152-
tag = "FALLBACK",
152+
tag = FALLBACK_NOTIFICATION_TAG,
153153
notification = notification,
154154
isNoisy = false,
155155
timestamp = fallback.first().timestamp
@@ -174,6 +174,10 @@ class DefaultNotificationDataFactory(
174174
)
175175
}
176176
}
177+
178+
companion object {
179+
const val FALLBACK_NOTIFICATION_TAG = "FALLBACK"
180+
}
177181
}
178182

179183
data class RoomNotification(

libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/model/NotifiableMessageEvent.kt

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ import io.element.android.libraries.matrix.api.core.SessionId
1515
import io.element.android.libraries.matrix.api.core.ThreadId
1616
import io.element.android.libraries.matrix.api.core.UserId
1717
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
18-
import io.element.android.services.appnavstate.api.AppNavigationState
19-
import io.element.android.services.appnavstate.api.currentRoomId
20-
import io.element.android.services.appnavstate.api.currentSessionId
21-
import io.element.android.services.appnavstate.api.currentThreadId
2218

2319
data class NotifiableMessageEvent(
2420
override val sessionId: SessionId,
@@ -56,24 +52,3 @@ data class NotifiableMessageEvent(
5652
val imageUri: Uri?
5753
get() = imageUriString?.toUri()
5854
}
59-
60-
/**
61-
* Used to check if a notification should be ignored based on the current app and navigation state.
62-
*/
63-
fun NotifiableEvent.shouldIgnoreEventInRoom(appNavigationState: AppNavigationState): Boolean {
64-
val currentSessionId = appNavigationState.navigationState.currentSessionId() ?: return false
65-
return when (val currentRoomId = appNavigationState.navigationState.currentRoomId()) {
66-
null -> false
67-
else -> {
68-
// Never ignore ringing call notifications
69-
if (this is NotifiableRingingCallEvent) {
70-
false
71-
} else {
72-
appNavigationState.isInForeground &&
73-
sessionId == currentSessionId &&
74-
roomId == currentRoomId &&
75-
(this as? NotifiableMessageEvent)?.threadId == appNavigationState.navigationState.currentThreadId()
76-
}
77-
}
78-
}
79-
}

0 commit comments

Comments
 (0)