Fix issues on Notification Event resolver

This commit is contained in:
Valere
2019-06-22 17:08:45 +02:00
committed by Benoit Marty
parent 6743dc6273
commit 4e6b34b9d1
11 changed files with 151 additions and 131 deletions

View File

@ -90,7 +90,7 @@ class AppModule(private val context: Context) {
}
single {
OutdatedEventDetector(context)
OutdatedEventDetector()
}
single {
@ -98,7 +98,7 @@ class AppModule(private val context: Context) {
}
single {
NotifiableEventResolver(context)
NotifiableEventResolver(get(), get())
}
factory {

View File

@ -46,6 +46,22 @@ class NoticeEventFormatter(private val stringProvider: StringProvider) {
}
}
fun format(event: Event, senderName: String?): CharSequence? {
return when (val type = event.getClearType()) {
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(event, senderName)
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(event, senderName)
EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(event, senderName)
EventType.STATE_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(event, senderName)
EventType.CALL_INVITE,
EventType.CALL_HANGUP,
EventType.CALL_ANSWER -> formatCallEvent(event, senderName)
else -> {
Timber.v("Type $type not handled by this formatter")
null
}
}
}
private fun formatRoomNameEvent(event: Event, senderName: String?): CharSequence? {
val content = event.getClearContent().toModel<RoomNameContent>() ?: return null
return if (!TextUtils.isEmpty(content.name)) {

View File

@ -15,16 +15,19 @@
*/
package im.vector.riotredesign.features.notifications
import android.content.Context
import im.vector.matrix.android.api.pushrules.rest.PushRule
import androidx.core.app.NotificationCompat
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomMember
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.riotredesign.BuildConfig
import im.vector.riotredesign.R
import im.vector.riotredesign.core.preference.BingRule
import im.vector.riotredesign.core.resources.StringProvider
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
import timber.log.Timber
// TODO Remove
@ -39,46 +42,44 @@ class RoomState {
* The NotifiableEventResolver is the only aware of session/store, the NotificationDrawerManager has no knowledge of that,
* this pattern allow decoupling between the object responsible of displaying notifications and the matrix sdk.
*/
class NotifiableEventResolver(val context: Context) {
class NotifiableEventResolver(val stringProvider: StringProvider,
val noticeEventFormatter: NoticeEventFormatter) {
//private val eventDisplay = RiotEventDisplay(context)
fun resolveEvent(event: Event/*, roomState: RoomState?, bingRule: PushRule?*/, session: Session): NotifiableEvent? {
// val store = session.dataHandler.store
// if (store == null) {
// Log.e("## NotifiableEventResolver, unable to get store")
// //TODO notify somehow that something did fail?
// return null
// }
val roomID = event.roomId ?: return null
val eventId = event.eventId ?: return null
val timelineEvent = session.getRoom(roomID)?.getTimeLineEvent(eventId) ?: return null
when (event.getClearType()) {
EventType.MESSAGE -> {
return resolveMessageEvent(event, session)
return resolveMessageEvent(timelineEvent, session)
}
// EventType.ENCRYPTED -> {
// val messageEvent = resolveMessageEvent(event, bingRule, session, store)
// messageEvent?.lockScreenVisibility = NotificationCompat.VISIBILITY_PRIVATE
// return messageEvent
// }
// EventType.STATE_ROOM_MEMBER -> {
// return resolveStateRoomEvent(event, bingRule, session, store)
// }
else -> {
EventType.ENCRYPTED -> {
val messageEvent = resolveMessageEvent(timelineEvent, session)
messageEvent?.lockScreenVisibility = NotificationCompat.VISIBILITY_PRIVATE
return messageEvent
}
EventType.STATE_ROOM_MEMBER -> {
return resolveStateRoomEvent(event, session)
}
else -> {
//If the event can be displayed, display it as is
// eventDisplay.getTextualDisplay(event, roomState)?.toString()?.let { body ->
// return SimpleNotifiableEvent(
// session.myUserId,
// eventId = event.eventId,
// noisy = bingRule?.notificationSound != null,
// timestamp = event.originServerTs,
// description = body,
// soundName = bingRule?.notificationSound,
// title = context.getString(R.string.notification_unknown_new_event),
// type = event.type)
// }
//TODO Better event text display
val bodyPreview = event.type
return SimpleNotifiableEvent(
session.sessionParams.credentials.userId,
eventId = event.eventId!!,
noisy = false,//will be updated
timestamp = event.originServerTs ?: System.currentTimeMillis(),
description = bodyPreview,
title = stringProvider.getString(R.string.notification_unknown_new_event),
soundName = null,
type = event.type)
//Unsupported event
Timber.w("NotifiableEventResolver Received an unsupported event matching a bing rule")
@ -88,57 +89,55 @@ class NotifiableEventResolver(val context: Context) {
}
private fun resolveMessageEvent(event: Event, session: Session): NotifiableEvent? {
//If we are here, that means that the event should be notified to the user, we check now how it should be presented (sound)
// val soundName = pushRule?.notificationSound
private fun resolveMessageEvent(event: TimelineEvent, session: Session): NotifiableEvent? {
//The event only contains an eventId, and roomId (type is m.room.*) , we need to get the displayable content (names, avatar, text, etc...)
val room = session.getRoom(event.roomId!! /*roomID cannot be null (see Matrix SDK code)*/)
val room = session.getRoom(event.root.roomId!! /*roomID cannot be null*/)
if (room == null) {
Timber.e("## Unable to resolve room for eventId [${event.eventId}] and roomID [${event.roomId}]")
Timber.e("## Unable to resolve room for eventId [${event}]")
// Ok room is not known in store, but we can still display something
val body = event.content?.toModel<MessageContent>()?.body
?: context.getString(R.string.notification_unknown_new_event)
val roomName = context.getString(R.string.notification_unknown_room_name)
val senderDisplayName = event.senderId ?: ""
val body =
event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
?: event.root.getClearContent().toModel<MessageContent>()?.body
?: stringProvider.getString(R.string.notification_unknown_new_event)
val roomName = stringProvider.getString(R.string.notification_unknown_room_name)
val senderDisplayName = event.senderName
val notifiableEvent = NotifiableMessageEvent(
eventId = event.eventId ?: "",
timestamp = event.originServerTs ?: 0,
eventId = event.root.eventId!!,
timestamp = event.root.originServerTs ?: 0,
noisy = false,//will be updated
senderName = senderDisplayName,
senderId = event.senderId,
senderId = event.root.senderId,
body = body,
roomId = event.roomId ?: "",
roomId = event.root.roomId!!,
roomName = roomName)
notifiableEvent.matrixID = session.sessionParams.credentials.userId
// notifiableEvent.soundName = soundName
return notifiableEvent
} else {
val tEvent = room.getTimeLineEvent(event.eventId!!)
val body = event.content?.toModel<MessageContent>()?.body
?: context.getString(R.string.notification_unknown_new_event)
val roomName = event.roomId ?: "room"
val senderDisplayName = tEvent?.senderName ?: "?"
val body = event.root.getClearContent().toModel<MessageContent>()?.body
?: stringProvider.getString(R.string.notification_unknown_new_event)
val roomName = room.roomSummary?.displayName ?: ""
val senderDisplayName = event.senderName ?: ""
val notifiableEvent = NotifiableMessageEvent(
eventId = event.eventId!!,
timestamp = event.originServerTs ?: 0,
eventId = event.root.eventId!!,
timestamp = event.root.originServerTs ?: 0,
noisy = false,//will be updated
senderName = senderDisplayName,
senderId = event.senderId,
senderId = event.root.senderId,
body = body,
roomId = event.roomId ?: "00",
roomId = event.root.roomId!!,
roomName = roomName,
roomIsDirect = true)
roomIsDirect = room.roomSummary?.isDirect ?: false)
notifiableEvent.matrixID = session.sessionParams.credentials.userId
notifiableEvent.soundName = null
//TODO get the avatar?
// val roomAvatarPath = session.mediaCache?.thumbnailCacheFile(room.avatarUrl, 50)
// if (roomAvatarPath != null) {
@ -162,21 +161,24 @@ class NotifiableEventResolver(val context: Context) {
return notifiableEvent
}
}
/*
private fun resolveStateRoomEvent(event: Event, bingRule: BingRule?, session: MXSession, store: IMXStore): NotifiableEvent? {
if (RoomMember.MEMBERSHIP_INVITE == event.contentAsJsonObject?.getAsJsonPrimitive("membership")?.asString) {
val room = store.getRoom(event.roomId /*roomID cannot be null (see Matrix SDK code)*/)
val body = eventDisplay.getTextualDisplay(event, room.state)?.toString()
?: context.getString(R.string.notification_new_invitation)
private fun resolveStateRoomEvent(event: Event, session: Session): NotifiableEvent? {
val content = event.content?.toModel<RoomMember>() ?: return null
val roomId = event.roomId ?: return null
val dName = event.senderId?.let { session.getUser(it)?.displayName }
if (Membership.INVITE == content.membership) {
val body = noticeEventFormatter.format(event, dName)
?: stringProvider.getString(R.string.notification_new_invitation)
return InviteNotifiableEvent(
session.myUserId,
eventId = event.eventId,
roomId = event.roomId,
timestamp = event.originServerTs,
noisy = bingRule?.notificationSound != null,
title = context.getString(R.string.notification_new_invitation),
description = body,
soundName = bingRule?.notificationSound,
session.sessionParams.credentials.userId,
eventId = event.eventId!!,
roomId = roomId,
timestamp = event.originServerTs ?: 0,
noisy = false,//will be set later
title = stringProvider.getString(R.string.notification_new_invitation),
description = body.toString(),
soundName = null, //will be set later
type = event.getClearType(),
isPushGatewayEvent = false)
} else {
@ -187,6 +189,6 @@ class NotifiableEventResolver(val context: Context) {
//TODO generic handling?
}
return null
} */
}
}

View File

@ -22,7 +22,8 @@ import android.graphics.BitmapFactory
import android.text.TextUtils
import androidx.core.app.NotificationCompat
import androidx.core.app.Person
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.riotredesign.BuildConfig
import im.vector.riotredesign.R
import im.vector.riotredesign.core.utils.SecretStoringUtils
@ -36,14 +37,14 @@ import java.io.FileOutputStream
* organise them in order to display them in the notification drawer.
* Events can be grouped into the same notification, old (already read) events can be removed to do some cleaning.
*/
class NotificationDrawerManager(val context: Context, private val outdatedDetector: OutdatedEventDetector?) {
class NotificationDrawerManager(val context: Context,
private val outdatedDetector: OutdatedEventDetector?) {
//The first time the notification drawer is refreshed, we force re-render of all notifications
private var firstTime = true
private var eventList = loadEventInfo()
private var myUserDisplayName: String = "Todo"
private var myUserAvatarUrl: String = ""
private val avatarSize = context.resources.getDimensionPixelSize(R.dimen.profile_avatar_size)
@ -156,17 +157,11 @@ class NotificationDrawerManager(val context: Context, private val outdatedDetect
fun refreshNotificationDrawer() {
if (myUserDisplayName.isBlank()) {
// TODO
// initWithSession(Matrix.getInstance(context).defaultSession)
}
if (myUserDisplayName.isBlank()) {
// Should not happen, but myUserDisplayName cannot be blank if used to create a Person
//TODO
// return
}
val session = Matrix.getInstance().currentSession ?: return
val user = session.getUser(session.sessionParams.credentials.userId)
val myUserDisplayName = user?.displayName ?: ""
val myUserAvatarUrl = session.contentUrlResolver().resolveThumbnail(user?.avatarUrl, avatarSize, avatarSize, ContentUrlResolver.ThumbnailMethod.SCALE)
synchronized(eventList) {
Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER ")

View File

@ -15,10 +15,9 @@
*/
package im.vector.riotredesign.features.notifications
import android.content.Context
import im.vector.matrix.android.api.Matrix
class OutdatedEventDetector(val context: Context) {
class OutdatedEventDetector() {
/**
* Returns true if the given event is outdated.