moving the notifable queue adding to the queue itself and making onNotifiableEventReceived not synchronised for use within the synchronized batching
- makes the refresh function private as all interactions now come through via update
This commit is contained in:
parent
9009606e86
commit
588958c807
|
@ -201,8 +201,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
resolvedEvent
|
resolvedEvent
|
||||||
?.also { Timber.tag(loggerTag.value).d("Fast lane: notify drawer") }
|
?.also { Timber.tag(loggerTag.value).d("Fast lane: notify drawer") }
|
||||||
?.let {
|
?.let {
|
||||||
notificationDrawerManager.onNotifiableEventReceived(it)
|
notificationDrawerManager.updateEvents { it.onNotifiableEventReceived(resolvedEvent) }
|
||||||
notificationDrawerManager.refreshNotificationDrawer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,8 +145,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
||||||
canBeReplaced = false
|
canBeReplaced = false
|
||||||
)
|
)
|
||||||
|
|
||||||
notificationDrawerManager.onNotifiableEventReceived(notifiableMessageEvent)
|
notificationDrawerManager.updateEvents { it.onNotifiableEventReceived(notifiableMessageEvent) }
|
||||||
notificationDrawerManager.refreshNotificationDrawer()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// TODO Error cannot be managed the same way than in Riot
|
// TODO Error cannot be managed the same way than in Riot
|
||||||
|
|
|
@ -93,7 +93,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
|
||||||
#refreshNotificationDrawer() is called.
|
#refreshNotificationDrawer() is called.
|
||||||
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 NotificationEventQueue.onNotifiableEventReceived(notifiableEvent: NotifiableEvent) {
|
||||||
if (!vectorPreferences.areNotificationEnabledForDevice()) {
|
if (!vectorPreferences.areNotificationEnabledForDevice()) {
|
||||||
Timber.i("Notification are disabled for this device")
|
Timber.i("Notification are disabled for this device")
|
||||||
return
|
return
|
||||||
|
@ -105,46 +105,8 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
|
||||||
} else {
|
} else {
|
||||||
Timber.d("onNotifiableEventReceived(): is push: ${notifiableEvent.canBeReplaced}")
|
Timber.d("onNotifiableEventReceived(): is push: ${notifiableEvent.canBeReplaced}")
|
||||||
}
|
}
|
||||||
synchronized(queuedEvents) {
|
|
||||||
val existing = queuedEvents.findExistingById(notifiableEvent)
|
|
||||||
val edited = queuedEvents.findEdited(notifiableEvent)
|
|
||||||
when {
|
|
||||||
existing != null -> {
|
|
||||||
if (existing.canBeReplaced) {
|
|
||||||
// Use the event coming from the event stream as it may contains more info than
|
|
||||||
// the fcm one (like type/content/clear text) (e.g when an encrypted message from
|
|
||||||
// FCM should be update with clear text after a sync)
|
|
||||||
// In this case the message has already been notified, and might have done some noise
|
|
||||||
// So we want the notification to be updated even if it has already been displayed
|
|
||||||
// Use setOnlyAlertOnce to ensure update notification does not interfere with sound
|
|
||||||
// from first notify invocation as outlined in:
|
|
||||||
// https://developer.android.com/training/notify-user/build-notification#Updating
|
|
||||||
queuedEvents.replace(replace = existing, with = notifiableEvent)
|
|
||||||
} else {
|
|
||||||
// keep the existing one, do not replace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
edited != null -> {
|
|
||||||
// Replace the existing notification with the new content
|
|
||||||
queuedEvents.replace(replace = edited, with = notifiableEvent)
|
|
||||||
}
|
|
||||||
seenEventIds.contains(notifiableEvent.eventId) -> {
|
|
||||||
// we've already seen the event, lets skip
|
|
||||||
Timber.d("onNotifiableEventReceived(): skipping event, already seen")
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
seenEventIds.put(notifiableEvent.eventId)
|
|
||||||
queuedEvents.add(notifiableEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateEvents(action: (NotificationEventQueue) -> Unit) {
|
add(notifiableEvent, seenEventIds)
|
||||||
synchronized(queuedEvents) {
|
|
||||||
action(queuedEvents)
|
|
||||||
}
|
|
||||||
refreshNotificationDrawer()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -168,9 +130,27 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun notificationStyleChanged() {
|
||||||
|
updateEvents {
|
||||||
|
val newSettings = vectorPreferences.useCompleteNotificationFormat()
|
||||||
|
if (newSettings != useCompleteNotificationFormat) {
|
||||||
|
// Settings has changed, remove all current notifications
|
||||||
|
notificationDisplayer.cancelAllNotifications()
|
||||||
|
useCompleteNotificationFormat = newSettings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateEvents(action: NotificationDrawerManager.(NotificationEventQueue) -> Unit) {
|
||||||
|
synchronized(queuedEvents) {
|
||||||
|
action(this, queuedEvents)
|
||||||
|
}
|
||||||
|
refreshNotificationDrawer()
|
||||||
|
}
|
||||||
|
|
||||||
private var firstThrottler = FirstThrottler(200)
|
private var firstThrottler = FirstThrottler(200)
|
||||||
|
|
||||||
fun refreshNotificationDrawer() {
|
private fun refreshNotificationDrawer() {
|
||||||
// Implement last throttler
|
// Implement last throttler
|
||||||
val canHandle = firstThrottler.canHandle()
|
val canHandle = firstThrottler.canHandle()
|
||||||
Timber.v("refreshNotificationDrawer(), delay: ${canHandle.waitMillis()} ms")
|
Timber.v("refreshNotificationDrawer(), delay: ${canHandle.waitMillis()} ms")
|
||||||
|
@ -191,14 +171,6 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private fun refreshNotificationDrawerBg() {
|
private fun refreshNotificationDrawerBg() {
|
||||||
Timber.v("refreshNotificationDrawerBg()")
|
Timber.v("refreshNotificationDrawerBg()")
|
||||||
|
|
||||||
val newSettings = vectorPreferences.useCompleteNotificationFormat()
|
|
||||||
if (newSettings != useCompleteNotificationFormat) {
|
|
||||||
// Settings has changed, remove all current notifications
|
|
||||||
notificationDisplayer.cancelAllNotifications()
|
|
||||||
useCompleteNotificationFormat = newSettings
|
|
||||||
}
|
|
||||||
|
|
||||||
val eventsToRender = synchronized(queuedEvents) {
|
val eventsToRender = synchronized(queuedEvents) {
|
||||||
notifiableEventProcessor.process(queuedEvents.rawEvents(), currentRoomId, renderedEvents).also {
|
notifiableEventProcessor.process(queuedEvents.rawEvents(), currentRoomId, renderedEvents).also {
|
||||||
queuedEvents.clearAndAdd(it.onlyKeptEvents())
|
queuedEvents.clearAndAdd(it.onlyKeptEvents())
|
||||||
|
|
|
@ -82,10 +82,41 @@ class NotificationEventQueue(
|
||||||
queue.clear()
|
queue.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(notifiableEvent: NotifiableEvent) {
|
fun add(notifiableEvent: NotifiableEvent, seenEventIds: CircularCache<String>) {
|
||||||
queue.add(notifiableEvent)
|
val existing = findExistingById(notifiableEvent)
|
||||||
|
val edited = findEdited(notifiableEvent)
|
||||||
|
when {
|
||||||
|
existing != null -> {
|
||||||
|
if (existing.canBeReplaced) {
|
||||||
|
// Use the event coming from the event stream as it may contains more info than
|
||||||
|
// the fcm one (like type/content/clear text) (e.g when an encrypted message from
|
||||||
|
// FCM should be update with clear text after a sync)
|
||||||
|
// In this case the message has already been notified, and might have done some noise
|
||||||
|
// So we want the notification to be updated even if it has already been displayed
|
||||||
|
// Use setOnlyAlertOnce to ensure update notification does not interfere with sound
|
||||||
|
// from first notify invocation as outlined in:
|
||||||
|
// https://developer.android.com/training/notify-user/build-notification#Updating
|
||||||
|
replace(replace = existing, with = notifiableEvent)
|
||||||
|
} else {
|
||||||
|
// keep the existing one, do not replace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edited != null -> {
|
||||||
|
// Replace the existing notification with the new content
|
||||||
|
replace(replace = edited, with = notifiableEvent)
|
||||||
|
}
|
||||||
|
seenEventIds.contains(notifiableEvent.eventId) -> {
|
||||||
|
// we've already seen the event, lets skip
|
||||||
|
Timber.d("onNotifiableEventReceived(): skipping event, already seen")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
seenEventIds.put(notifiableEvent.eventId)
|
||||||
|
queue.add(notifiableEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun clearMemberShipNotificationForRoom(roomId: String) {
|
fun clearMemberShipNotificationForRoom(roomId: String) {
|
||||||
Timber.v("clearMemberShipOfRoom $roomId")
|
Timber.v("clearMemberShipOfRoom $roomId")
|
||||||
queue.removeAll { it is InviteNotifiableEvent && it.roomId == roomId }
|
queue.removeAll { it is InviteNotifiableEvent && it.roomId == roomId }
|
||||||
|
|
|
@ -34,7 +34,7 @@ class PushRuleTriggerListener @Inject constructor(
|
||||||
|
|
||||||
override fun onEvents(pushEvents: PushEvents) {
|
override fun onEvents(pushEvents: PushEvents) {
|
||||||
session?.let { session ->
|
session?.let { session ->
|
||||||
pushEvents.matchedEvents.mapNotNull { (event, pushRule) ->
|
val notifiableEvents = pushEvents.matchedEvents.mapNotNull { (event, pushRule) ->
|
||||||
Timber.v("Push rule match for event ${event.eventId}")
|
Timber.v("Push rule match for event ${event.eventId}")
|
||||||
val action = pushRule.getActions().toNotificationAction()
|
val action = pushRule.getActions().toNotificationAction()
|
||||||
if (action.shouldNotify) {
|
if (action.shouldNotify) {
|
||||||
|
@ -43,14 +43,15 @@ class PushRuleTriggerListener @Inject constructor(
|
||||||
Timber.v("Matched push rule is set to not notify")
|
Timber.v("Matched push rule is set to not notify")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}.forEach { notificationDrawerManager.onNotifiableEventReceived(it) }
|
}
|
||||||
|
|
||||||
notificationDrawerManager.updateEvents { queuedEvents ->
|
notificationDrawerManager.updateEvents { queuedEvents ->
|
||||||
|
notifiableEvents.forEach { notifiableEvent ->
|
||||||
|
queuedEvents.onNotifiableEventReceived(notifiableEvent)
|
||||||
|
}
|
||||||
queuedEvents.syncRoomEvents(roomsLeft = pushEvents.roomsLeft, roomsJoined = pushEvents.roomsJoined)
|
queuedEvents.syncRoomEvents(roomsLeft = pushEvents.roomsLeft, roomsJoined = pushEvents.roomsJoined)
|
||||||
queuedEvents.markRedacted(pushEvents.redactedEventIds)
|
queuedEvents.markRedacted(pushEvents.redactedEventIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationDrawerManager.refreshNotificationDrawer()
|
|
||||||
} ?: Timber.e("Called without active session")
|
} ?: Timber.e("Called without active session")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ class VectorSettingsPinFragment @Inject constructor(
|
||||||
|
|
||||||
useCompleteNotificationPref.setOnPreferenceChangeListener { _, _ ->
|
useCompleteNotificationPref.setOnPreferenceChangeListener { _, _ ->
|
||||||
// Refresh the drawer for an immediate effect of this change
|
// Refresh the drawer for an immediate effect of this change
|
||||||
notificationDrawerManager.refreshNotificationDrawer()
|
notificationDrawerManager.notificationStyleChanged()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue