Merge pull request #1350 from vector-im/feature/bma/duplicateNotif

Investigation of duplicate notification.
This commit is contained in:
Benoit Marty 2023-09-15 19:31:48 +02:00 committed by GitHub
commit d19d485205
21 changed files with 94 additions and 101 deletions

View file

@ -141,7 +141,7 @@ class InviteListPresenter @Inject constructor(
suspend { suspend {
client.getRoom(roomId)?.use { client.getRoom(roomId)?.use {
it.join().getOrThrow() it.join().getOrThrow()
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId) notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId, doRender = true)
analyticsService.capture(it.toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite)) analyticsService.capture(it.toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
} }
roomId roomId
@ -152,7 +152,7 @@ class InviteListPresenter @Inject constructor(
suspend { suspend {
client.getRoom(roomId)?.use { client.getRoom(roomId)?.use {
it.leave().getOrThrow() it.leave().getOrThrow()
notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId) notificationDrawerManager.clearMembershipNotificationForRoom(client.sessionId, roomId, doRender = true)
}.let { } }.let { }
}.runCatchingUpdatingState(declinedAction) }.runCatchingUpdatingState(declinedAction)
} }

View file

@ -25,6 +25,7 @@ import java.util.Locale
import java.util.UUID import java.util.UUID
fun File.safeDelete() { fun File.safeDelete() {
if (exists().not()) return
tryOrNull( tryOrNull(
onError = { onError = {
Timber.e(it, "Error, unable to delete file $path") Timber.e(it, "Error, unable to delete file $path")

View file

@ -24,10 +24,8 @@ package io.element.android.libraries.core.log.logger
*/ */
open class LoggerTag(name: String, parentTag: LoggerTag? = null) { open class LoggerTag(name: String, parentTag: LoggerTag? = null) {
object SYNC : LoggerTag("SYNC") object PushLoggerTag : LoggerTag("Push")
object VOIP : LoggerTag("VOIP") object NotificationLoggerTag : LoggerTag("Notification", PushLoggerTag)
object CRYPTO : LoggerTag("CRYPTO")
object RENDEZVOUS : LoggerTag("RZ")
val value: String = if (parentTag == null) { val value: String = if (parentTag == null) {
name name

View file

@ -49,7 +49,7 @@ internal class RustTracingTree(private val retrieveFromStackTrace: Boolean) : Ti
line = location.line, line = location.line,
level = logLevel, level = logLevel,
target = Target.ELEMENT.filter, target = Target.ELEMENT.filter,
message = message, message = if (tag != null) "[$tag] $message" else message,
) )
} }

View file

@ -21,5 +21,5 @@ import io.element.android.libraries.matrix.api.core.SessionId
interface NotificationDrawerManager { interface NotificationDrawerManager {
fun clearMembershipNotificationForSession(sessionId: SessionId) fun clearMembershipNotificationForSession(sessionId: SessionId)
fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId) fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId, doRender: Boolean)
} }

View file

@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.pusher.SetHttpPusherData import io.element.android.libraries.matrix.api.pusher.SetHttpPusherData
import io.element.android.libraries.push.impl.config.PushConfig import io.element.android.libraries.push.impl.config.PushConfig
import io.element.android.libraries.push.impl.log.pushLoggerTag
import io.element.android.libraries.push.impl.pushgateway.PushGatewayNotifyRequest import io.element.android.libraries.push.impl.pushgateway.PushGatewayNotifyRequest
import io.element.android.libraries.pushproviders.api.PusherSubscriber import io.element.android.libraries.pushproviders.api.PusherSubscriber
import io.element.android.libraries.pushstore.api.UserPushStoreFactory import io.element.android.libraries.pushstore.api.UserPushStoreFactory
@ -35,7 +34,7 @@ import javax.inject.Inject
internal const val DEFAULT_PUSHER_FILE_TAG = "mobile" internal const val DEFAULT_PUSHER_FILE_TAG = "mobile"
private val loggerTag = LoggerTag("PushersManager", pushLoggerTag) private val loggerTag = LoggerTag("PushersManager", LoggerTag.PushLoggerTag)
@ContributesBinding(AppScope::class) @ContributesBinding(AppScope::class)
class PushersManager @Inject constructor( class PushersManager @Inject constructor(

View file

@ -1,22 +0,0 @@
/*
* Copyright (c) 2023 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 io.element.android.libraries.push.impl.log
import io.element.android.libraries.core.log.logger.LoggerTag
internal val pushLoggerTag = LoggerTag("Push")
internal val notificationLoggerTag = LoggerTag("Notification", pushLoggerTag)

View file

@ -20,6 +20,7 @@ import io.element.android.libraries.androidutils.throttler.FirstThrottler
import io.element.android.libraries.core.cache.CircularCache import io.element.android.libraries.core.cache.CircularCache
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn import io.element.android.libraries.di.SingleIn
@ -41,6 +42,8 @@ import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("DefaultNotificationDrawerManager", LoggerTag.NotificationLoggerTag)
/** /**
* The NotificationDrawerManager receives notification events as they arrived (from event stream or fcm) and * The NotificationDrawerManager receives notification events as they arrived (from event stream or fcm) and
* organise them in order to display them in the notification drawer. * organise them in order to display them in the notification drawer.
@ -89,7 +92,11 @@ class DefaultNotificationDrawerManager @Inject constructor(
is NavigationState.Space -> {} is NavigationState.Space -> {}
is NavigationState.Room -> { is NavigationState.Room -> {
// Cleanup notification for current room // Cleanup notification for current room
clearMessagesForRoom(navigationState.parentSpace.parentSession.sessionId, navigationState.roomId) clearMessagesForRoom(
sessionId = navigationState.parentSpace.parentSession.sessionId,
roomId = navigationState.roomId,
doRender = true,
)
} }
is NavigationState.Thread -> { is NavigationState.Thread -> {
onEnteringThread( onEnteringThread(
@ -112,13 +119,13 @@ class DefaultNotificationDrawerManager @Inject constructor(
private fun NotificationEventQueue.onNotifiableEventReceived(notifiableEvent: NotifiableEvent) { private fun NotificationEventQueue.onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
if (buildMeta.lowPrivacyLoggingEnabled) { if (buildMeta.lowPrivacyLoggingEnabled) {
Timber.d("onNotifiableEventReceived(): $notifiableEvent") Timber.tag(loggerTag.value).d("onNotifiableEventReceived(): $notifiableEvent")
} else { } else {
Timber.d("onNotifiableEventReceived(): is push: ${notifiableEvent.canBeReplaced}") Timber.tag(loggerTag.value).d("onNotifiableEventReceived(): is push: ${notifiableEvent.canBeReplaced}")
} }
if (filteredEventDetector.shouldBeIgnored(notifiableEvent)) { if (filteredEventDetector.shouldBeIgnored(notifiableEvent)) {
Timber.d("onNotifiableEventReceived(): ignore the event") Timber.tag(loggerTag.value).d("onNotifiableEventReceived(): ignore the event")
return return
} }
@ -132,7 +139,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
* Events might be grouped and there might not be one notification per event! * Events might be grouped and there might not be one notification per event!
*/ */
fun onNotifiableEventReceived(notifiableEvent: NotifiableEvent) { fun onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
updateEvents { updateEvents(doRender = true) {
it.onNotifiableEventReceived(notifiableEvent) it.onNotifiableEventReceived(notifiableEvent)
} }
} }
@ -140,8 +147,8 @@ class DefaultNotificationDrawerManager @Inject constructor(
/** /**
* Clear all known events and refresh the notification drawer. * Clear all known events and refresh the notification drawer.
*/ */
fun clearAllMessagesEvents(sessionId: SessionId) { fun clearAllMessagesEvents(sessionId: SessionId, doRender: Boolean) {
updateEvents { updateEvents(doRender = doRender) {
it.clearMessagesForSession(sessionId) it.clearMessagesForSession(sessionId)
} }
} }
@ -150,7 +157,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
* Clear all notifications related to the session and refresh the notification drawer. * Clear all notifications related to the session and refresh the notification drawer.
*/ */
fun clearAllEvents(sessionId: SessionId) { fun clearAllEvents(sessionId: SessionId) {
updateEvents { updateEvents(doRender = true) {
it.clearAllForSession(sessionId) it.clearAllForSession(sessionId)
} }
} }
@ -160,14 +167,14 @@ class DefaultNotificationDrawerManager @Inject constructor(
* Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room. * Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room.
* Can also be called when a notification for this room is dismissed by the user. * Can also be called when a notification for this room is dismissed by the user.
*/ */
fun clearMessagesForRoom(sessionId: SessionId, roomId: RoomId) { fun clearMessagesForRoom(sessionId: SessionId, roomId: RoomId, doRender: Boolean) {
updateEvents { updateEvents(doRender = doRender) {
it.clearMessagesForRoom(sessionId, roomId) it.clearMessagesForRoom(sessionId, roomId)
} }
} }
override fun clearMembershipNotificationForSession(sessionId: SessionId) { override fun clearMembershipNotificationForSession(sessionId: SessionId) {
updateEvents { updateEvents(doRender = true) {
it.clearMembershipNotificationForSession(sessionId) it.clearMembershipNotificationForSession(sessionId)
} }
} }
@ -175,8 +182,12 @@ class DefaultNotificationDrawerManager @Inject constructor(
/** /**
* Clear invitation notification for the provided room. * Clear invitation notification for the provided room.
*/ */
override fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId) { override fun clearMembershipNotificationForRoom(
updateEvents { sessionId: SessionId,
roomId: RoomId,
doRender: Boolean,
) {
updateEvents(doRender = doRender) {
it.clearMembershipNotificationForRoom(sessionId, roomId) it.clearMembershipNotificationForRoom(sessionId, roomId)
} }
} }
@ -184,8 +195,8 @@ class DefaultNotificationDrawerManager @Inject constructor(
/** /**
* Clear the notifications for a single event. * Clear the notifications for a single event.
*/ */
fun clearEvent(eventId: EventId) { fun clearEvent(eventId: EventId, doRender: Boolean) {
updateEvents { updateEvents(doRender = doRender) {
it.clearEvent(eventId) it.clearEvent(eventId)
} }
} }
@ -195,14 +206,14 @@ class DefaultNotificationDrawerManager @Inject constructor(
* Used to ignore events related to that thread (no need to display notification) and clean any existing notification on this room. * Used to ignore events related to that thread (no need to display notification) and clean any existing notification on this room.
*/ */
private fun onEnteringThread(sessionId: SessionId, roomId: RoomId, threadId: ThreadId) { private fun onEnteringThread(sessionId: SessionId, roomId: RoomId, threadId: ThreadId) {
updateEvents { updateEvents(doRender = true) {
it.clearMessagesForThread(sessionId, roomId, threadId) it.clearMessagesForThread(sessionId, roomId, threadId)
} }
} }
// TODO EAx Must be per account // TODO EAx Must be per account
fun notificationStyleChanged() { fun notificationStyleChanged() {
updateEvents { updateEvents(doRender = true) {
val newSettings = true // pushDataStore.useCompleteNotificationFormat() val newSettings = true // pushDataStore.useCompleteNotificationFormat()
if (newSettings != useCompleteNotificationFormat) { if (newSettings != useCompleteNotificationFormat) {
// Settings has changed, remove all current notifications // Settings has changed, remove all current notifications
@ -212,41 +223,46 @@ class DefaultNotificationDrawerManager @Inject constructor(
} }
} }
private fun updateEvents(action: DefaultNotificationDrawerManager.(NotificationEventQueue) -> Unit) { private fun updateEvents(
notificationState.updateQueuedEvents(this) { queuedEvents, _ -> doRender: Boolean,
action: (NotificationEventQueue) -> Unit,
) {
notificationState.updateQueuedEvents { queuedEvents, _ ->
action(queuedEvents) action(queuedEvents)
} }
coroutineScope.refreshNotificationDrawer() coroutineScope.refreshNotificationDrawer(doRender)
} }
private fun CoroutineScope.refreshNotificationDrawer() = launch { private fun CoroutineScope.refreshNotificationDrawer(doRender: Boolean) = launch {
// Implement last throttler // Implement last throttler
val canHandle = firstThrottler.canHandle() val canHandle = firstThrottler.canHandle()
Timber.v("refreshNotificationDrawer(), delay: ${canHandle.waitMillis()} ms") Timber.tag(loggerTag.value).v("refreshNotificationDrawer($doRender), delay: ${canHandle.waitMillis()} ms")
withContext(dispatchers.io) { withContext(dispatchers.io) {
delay(canHandle.waitMillis()) delay(canHandle.waitMillis())
try { try {
refreshNotificationDrawerBg() refreshNotificationDrawerBg(doRender)
} catch (throwable: Throwable) { } catch (throwable: Throwable) {
// It can happen if for instance session has been destroyed. It's a bit ugly to try catch like this, but it's safer // It can happen if for instance session has been destroyed. It's a bit ugly to try catch like this, but it's safer
Timber.w(throwable, "refreshNotificationDrawerBg failure") Timber.tag(loggerTag.value).w(throwable, "refreshNotificationDrawerBg failure")
} }
} }
} }
private suspend fun refreshNotificationDrawerBg() { private suspend fun refreshNotificationDrawerBg(doRender: Boolean) {
Timber.v("refreshNotificationDrawerBg()") Timber.tag(loggerTag.value).v("refreshNotificationDrawerBg($doRender)")
val eventsToRender = notificationState.updateQueuedEvents(this) { queuedEvents, renderedEvents -> val eventsToRender = notificationState.updateQueuedEvents { queuedEvents, renderedEvents ->
notifiableEventProcessor.process(queuedEvents.rawEvents(), renderedEvents).also { notifiableEventProcessor.process(queuedEvents.rawEvents(), renderedEvents).also {
queuedEvents.clearAndAdd(it.onlyKeptEvents()) queuedEvents.clearAndAdd(it.onlyKeptEvents())
} }
} }
if (notificationState.hasAlreadyRendered(eventsToRender)) { if (notificationState.hasAlreadyRendered(eventsToRender)) {
Timber.d("Skipping notification update due to event list not changing") Timber.tag(loggerTag.value).d("Skipping notification update due to event list not changing")
} else { } else {
notificationState.clearAndAddRenderedEvents(eventsToRender) notificationState.clearAndAddRenderedEvents(eventsToRender)
renderEvents(eventsToRender) if (doRender) {
renderEvents(eventsToRender)
}
persistEvents() persistEvents()
} }
} }
@ -265,7 +281,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
eventsForSessions.forEach { (sessionId, notifiableEvents) -> eventsForSessions.forEach { (sessionId, notifiableEvents) ->
val currentUser = tryOrNull( val currentUser = tryOrNull(
onError = { Timber.e(it, "Unable to retrieve info for user ${sessionId.value}") }, onError = { Timber.tag(loggerTag.value).e(it, "Unable to retrieve info for user ${sessionId.value}") },
operation = { operation = {
val client = matrixClientProvider.getOrRestore(sessionId).getOrThrow() val client = matrixClientProvider.getOrRestore(sessionId).getOrThrow()
// myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash // myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash

View file

@ -16,6 +16,7 @@
package io.element.android.libraries.push.impl.notifications package io.element.android.libraries.push.impl.notifications
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.matrix.api.timeline.item.event.EventType import io.element.android.libraries.matrix.api.timeline.item.event.EventType
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
@ -29,6 +30,8 @@ import javax.inject.Inject
private typealias ProcessedEvents = List<ProcessedEvent<NotifiableEvent>> private typealias ProcessedEvents = List<ProcessedEvent<NotifiableEvent>>
private val loggerTag = LoggerTag("NotifiableEventProcessor", LoggerTag.NotificationLoggerTag)
class NotifiableEventProcessor @Inject constructor( class NotifiableEventProcessor @Inject constructor(
private val outdatedDetector: OutdatedEventDetector, private val outdatedDetector: OutdatedEventDetector,
private val appNavigationStateService: AppNavigationStateService, private val appNavigationStateService: AppNavigationStateService,
@ -45,10 +48,10 @@ class NotifiableEventProcessor @Inject constructor(
is NotifiableMessageEvent -> when { is NotifiableMessageEvent -> when {
it.shouldIgnoreEventInRoom(appState) -> { it.shouldIgnoreEventInRoom(appState) -> {
ProcessedEvent.Type.REMOVE ProcessedEvent.Type.REMOVE
.also { Timber.d("notification message removed due to currently viewing the same room or thread") } .also { Timber.tag(loggerTag.value).d("notification message removed due to currently viewing the same room or thread") }
} }
outdatedDetector.isMessageOutdated(it) -> ProcessedEvent.Type.REMOVE outdatedDetector.isMessageOutdated(it) -> ProcessedEvent.Type.REMOVE
.also { Timber.d("notification message removed due to being read") } .also { Timber.tag(loggerTag.value).d("notification message removed due to being read") }
else -> ProcessedEvent.Type.KEEP else -> ProcessedEvent.Type.KEEP
} }
is SimpleNotifiableEvent -> when (it.type) { is SimpleNotifiableEvent -> when (it.type) {
@ -58,7 +61,7 @@ class NotifiableEventProcessor @Inject constructor(
is FallbackNotifiableEvent -> when { is FallbackNotifiableEvent -> when {
it.shouldIgnoreEventInRoom(appState) -> { it.shouldIgnoreEventInRoom(appState) -> {
ProcessedEvent.Type.REMOVE ProcessedEvent.Type.REMOVE
.also { Timber.d("notification fallback removed due to currently viewing the same room or thread") } .also { Timber.tag(loggerTag.value).d("notification fallback removed due to currently viewing the same room or thread") }
} }
else -> ProcessedEvent.Type.KEEP else -> ProcessedEvent.Type.KEEP
} }

View file

@ -36,7 +36,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageType import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
import io.element.android.libraries.push.impl.R import io.element.android.libraries.push.impl.R
import io.element.android.libraries.push.impl.log.pushLoggerTag
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
@ -47,7 +46,7 @@ import io.element.android.services.toolbox.api.systemclock.SystemClock
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("NotifiableEventResolver", pushLoggerTag) private val loggerTag = LoggerTag("NotifiableEventResolver", LoggerTag.NotificationLoggerTag)
/** /**
* The notifiable event resolver is able to create a NotifiableEvent (view model for notifications) from an sdk Event. * The notifiable event resolver is able to create a NotifiableEvent (view model for notifications) from an sdk Event.

View file

@ -24,11 +24,10 @@ import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.push.impl.log.notificationLoggerTag
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("NotificationBroadcastReceiver", notificationLoggerTag) private val loggerTag = LoggerTag("NotificationBroadcastReceiver", LoggerTag.NotificationLoggerTag)
/** /**
* Receives actions broadcast by notification (on click, on dismiss, inline replies, etc.). * Receives actions broadcast by notification (on click, on dismiss, inline replies, etc.).
@ -41,34 +40,34 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
if (intent == null || context == null) return if (intent == null || context == null) return
context.bindings<NotificationBroadcastReceiverBindings>().inject(this) context.bindings<NotificationBroadcastReceiverBindings>().inject(this)
Timber.tag(loggerTag.value).v("NotificationBroadcastReceiver received : $intent")
val sessionId = intent.extras?.getString(KEY_SESSION_ID)?.let(::SessionId) ?: return val sessionId = intent.extras?.getString(KEY_SESSION_ID)?.let(::SessionId) ?: return
val roomId = intent.getStringExtra(KEY_ROOM_ID)?.let(::RoomId) val roomId = intent.getStringExtra(KEY_ROOM_ID)?.let(::RoomId)
val eventId = intent.getStringExtra(KEY_EVENT_ID)?.let(::EventId) val eventId = intent.getStringExtra(KEY_EVENT_ID)?.let(::EventId)
Timber.tag(loggerTag.value).d("onReceive: ${intent.action} ${intent.data} for: ${roomId?.value}/${eventId?.value}")
when (intent.action) { when (intent.action) {
actionIds.smartReply -> actionIds.smartReply ->
handleSmartReply(intent, context) handleSmartReply(intent, context)
actionIds.dismissRoom -> if (roomId != null) { actionIds.dismissRoom -> if (roomId != null) {
defaultNotificationDrawerManager.clearMessagesForRoom(sessionId, roomId) defaultNotificationDrawerManager.clearMessagesForRoom(sessionId, roomId, doRender = false)
} }
actionIds.dismissSummary -> actionIds.dismissSummary ->
defaultNotificationDrawerManager.clearAllMessagesEvents(sessionId) defaultNotificationDrawerManager.clearAllMessagesEvents(sessionId, doRender = false)
actionIds.dismissInvite -> if (roomId != null) { actionIds.dismissInvite -> if (roomId != null) {
defaultNotificationDrawerManager.clearMembershipNotificationForRoom(sessionId, roomId) defaultNotificationDrawerManager.clearMembershipNotificationForRoom(sessionId, roomId, doRender = false)
} }
actionIds.dismissEvent -> if (eventId != null) { actionIds.dismissEvent -> if (eventId != null) {
defaultNotificationDrawerManager.clearEvent(eventId) defaultNotificationDrawerManager.clearEvent(eventId, doRender = false)
} }
actionIds.markRoomRead -> if (roomId != null) { actionIds.markRoomRead -> if (roomId != null) {
defaultNotificationDrawerManager.clearMessagesForRoom(sessionId, roomId) defaultNotificationDrawerManager.clearMessagesForRoom(sessionId, roomId, doRender = true)
handleMarkAsRead(sessionId, roomId) handleMarkAsRead(sessionId, roomId)
} }
actionIds.join -> if (roomId != null) { actionIds.join -> if (roomId != null) {
defaultNotificationDrawerManager.clearMembershipNotificationForRoom(sessionId, roomId) defaultNotificationDrawerManager.clearMembershipNotificationForRoom(sessionId, roomId, doRender = true)
handleJoinRoom(sessionId, roomId) handleJoinRoom(sessionId, roomId)
} }
actionIds.reject -> if (roomId != null) { actionIds.reject -> if (roomId != null) {
defaultNotificationDrawerManager.clearMembershipNotificationForRoom(sessionId, roomId) defaultNotificationDrawerManager.clearMembershipNotificationForRoom(sessionId, roomId, doRender = true)
handleRejectRoom(sessionId, roomId) handleRejectRoom(sessionId, roomId)
} }
} }

View file

@ -22,7 +22,6 @@ import io.element.android.libraries.androidutils.file.safeDelete
import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.push.impl.log.notificationLoggerTag
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
@ -33,7 +32,7 @@ import javax.inject.Inject
private const val ROOMS_NOTIFICATIONS_FILE_NAME_LEGACY = "im.vector.notifications.cache" private const val ROOMS_NOTIFICATIONS_FILE_NAME_LEGACY = "im.vector.notifications.cache"
private const val FILE_NAME = "notifications.bin" private const val FILE_NAME = "notifications.bin"
private val loggerTag = LoggerTag("NotificationEventPersistence", notificationLoggerTag) private val loggerTag = LoggerTag("NotificationEventPersistence", LoggerTag.NotificationLoggerTag)
class NotificationEventPersistence @Inject constructor( class NotificationEventPersistence @Inject constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,

View file

@ -16,6 +16,7 @@
package io.element.android.libraries.push.impl.notifications package io.element.android.libraries.push.impl.notifications
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
@ -26,6 +27,8 @@ import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiab
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("NotificationRenderer", LoggerTag.NotificationLoggerTag)
class NotificationRenderer @Inject constructor( class NotificationRenderer @Inject constructor(
private val notificationIdProvider: NotificationIdProvider, private val notificationIdProvider: NotificationIdProvider,
private val notificationDisplayer: NotificationDisplayer, private val notificationDisplayer: NotificationDisplayer,
@ -54,7 +57,7 @@ class NotificationRenderer @Inject constructor(
// Remove summary first to avoid briefly displaying it after dismissing the last notification // Remove summary first to avoid briefly displaying it after dismissing the last notification
if (summaryNotification == SummaryNotification.Removed) { if (summaryNotification == SummaryNotification.Removed) {
Timber.d("Removing summary notification") Timber.tag(loggerTag.value).d("Removing summary notification")
notificationDisplayer.cancelNotificationMessage( notificationDisplayer.cancelNotificationMessage(
tag = null, tag = null,
id = notificationIdProvider.getSummaryNotificationId(currentUser.userId) id = notificationIdProvider.getSummaryNotificationId(currentUser.userId)
@ -64,14 +67,14 @@ class NotificationRenderer @Inject constructor(
roomNotifications.forEach { wrapper -> roomNotifications.forEach { wrapper ->
when (wrapper) { when (wrapper) {
is RoomNotification.Removed -> { is RoomNotification.Removed -> {
Timber.d("Removing room messages notification ${wrapper.roomId}") Timber.tag(loggerTag.value).d("Removing room messages notification ${wrapper.roomId}")
notificationDisplayer.cancelNotificationMessage( notificationDisplayer.cancelNotificationMessage(
tag = wrapper.roomId.value, tag = wrapper.roomId.value,
id = notificationIdProvider.getRoomMessagesNotificationId(currentUser.userId) id = notificationIdProvider.getRoomMessagesNotificationId(currentUser.userId)
) )
} }
is RoomNotification.Message -> if (useCompleteNotificationFormat) { is RoomNotification.Message -> if (useCompleteNotificationFormat) {
Timber.d("Updating room messages notification ${wrapper.meta.roomId}") Timber.tag(loggerTag.value).d("Updating room messages notification ${wrapper.meta.roomId}")
notificationDisplayer.showNotificationMessage( notificationDisplayer.showNotificationMessage(
tag = wrapper.meta.roomId.value, tag = wrapper.meta.roomId.value,
id = notificationIdProvider.getRoomMessagesNotificationId(currentUser.userId), id = notificationIdProvider.getRoomMessagesNotificationId(currentUser.userId),
@ -84,14 +87,14 @@ class NotificationRenderer @Inject constructor(
invitationNotifications.forEach { wrapper -> invitationNotifications.forEach { wrapper ->
when (wrapper) { when (wrapper) {
is OneShotNotification.Removed -> { is OneShotNotification.Removed -> {
Timber.d("Removing invitation notification ${wrapper.key}") Timber.tag(loggerTag.value).d("Removing invitation notification ${wrapper.key}")
notificationDisplayer.cancelNotificationMessage( notificationDisplayer.cancelNotificationMessage(
tag = wrapper.key, tag = wrapper.key,
id = notificationIdProvider.getRoomInvitationNotificationId(currentUser.userId) id = notificationIdProvider.getRoomInvitationNotificationId(currentUser.userId)
) )
} }
is OneShotNotification.Append -> if (useCompleteNotificationFormat) { is OneShotNotification.Append -> if (useCompleteNotificationFormat) {
Timber.d("Updating invitation notification ${wrapper.meta.key}") Timber.tag(loggerTag.value).d("Updating invitation notification ${wrapper.meta.key}")
notificationDisplayer.showNotificationMessage( notificationDisplayer.showNotificationMessage(
tag = wrapper.meta.key, tag = wrapper.meta.key,
id = notificationIdProvider.getRoomInvitationNotificationId(currentUser.userId), id = notificationIdProvider.getRoomInvitationNotificationId(currentUser.userId),
@ -104,14 +107,14 @@ class NotificationRenderer @Inject constructor(
simpleNotifications.forEach { wrapper -> simpleNotifications.forEach { wrapper ->
when (wrapper) { when (wrapper) {
is OneShotNotification.Removed -> { is OneShotNotification.Removed -> {
Timber.d("Removing simple notification ${wrapper.key}") Timber.tag(loggerTag.value).d("Removing simple notification ${wrapper.key}")
notificationDisplayer.cancelNotificationMessage( notificationDisplayer.cancelNotificationMessage(
tag = wrapper.key, tag = wrapper.key,
id = notificationIdProvider.getRoomEventNotificationId(currentUser.userId) id = notificationIdProvider.getRoomEventNotificationId(currentUser.userId)
) )
} }
is OneShotNotification.Append -> if (useCompleteNotificationFormat) { is OneShotNotification.Append -> if (useCompleteNotificationFormat) {
Timber.d("Updating simple notification ${wrapper.meta.key}") Timber.tag(loggerTag.value).d("Updating simple notification ${wrapper.meta.key}")
notificationDisplayer.showNotificationMessage( notificationDisplayer.showNotificationMessage(
tag = wrapper.meta.key, tag = wrapper.meta.key,
id = notificationIdProvider.getRoomEventNotificationId(currentUser.userId), id = notificationIdProvider.getRoomEventNotificationId(currentUser.userId),
@ -124,14 +127,14 @@ class NotificationRenderer @Inject constructor(
fallbackNotifications.forEach { wrapper -> fallbackNotifications.forEach { wrapper ->
when (wrapper) { when (wrapper) {
is OneShotNotification.Removed -> { is OneShotNotification.Removed -> {
Timber.d("Removing fallback notification ${wrapper.key}") Timber.tag(loggerTag.value).d("Removing fallback notification ${wrapper.key}")
notificationDisplayer.cancelNotificationMessage( notificationDisplayer.cancelNotificationMessage(
tag = wrapper.key, tag = wrapper.key,
id = notificationIdProvider.getFallbackNotificationId(currentUser.userId) id = notificationIdProvider.getFallbackNotificationId(currentUser.userId)
) )
} }
is OneShotNotification.Append -> if (useCompleteNotificationFormat) { is OneShotNotification.Append -> if (useCompleteNotificationFormat) {
Timber.d("Updating fallback notification ${wrapper.meta.key}") Timber.tag(loggerTag.value).d("Updating fallback notification ${wrapper.meta.key}")
notificationDisplayer.showNotificationMessage( notificationDisplayer.showNotificationMessage(
tag = wrapper.meta.key, tag = wrapper.meta.key,
id = notificationIdProvider.getFallbackNotificationId(currentUser.userId), id = notificationIdProvider.getFallbackNotificationId(currentUser.userId),
@ -143,7 +146,7 @@ class NotificationRenderer @Inject constructor(
// Update summary last to avoid briefly displaying it before other notifications // Update summary last to avoid briefly displaying it before other notifications
if (summaryNotification is SummaryNotification.Update) { if (summaryNotification is SummaryNotification.Update) {
Timber.d("Updating summary notification") Timber.tag(loggerTag.value).d("Updating summary notification")
notificationDisplayer.showNotificationMessage( notificationDisplayer.showNotificationMessage(
tag = null, tag = null,
id = notificationIdProvider.getSummaryNotificationId(currentUser.userId), id = notificationIdProvider.getSummaryNotificationId(currentUser.userId),

View file

@ -39,11 +39,10 @@ class NotificationState(
) { ) {
fun <T> updateQueuedEvents( fun <T> updateQueuedEvents(
drawerManager: DefaultNotificationDrawerManager, action: (NotificationEventQueue, List<ProcessedEvent<NotifiableEvent>>) -> T
action: DefaultNotificationDrawerManager.(NotificationEventQueue, List<ProcessedEvent<NotifiableEvent>>) -> T
): T { ): T {
return synchronized(queuedEvents) { return synchronized(queuedEvents) {
action(drawerManager, queuedEvents, renderedEvents) action(queuedEvents, renderedEvents)
} }
} }

View file

@ -24,7 +24,6 @@ import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
import io.element.android.libraries.push.impl.PushersManager import io.element.android.libraries.push.impl.PushersManager
import io.element.android.libraries.push.impl.log.pushLoggerTag
import io.element.android.libraries.push.impl.notifications.DefaultNotificationDrawerManager import io.element.android.libraries.push.impl.notifications.DefaultNotificationDrawerManager
import io.element.android.libraries.push.impl.notifications.NotifiableEventResolver import io.element.android.libraries.push.impl.notifications.NotifiableEventResolver
import io.element.android.libraries.push.impl.store.DefaultPushDataStore import io.element.android.libraries.push.impl.store.DefaultPushDataStore
@ -40,7 +39,7 @@ import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("PushHandler", pushLoggerTag) private val loggerTag = LoggerTag("PushHandler", LoggerTag.PushLoggerTag)
@ContributesBinding(AppScope::class) @ContributesBinding(AppScope::class)
class DefaultPushHandler @Inject constructor( class DefaultPushHandler @Inject constructor(
@ -67,7 +66,7 @@ class DefaultPushHandler @Inject constructor(
* @param pushData the data received in the push. * @param pushData the data received in the push.
*/ */
override suspend fun handle(pushData: PushData) { override suspend fun handle(pushData: PushData) {
Timber.tag(loggerTag.value).d("## handling pushData") Timber.tag(loggerTag.value).d("## handling pushData: ${pushData.roomId}/${pushData.eventId}")
if (buildMeta.lowPrivacyLoggingEnabled) { if (buildMeta.lowPrivacyLoggingEnabled) {
Timber.tag(loggerTag.value).d("## pushData: $pushData") Timber.tag(loggerTag.value).d("## pushData: $pushData")

View file

@ -28,7 +28,7 @@ class FakeNotificationDrawerManager : NotificationDrawerManager {
clearMemberShipNotificationForSessionCallsCount.merge(sessionId.value, 1) { oldValue, value -> oldValue + value } clearMemberShipNotificationForSessionCallsCount.merge(sessionId.value, 1) { oldValue, value -> oldValue + value }
} }
override fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId) { override fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId, doRender: Boolean) {
val key = getMembershipNotificationKey(sessionId, roomId) val key = getMembershipNotificationKey(sessionId, roomId)
clearMemberShipNotificationForRoomCallsCount.merge(key, 1) { oldValue, value -> oldValue + value } clearMemberShipNotificationForRoomCallsCount.merge(key, 1) { oldValue, value -> oldValue + value }
} }

View file

@ -26,7 +26,7 @@ import io.element.android.libraries.sessionstorage.api.toUserList
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("FirebaseNewTokenHandler") private val loggerTag = LoggerTag("FirebaseNewTokenHandler", LoggerTag.PushLoggerTag)
/** /**
* Handle new token receive from Firebase. Will update all the sessions which are using Firebase as a push provider. * Handle new token receive from Firebase. Will update all the sessions which are using Firebase as a push provider.

View file

@ -26,7 +26,7 @@ import io.element.android.libraries.pushproviders.api.PusherSubscriber
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("FirebasePushProvider") private val loggerTag = LoggerTag("FirebasePushProvider", LoggerTag.PushLoggerTag)
@ContributesMultibinding(AppScope::class) @ContributesMultibinding(AppScope::class)
class FirebasePushProvider @Inject constructor( class FirebasePushProvider @Inject constructor(

View file

@ -27,7 +27,7 @@ import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("Firebase") private val loggerTag = LoggerTag("VectorFirebaseMessagingService", LoggerTag.PushLoggerTag)
class VectorFirebaseMessagingService : FirebaseMessagingService() { class VectorFirebaseMessagingService : FirebaseMessagingService() {
@Inject lateinit var firebaseNewTokenHandler: FirebaseNewTokenHandler @Inject lateinit var firebaseNewTokenHandler: FirebaseNewTokenHandler

View file

@ -24,7 +24,7 @@ import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("UnifiedPushNewGatewayHandler") private val loggerTag = LoggerTag("UnifiedPushNewGatewayHandler", LoggerTag.PushLoggerTag)
/** /**
* Handle new endpoint received from UnifiedPush. Will update all the sessions which are using UnifiedPush as a push provider. * Handle new endpoint received from UnifiedPush. Will update all the sessions which are using UnifiedPush as a push provider.

View file

@ -28,7 +28,7 @@ import org.unifiedpush.android.connector.MessagingReceiver
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private val loggerTag = LoggerTag("VectorUnifiedPushMessagingReceiver") private val loggerTag = LoggerTag("VectorUnifiedPushMessagingReceiver", LoggerTag.PushLoggerTag)
class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
@Inject lateinit var pushParser: UnifiedPushParser @Inject lateinit var pushParser: UnifiedPushParser