Skip to content

Commit 27ed39d

Browse files
authored
Merge pull request #1350 from vector-im/feature/bma/duplicateNotif
Investigation of duplicate notification.
2 parents 4a6ce3f + 0d204f5 commit 27ed39d

File tree

21 files changed

+94
-101
lines changed

21 files changed

+94
-101
lines changed

features/invitelist/impl/src/main/kotlin/io/element/android/features/invitelist/impl/InviteListPresenter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class InviteListPresenter @Inject constructor(
141141
suspend {
142142
client.getRoom(roomId)?.use {
143143
it.join().getOrThrow()
144-
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId)
144+
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId, doRender = true)
145145
analyticsService.capture(it.toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
146146
}
147147
roomId
@@ -152,7 +152,7 @@ class InviteListPresenter @Inject constructor(
152152
suspend {
153153
client.getRoom(roomId)?.use {
154154
it.leave().getOrThrow()
155-
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId)
155+
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId, doRender = true)
156156
}.let { }
157157
}.runCatchingUpdatingState(declinedAction)
158158
}

libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/file/File.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import java.util.Locale
2525
import java.util.UUID
2626

2727
fun File.safeDelete() {
28+
if (exists().not()) return
2829
tryOrNull(
2930
onError = {
3031
Timber.e(it, "Error, unable to delete file $path")

libraries/core/src/main/kotlin/io/element/android/libraries/core/log/logger/LoggerTag.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@ package io.element.android.libraries.core.log.logger
2424
*/
2525
open class LoggerTag(name: String, parentTag: LoggerTag? = null) {
2626

27-
object SYNC : LoggerTag("SYNC")
28-
object VOIP : LoggerTag("VOIP")
29-
object CRYPTO : LoggerTag("CRYPTO")
30-
object RENDEZVOUS : LoggerTag("RZ")
27+
object PushLoggerTag : LoggerTag("Push")
28+
object NotificationLoggerTag : LoggerTag("Notification", PushLoggerTag)
3129

3230
val value: String = if (parentTag == null) {
3331
name

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/tracing/RustTracingTree.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ internal class RustTracingTree(private val retrieveFromStackTrace: Boolean) : Ti
4949
line = location.line,
5050
level = logLevel,
5151
target = Target.ELEMENT.filter,
52-
message = message,
52+
message = if (tag != null) "[$tag] $message" else message,
5353
)
5454
}
5555

libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/notifications/NotificationDrawerManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ import io.element.android.libraries.matrix.api.core.SessionId
2121

2222
interface NotificationDrawerManager {
2323
fun clearMembershipNotificationForSession(sessionId: SessionId)
24-
fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId)
24+
fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId, doRender: Boolean)
2525
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.core.EventId
2424
import io.element.android.libraries.matrix.api.core.SessionId
2525
import io.element.android.libraries.matrix.api.pusher.SetHttpPusherData
2626
import io.element.android.libraries.push.impl.config.PushConfig
27-
import io.element.android.libraries.push.impl.log.pushLoggerTag
2827
import io.element.android.libraries.push.impl.pushgateway.PushGatewayNotifyRequest
2928
import io.element.android.libraries.pushproviders.api.PusherSubscriber
3029
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
@@ -35,7 +34,7 @@ import javax.inject.Inject
3534

3635
internal const val DEFAULT_PUSHER_FILE_TAG = "mobile"
3736

38-
private val loggerTag = LoggerTag("PushersManager", pushLoggerTag)
37+
private val loggerTag = LoggerTag("PushersManager", LoggerTag.PushLoggerTag)
3938

4039
@ContributesBinding(AppScope::class)
4140
class PushersManager @Inject constructor(

libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/log/LoggerTag.kt

Lines changed: 0 additions & 22 deletions
This file was deleted.

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

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import io.element.android.libraries.androidutils.throttler.FirstThrottler
2020
import io.element.android.libraries.core.cache.CircularCache
2121
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
2222
import io.element.android.libraries.core.data.tryOrNull
23+
import io.element.android.libraries.core.log.logger.LoggerTag
2324
import io.element.android.libraries.core.meta.BuildMeta
2425
import io.element.android.libraries.di.AppScope
2526
import io.element.android.libraries.di.SingleIn
@@ -41,6 +42,8 @@ import kotlinx.coroutines.withContext
4142
import timber.log.Timber
4243
import javax.inject.Inject
4344

45+
private val loggerTag = LoggerTag("DefaultNotificationDrawerManager", LoggerTag.NotificationLoggerTag)
46+
4447
/**
4548
* The NotificationDrawerManager receives notification events as they arrived (from event stream or fcm) and
4649
* organise them in order to display them in the notification drawer.
@@ -89,7 +92,11 @@ class DefaultNotificationDrawerManager @Inject constructor(
8992
is NavigationState.Space -> {}
9093
is NavigationState.Room -> {
9194
// Cleanup notification for current room
92-
clearMessagesForRoom(navigationState.parentSpace.parentSession.sessionId, navigationState.roomId)
95+
clearMessagesForRoom(
96+
sessionId = navigationState.parentSpace.parentSession.sessionId,
97+
roomId = navigationState.roomId,
98+
doRender = true,
99+
)
93100
}
94101
is NavigationState.Thread -> {
95102
onEnteringThread(
@@ -112,13 +119,13 @@ class DefaultNotificationDrawerManager @Inject constructor(
112119

113120
private fun NotificationEventQueue.onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
114121
if (buildMeta.lowPrivacyLoggingEnabled) {
115-
Timber.d("onNotifiableEventReceived(): $notifiableEvent")
122+
Timber.tag(loggerTag.value).d("onNotifiableEventReceived(): $notifiableEvent")
116123
} else {
117-
Timber.d("onNotifiableEventReceived(): is push: ${notifiableEvent.canBeReplaced}")
124+
Timber.tag(loggerTag.value).d("onNotifiableEventReceived(): is push: ${notifiableEvent.canBeReplaced}")
118125
}
119126

120127
if (filteredEventDetector.shouldBeIgnored(notifiableEvent)) {
121-
Timber.d("onNotifiableEventReceived(): ignore the event")
128+
Timber.tag(loggerTag.value).d("onNotifiableEventReceived(): ignore the event")
122129
return
123130
}
124131

@@ -132,16 +139,16 @@ class DefaultNotificationDrawerManager @Inject constructor(
132139
* Events might be grouped and there might not be one notification per event!
133140
*/
134141
fun onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
135-
updateEvents {
142+
updateEvents(doRender = true) {
136143
it.onNotifiableEventReceived(notifiableEvent)
137144
}
138145
}
139146

140147
/**
141148
* Clear all known events and refresh the notification drawer.
142149
*/
143-
fun clearAllMessagesEvents(sessionId: SessionId) {
144-
updateEvents {
150+
fun clearAllMessagesEvents(sessionId: SessionId, doRender: Boolean) {
151+
updateEvents(doRender = doRender) {
145152
it.clearMessagesForSession(sessionId)
146153
}
147154
}
@@ -150,7 +157,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
150157
* Clear all notifications related to the session and refresh the notification drawer.
151158
*/
152159
fun clearAllEvents(sessionId: SessionId) {
153-
updateEvents {
160+
updateEvents(doRender = true) {
154161
it.clearAllForSession(sessionId)
155162
}
156163
}
@@ -160,32 +167,36 @@ class DefaultNotificationDrawerManager @Inject constructor(
160167
* Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room.
161168
* Can also be called when a notification for this room is dismissed by the user.
162169
*/
163-
fun clearMessagesForRoom(sessionId: SessionId, roomId: RoomId) {
164-
updateEvents {
170+
fun clearMessagesForRoom(sessionId: SessionId, roomId: RoomId, doRender: Boolean) {
171+
updateEvents(doRender = doRender) {
165172
it.clearMessagesForRoom(sessionId, roomId)
166173
}
167174
}
168175

169176
override fun clearMembershipNotificationForSession(sessionId: SessionId) {
170-
updateEvents {
177+
updateEvents(doRender = true) {
171178
it.clearMembershipNotificationForSession(sessionId)
172179
}
173180
}
174181

175182
/**
176183
* Clear invitation notification for the provided room.
177184
*/
178-
override fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId) {
179-
updateEvents {
185+
override fun clearMembershipNotificationForRoom(
186+
sessionId: SessionId,
187+
roomId: RoomId,
188+
doRender: Boolean,
189+
) {
190+
updateEvents(doRender = doRender) {
180191
it.clearMembershipNotificationForRoom(sessionId, roomId)
181192
}
182193
}
183194

184195
/**
185196
* Clear the notifications for a single event.
186197
*/
187-
fun clearEvent(eventId: EventId) {
188-
updateEvents {
198+
fun clearEvent(eventId: EventId, doRender: Boolean) {
199+
updateEvents(doRender = doRender) {
189200
it.clearEvent(eventId)
190201
}
191202
}
@@ -195,14 +206,14 @@ class DefaultNotificationDrawerManager @Inject constructor(
195206
* Used to ignore events related to that thread (no need to display notification) and clean any existing notification on this room.
196207
*/
197208
private fun onEnteringThread(sessionId: SessionId, roomId: RoomId, threadId: ThreadId) {
198-
updateEvents {
209+
updateEvents(doRender = true) {
199210
it.clearMessagesForThread(sessionId, roomId, threadId)
200211
}
201212
}
202213

203214
// TODO EAx Must be per account
204215
fun notificationStyleChanged() {
205-
updateEvents {
216+
updateEvents(doRender = true) {
206217
val newSettings = true // pushDataStore.useCompleteNotificationFormat()
207218
if (newSettings != useCompleteNotificationFormat) {
208219
// Settings has changed, remove all current notifications
@@ -212,41 +223,46 @@ class DefaultNotificationDrawerManager @Inject constructor(
212223
}
213224
}
214225

215-
private fun updateEvents(action: DefaultNotificationDrawerManager.(NotificationEventQueue) -> Unit) {
216-
notificationState.updateQueuedEvents(this) { queuedEvents, _ ->
226+
private fun updateEvents(
227+
doRender: Boolean,
228+
action: (NotificationEventQueue) -> Unit,
229+
) {
230+
notificationState.updateQueuedEvents { queuedEvents, _ ->
217231
action(queuedEvents)
218232
}
219-
coroutineScope.refreshNotificationDrawer()
233+
coroutineScope.refreshNotificationDrawer(doRender)
220234
}
221235

222-
private fun CoroutineScope.refreshNotificationDrawer() = launch {
236+
private fun CoroutineScope.refreshNotificationDrawer(doRender: Boolean) = launch {
223237
// Implement last throttler
224238
val canHandle = firstThrottler.canHandle()
225-
Timber.v("refreshNotificationDrawer(), delay: ${canHandle.waitMillis()} ms")
239+
Timber.tag(loggerTag.value).v("refreshNotificationDrawer($doRender), delay: ${canHandle.waitMillis()} ms")
226240
withContext(dispatchers.io) {
227241
delay(canHandle.waitMillis())
228242
try {
229-
refreshNotificationDrawerBg()
243+
refreshNotificationDrawerBg(doRender)
230244
} catch (throwable: Throwable) {
231245
// It can happen if for instance session has been destroyed. It's a bit ugly to try catch like this, but it's safer
232-
Timber.w(throwable, "refreshNotificationDrawerBg failure")
246+
Timber.tag(loggerTag.value).w(throwable, "refreshNotificationDrawerBg failure")
233247
}
234248
}
235249
}
236250

237-
private suspend fun refreshNotificationDrawerBg() {
238-
Timber.v("refreshNotificationDrawerBg()")
239-
val eventsToRender = notificationState.updateQueuedEvents(this) { queuedEvents, renderedEvents ->
251+
private suspend fun refreshNotificationDrawerBg(doRender: Boolean) {
252+
Timber.tag(loggerTag.value).v("refreshNotificationDrawerBg($doRender)")
253+
val eventsToRender = notificationState.updateQueuedEvents { queuedEvents, renderedEvents ->
240254
notifiableEventProcessor.process(queuedEvents.rawEvents(), renderedEvents).also {
241255
queuedEvents.clearAndAdd(it.onlyKeptEvents())
242256
}
243257
}
244258

245259
if (notificationState.hasAlreadyRendered(eventsToRender)) {
246-
Timber.d("Skipping notification update due to event list not changing")
260+
Timber.tag(loggerTag.value).d("Skipping notification update due to event list not changing")
247261
} else {
248262
notificationState.clearAndAddRenderedEvents(eventsToRender)
249-
renderEvents(eventsToRender)
263+
if (doRender) {
264+
renderEvents(eventsToRender)
265+
}
250266
persistEvents()
251267
}
252268
}
@@ -265,7 +281,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
265281

266282
eventsForSessions.forEach { (sessionId, notifiableEvents) ->
267283
val currentUser = tryOrNull(
268-
onError = { Timber.e(it, "Unable to retrieve info for user ${sessionId.value}") },
284+
onError = { Timber.tag(loggerTag.value).e(it, "Unable to retrieve info for user ${sessionId.value}") },
269285
operation = {
270286
val client = matrixClientProvider.getOrRestore(sessionId).getOrThrow()
271287
// myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.element.android.libraries.push.impl.notifications
1818

19+
import io.element.android.libraries.core.log.logger.LoggerTag
1920
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
2021
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
2122
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
@@ -29,6 +30,8 @@ import javax.inject.Inject
2930

3031
private typealias ProcessedEvents = List<ProcessedEvent<NotifiableEvent>>
3132

33+
private val loggerTag = LoggerTag("NotifiableEventProcessor", LoggerTag.NotificationLoggerTag)
34+
3235
class NotifiableEventProcessor @Inject constructor(
3336
private val outdatedDetector: OutdatedEventDetector,
3437
private val appNavigationStateService: AppNavigationStateService,
@@ -45,10 +48,10 @@ class NotifiableEventProcessor @Inject constructor(
4548
is NotifiableMessageEvent -> when {
4649
it.shouldIgnoreEventInRoom(appState) -> {
4750
ProcessedEvent.Type.REMOVE
48-
.also { Timber.d("notification message removed due to currently viewing the same room or thread") }
51+
.also { Timber.tag(loggerTag.value).d("notification message removed due to currently viewing the same room or thread") }
4952
}
5053
outdatedDetector.isMessageOutdated(it) -> ProcessedEvent.Type.REMOVE
51-
.also { Timber.d("notification message removed due to being read") }
54+
.also { Timber.tag(loggerTag.value).d("notification message removed due to being read") }
5255
else -> ProcessedEvent.Type.KEEP
5356
}
5457
is SimpleNotifiableEvent -> when (it.type) {
@@ -58,7 +61,7 @@ class NotifiableEventProcessor @Inject constructor(
5861
is FallbackNotifiableEvent -> when {
5962
it.shouldIgnoreEventInRoom(appState) -> {
6063
ProcessedEvent.Type.REMOVE
61-
.also { Timber.d("notification fallback removed due to currently viewing the same room or thread") }
64+
.also { Timber.tag(loggerTag.value).d("notification fallback removed due to currently viewing the same room or thread") }
6265
}
6366
else -> ProcessedEvent.Type.KEEP
6467
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy
3636
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageType
3737
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
3838
import io.element.android.libraries.push.impl.R
39-
import io.element.android.libraries.push.impl.log.pushLoggerTag
4039
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
4140
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
4241
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
@@ -47,7 +46,7 @@ import io.element.android.services.toolbox.api.systemclock.SystemClock
4746
import timber.log.Timber
4847
import javax.inject.Inject
4948

50-
private val loggerTag = LoggerTag("NotifiableEventResolver", pushLoggerTag)
49+
private val loggerTag = LoggerTag("NotifiableEventResolver", LoggerTag.NotificationLoggerTag)
5150

5251
/**
5352
* The notifiable event resolver is able to create a NotifiableEvent (view model for notifications) from an sdk Event.

0 commit comments

Comments
 (0)