Remove any notification of a redacted event (#563)

Also do some cleanup and kotlinification on the code
This commit is contained in:
Benoit Marty 2019-09-18 16:26:25 +02:00
parent 6f09eea248
commit 7da9cafcc2
11 changed files with 63 additions and 30 deletions

View File

@ -7,6 +7,7 @@ Features:
Improvements:
- Add unread indent on room list (#485)
- Message Editing: Update notifications (#128)
- Remove any notification of a redacted event (#563)
Other changes:
-

View File

@ -43,6 +43,7 @@ interface PushRuleService {
interface PushRuleListener {
fun onMatchRule(event: Event, actions: List<Action>)
fun onRoomLeft(roomId: String)
fun onEventRedacted(redactedEventId: String)
fun batchFinish()
}
}

View File

@ -132,6 +132,16 @@ internal class DefaultPushRuleService @Inject constructor(
}
}
fun dispatchRedactedEventId(redactedEventId: String) {
try {
listeners.forEach {
it.onEventRedacted(redactedEventId)
}
} catch (e: Throwable) {
Timber.e(e, "Error while dispatching room left")
}
}
fun dispatchFinish() {
try {
listeners.forEach {

View File

@ -78,6 +78,25 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
defaultPushRuleService.dispatchBing(event, it)
}
}
val allRedactedEvents = params.syncResponse.join
.map { entries ->
entries.value.timeline?.events?.filter {
it.type == EventType.REDACTION
}
.orEmpty()
.mapNotNull { it.redacts }
}
.fold(emptyList<String>(), { acc, next ->
acc + next
})
Timber.v("[PushRules] Found ${allRedactedEvents.size} redacted events")
allRedactedEvents.forEach { redactedEventId ->
defaultPushRuleService.dispatchRedactedEventId(redactedEventId)
}
defaultPushRuleService.dispatchFinish()
}

View File

@ -196,7 +196,6 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
// This ID can and should be used to detect duplicate notification requests.
val eventId = data["event_id"] ?: return //Just ignore
val eventType = data["type"]
if (eventType == null) {
//Just add a generic unknown event
@ -214,10 +213,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
)
notificationDrawerManager.onNotifiableEventReceived(simpleNotifiableEvent)
notificationDrawerManager.refreshNotificationDrawer()
return
} else {
val event = parseEvent(data) ?: return
val notifiableEvent = notifiableEventResolver.resolveEvent(event, session)
@ -228,8 +224,6 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
Timber.e("--> ${event}")
}
} else {
if (notifiableEvent is NotifiableMessageEvent) {
if (TextUtils.isEmpty(notifiableEvent.senderName)) {
notifiableEvent.senderName = data["sender_display_name"]
@ -246,7 +240,6 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
notificationDrawerManager.refreshNotificationDrawer()
}
}
}
private fun findRoomNameBestEffort(data: Map<String, String>, session: Session?): String? {

View File

@ -32,6 +32,7 @@ data class InviteNotifiableEvent(
override var isPushGatewayEvent: Boolean = false) : NotifiableEvent {
override var hasBeenDisplayed: Boolean = false
override var isRedacted: Boolean = false
override var lockScreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
}

View File

@ -31,6 +31,7 @@ interface NotifiableEvent : Serializable {
// Compat: Only for android <7, for newer version the sound is defined in the channel
var soundName: String?
var hasBeenDisplayed: Boolean
var isRedacted: Boolean
//Used to know if event should be replaced with the one coming from eventstream
var isPushGatewayEvent: Boolean
}

View File

@ -36,6 +36,7 @@ data class NotifiableMessageEvent(
override var soundName: String? = null
override var lockScreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
override var hasBeenDisplayed: Boolean = false
override var isRedacted: Boolean = false
var roomAvatarPath: String? = null
var senderAvatarPath: String? = null

View File

@ -15,7 +15,6 @@
*/
package im.vector.riotx.features.notifications
import android.app.Notification
import android.content.Context
import android.graphics.Bitmap
import android.os.Handler
@ -96,7 +95,6 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
notifiableEvent.noisy = false
eventList.remove(existing)
eventList.add(notifiableEvent)
} else {
//keep the existing one, do not replace
}
@ -127,6 +125,15 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
}
}
fun onEventRedacted(eventId: String) {
synchronized(eventList) {
eventList.filter { it.eventId == eventId }.map { notifiableEvent ->
notifiableEvent.isRedacted = true
notifiableEvent.hasBeenDisplayed = false
}
}
}
/**
Clear all known events and refresh the notification drawer
*/
@ -215,20 +222,15 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
val summaryInboxStyle = NotificationCompat.InboxStyle()
//group events by room to create a single MessagingStyle notif
val roomIdToEventMap: MutableMap<String, ArrayList<NotifiableMessageEvent>> = HashMap()
val simpleEvents: ArrayList<NotifiableEvent> = ArrayList()
val notifications: ArrayList<Notification> = ArrayList()
val roomIdToEventMap: MutableMap<String, MutableList<NotifiableMessageEvent>> = LinkedHashMap()
val simpleEvents: MutableList<NotifiableEvent> = ArrayList()
val eventIterator = eventList.listIterator()
while (eventIterator.hasNext()) {
val event = eventIterator.next()
if (event is NotifiableMessageEvent) {
val roomId = event.roomId
var roomEvents = roomIdToEventMap[roomId]
if (roomEvents == null) {
roomEvents = ArrayList()
roomIdToEventMap[roomId] = roomEvents
}
val roomEvents = roomIdToEventMap.getOrPut(roomId) { ArrayList() }
if (shouldIgnoreMessageEventInRoom(roomId) || outdatedDetector?.isMessageOutdated(event) == true) {
//forget this event
@ -246,10 +248,10 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
var globalLastMessageTimestamp = 0L
//events have been grouped
//events have been grouped by roomId
for ((roomId, events) in roomIdToEventMap) {
if (events.isEmpty()) {
// Build the notification for the room
if (events.isEmpty() || events.all { it.isRedacted }) {
//Just clear this notification
Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER $roomId has no more events")
NotificationUtils.cancelNotificationMessage(context, roomId, ROOM_MESSAGES_NOTIFICATION_ID)
@ -280,7 +282,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
for (event in events) {
//if all events in this room have already been displayed there is no need to update it
if (!event.hasBeenDisplayed) {
if (!event.hasBeenDisplayed && !event.isRedacted) {
roomEventGroupInfo.shouldBing = roomEventGroupInfo.shouldBing || event.noisy
roomEventGroupInfo.customSound = event.soundName
}
@ -296,7 +298,9 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
style.addMessage(context.getString(R.string.notification_inline_reply_failed), event.timestamp, senderPerson)
roomEventGroupInfo.hasSmartReplyError = true
} else {
style.addMessage(event.body, event.timestamp, senderPerson)
if (!event.isRedacted) {
style.addMessage(event.body, event.timestamp, senderPerson)
}
}
event.hasBeenDisplayed = true //we can consider it as displayed
@ -356,7 +360,6 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
myUserDisplayName)
?.let {
//is there an id for this room?
notifications.add(it)
NotificationUtils.showNotificationMessage(context, roomId, ROOM_MESSAGES_NOTIFICATION_ID, it)
}
hasNewEvent = true
@ -372,7 +375,6 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
//We build a simple event
if (firstTime || !event.hasBeenDisplayed) {
NotificationUtils.buildSimpleEventNotification(context, vectorPreferences, event, null, session.myUserId)?.let {
notifications.add(it)
NotificationUtils.showNotificationMessage(context, event.eventId, ROOM_EVENT_NOTIFICATION_ID, it)
event.hasBeenDisplayed = true //we can consider it as displayed
hasNewEvent = true
@ -396,7 +398,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
// To ensure the best experience on all devices and versions, always include a group summary when you create a group
// https://developer.android.com/training/notify-user/group
if (eventList.isEmpty()) {
if (eventList.isEmpty() || eventList.all { it.isRedacted }) {
NotificationUtils.cancelNotificationMessage(context, null, SUMMARY_NOTIFICATION_ID)
} else {
val nbEvents = roomIdToEventMap.size + simpleEvents.size
@ -443,12 +445,11 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
}
}
private fun getRoomBitmap(events: ArrayList<NotifiableMessageEvent>): Bitmap? {
private fun getRoomBitmap(events: List<NotifiableMessageEvent>): Bitmap? {
if (events.isEmpty()) return null
//Use the last event (most recent?)
val roomAvatarPath = events.last().roomAvatarPath
?: events.last().senderAvatarPath
val roomAvatarPath = events.last().roomAvatarPath ?: events.last().senderAvatarPath
return bitmapLoader.getRoomBitmap(roomAvatarPath)
}
@ -476,14 +477,14 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
}
}
private fun loadEventInfo(): ArrayList<NotifiableEvent> {
private fun loadEventInfo(): MutableList<NotifiableEvent> {
try {
val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
if (file.exists()) {
FileInputStream(file).use {
val events: ArrayList<NotifiableEvent>? = activeSessionHolder.getSafeActiveSession()?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE)
if (events != null) {
return ArrayList(events.mapNotNull { it as? NotifiableEvent })
return events.toMutableList()
}
}
}

View File

@ -60,6 +60,10 @@ class PushRuleTriggerListener @Inject constructor(
notificationDrawerManager.clearMessageEventOfRoom(roomId)
}
override fun onEventRedacted(redactedEventId: String) {
notificationDrawerManager.onEventRedacted(redactedEventId)
}
override fun batchFinish() {
notificationDrawerManager.refreshNotificationDrawer()
}

View File

@ -30,6 +30,7 @@ data class SimpleNotifiableEvent(
override var isPushGatewayEvent: Boolean = false) : NotifiableEvent {
override var hasBeenDisplayed: Boolean = false
override var isRedacted: Boolean = false
override var lockScreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
}