16
16
17
17
package io.element.android.libraries.push.impl.notifications
18
18
19
+ import androidx.annotation.VisibleForTesting
19
20
import androidx.core.app.NotificationManagerCompat
20
21
import io.element.android.libraries.core.data.tryOrNull
21
22
import io.element.android.libraries.core.log.logger.LoggerTag
22
23
import io.element.android.libraries.di.AppScope
23
24
import io.element.android.libraries.di.SingleIn
25
+ import io.element.android.libraries.matrix.api.MatrixClient
24
26
import io.element.android.libraries.matrix.api.MatrixClientProvider
25
27
import io.element.android.libraries.matrix.api.core.EventId
26
28
import io.element.android.libraries.matrix.api.core.RoomId
@@ -43,7 +45,7 @@ import javax.inject.Inject
43
45
private val loggerTag = LoggerTag (" DefaultNotificationDrawerManager" , LoggerTag .NotificationLoggerTag )
44
46
45
47
/* *
46
- * The NotificationDrawerManager receives notification events as they arrived (from event stream or fcm) and
48
+ * The NotificationDrawerManager receives notification events as they arrive (from event stream or fcm) and
47
49
* organise them in order to display them in the notification drawer.
48
50
* Events can be grouped into the same notification, old (already read) events can be removed to do some cleaning.
49
51
*/
@@ -72,7 +74,8 @@ class DefaultNotificationDrawerManager @Inject constructor(
72
74
}
73
75
74
76
// For test only
75
- fun destroy () {
77
+ @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
78
+ internal fun destroy () {
76
79
appNavigationStateObserver?.cancel()
77
80
}
78
81
@@ -107,9 +110,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
107
110
}
108
111
109
112
/* *
110
- * Should be called as soon as a new event is ready to be displayed.
111
- * The notification corresponding to this event will not be displayed until
112
- * #refreshNotificationDrawer() is called.
113
+ * Should be called as soon as a new event is ready to be displayed, filtering out notifications that shouldn't be displayed.
113
114
* Events might be grouped and there might not be one notification per event!
114
115
*/
115
116
suspend fun onNotifiableEventReceived (notifiableEvent : NotifiableEvent ) {
@@ -120,23 +121,23 @@ class DefaultNotificationDrawerManager @Inject constructor(
120
121
}
121
122
122
123
/* *
123
- * Clear all known events and refresh the notification drawer .
124
+ * Clear all known message events for a [sessionId] .
124
125
*/
125
126
fun clearAllMessagesEvents (sessionId : SessionId ) {
126
127
notificationManager.cancel(null , notificationIdProvider.getRoomMessagesNotificationId(sessionId))
127
128
clearSummaryNotificationIfNeeded(sessionId)
128
129
}
129
130
130
131
/* *
131
- * Clear all notifications related to the session and refresh the notification drawer .
132
+ * Clear all notifications related to the session.
132
133
*/
133
134
fun clearAllEvents (sessionId : SessionId ) {
134
135
activeNotificationsProvider.getNotificationsForSession(sessionId)
135
136
.forEach { notificationManager.cancel(it.tag, it.id) }
136
137
}
137
138
138
139
/* *
139
- * Should be called when the application is currently opened and showing timeline for the given roomId.
140
+ * Should be called when the application is currently opened and showing timeline for the given [ roomId] .
140
141
* Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room.
141
142
* Can also be called when a notification for this room is dismissed by the user.
142
143
*/
@@ -192,35 +193,37 @@ class DefaultNotificationDrawerManager @Inject constructor(
192
193
it.sessionId
193
194
}
194
195
195
- eventsForSessions.forEach { ( sessionId, notifiableEvents) ->
196
+ for (( sessionId, notifiableEvents) in eventsForSessions) {
196
197
val client = matrixClientProvider.getOrRestore(sessionId).getOrThrow()
197
198
val imageLoader = imageLoaderHolder.get(client)
198
199
val userFromCache = client.userProfile.value
199
200
val currentUser = if (userFromCache.avatarUrl != null && userFromCache.displayName.isNullOrEmpty().not ()) {
200
201
// We have an avatar and a display name, use it
201
202
userFromCache
202
203
} else {
203
- tryOrNull(
204
- onError = { Timber .tag(loggerTag.value).e(it, " Unable to retrieve info for user ${sessionId.value} " ) },
205
- operation = {
206
- client.getUserProfile().getOrNull()
207
- ?.let {
208
- // displayName cannot be empty else NotificationCompat.MessagingStyle() will crash
209
- if (it.displayName.isNullOrEmpty()) {
210
- it.copy(displayName = sessionId.value)
211
- } else {
212
- it
213
- }
214
- }
215
- }
216
- ) ? : MatrixUser (
217
- userId = sessionId,
218
- displayName = sessionId.value,
219
- avatarUrl = null
220
- )
204
+ client.getSafeUserProfile()
221
205
}
222
206
223
207
notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents, imageLoader)
224
208
}
225
209
}
210
+
211
+ private suspend fun MatrixClient.getSafeUserProfile (): MatrixUser {
212
+ return tryOrNull(
213
+ onError = { Timber .tag(loggerTag.value).e(it, " Unable to retrieve info for user ${sessionId.value} " ) },
214
+ operation = {
215
+ val profile = getUserProfile().getOrNull()
216
+ // displayName cannot be empty else NotificationCompat.MessagingStyle() will crash
217
+ if (profile?.displayName.isNullOrEmpty()) {
218
+ profile?.copy(displayName = sessionId.value)
219
+ } else {
220
+ profile
221
+ }
222
+ }
223
+ ) ? : MatrixUser (
224
+ userId = sessionId,
225
+ displayName = sessionId.value,
226
+ avatarUrl = null
227
+ )
228
+ }
226
229
}
0 commit comments