From 4e6b34b9d150a13cce1a7d14b902a9f69b85b9c5 Mon Sep 17 00:00:00 2001 From: Valere Date: Sat, 22 Jun 2019 17:08:45 +0200 Subject: [PATCH] Fix issues on Notification Event resolver --- .../main/java/im/vector/matrix/rx/RxRoom.kt | 2 +- .../matrix/android/api/session/room/Room.kt | 4 +- .../room/model/call/CallInviteContent.kt | 2 + .../internal/session/room/DefaultRoom.kt | 11 +- .../api/pushrules/PushrulesConditionTest.kt | 5 +- .../fcm/VectorFirebaseMessagingService.kt | 62 ++++---- .../vector/riotredesign/core/di/AppModule.kt | 4 +- .../timeline/format/NoticeEventFormatter.kt | 16 ++ .../notifications/NotifiableEventResolver.kt | 150 +++++++++--------- .../NotificationDrawerManager.kt | 23 ++- .../notifications/OutdatedEventDetector.kt | 3 +- 11 files changed, 151 insertions(+), 131 deletions(-) diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt index c9dbbdd068..6c5724be29 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxRoom.kt @@ -23,7 +23,7 @@ import io.reactivex.Observable class RxRoom(private val room: Room) { fun liveRoomSummary(): Observable { - return room.roomSummary.asObservable() + return room.liveRoomSummary.asObservable() } fun liveRoomMemberIds(): Observable> { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt index fe6a5443e9..3e893a091d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt @@ -47,6 +47,8 @@ interface Room : * A live [RoomSummary] associated with the room * You can observe this summary to get dynamic data from this room. */ - val roomSummary: LiveData + val liveRoomSummary: LiveData + + val roomSummary: RoomSummary? } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt index b47e7ba291..2ec393a0cc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/call/CallInviteContent.kt @@ -39,4 +39,6 @@ data class CallInviteContent( } } + + fun isVideo(): Boolean = offer.sdp.contains(Offer.SDP_VIDEO) } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt index 5c37fa7d87..68f5f89255 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt @@ -52,7 +52,7 @@ internal class DefaultRoom( RelationService by relationService, MembershipService by roomMembersService { - override val roomSummary: LiveData by lazy { + override val liveRoomSummary: LiveData by lazy { val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) } @@ -68,6 +68,15 @@ internal class DefaultRoom( } } + override val roomSummary: RoomSummary? + get() { + var sum: RoomSummaryEntity? = null + monarchy.runTransactionSync { + sum = RoomSummaryEntity.where(it, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME).findFirst() + } + return sum?.asDomain() + } + override fun isEncrypted(): Boolean { return cryptoService.isRoomEncrypted(roomId) } diff --git a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt index d9b81917b2..11c2be1db9 100644 --- a/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt +++ b/matrix-sdk-android/src/test/java/im/vector/matrix/android/api/pushrules/PushrulesConditionTest.kt @@ -175,7 +175,10 @@ class PushrulesConditionTest { return _numberOfJoinedMembers } - override val roomSummary: LiveData + override val liveRoomSummary: LiveData + get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. + + override val roomSummary: RoomSummary? get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. override fun createTimeline(eventId: String?, allowedTypes: List?): Timeline { diff --git a/vector/src/gplay/java/im/vector/riotredesign/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/riotredesign/push/fcm/VectorFirebaseMessagingService.kt index c6da01a3b3..14fed48dbd 100755 --- a/vector/src/gplay/java/im/vector/riotredesign/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/riotredesign/push/fcm/VectorFirebaseMessagingService.kt @@ -49,10 +49,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { private val notificationDrawerManager by inject() private val pusherManager by inject() - private val notifiableEventResolver by lazy { - NotifiableEventResolver(this) - } - + private val notifiableEventResolver by inject() // UI handler private val mUIHandler by lazy { Handler(Looper.getMainLooper()) @@ -69,8 +66,8 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { return } if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.i("## onMessageReceived()" + message.data.toString()) - Timber.i("## onMessageReceived() from FCM with priority " + message.priority) + Timber.i("## onMessageReceived() %s", message.data.toString()) + Timber.i("## onMessageReceived() from FCM with priority %s", message.priority) } mUIHandler.post { if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { @@ -168,7 +165,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { val room = session.getRoom(roomId) ?: return false return room.getTimeLineEvent(eventId) != null } catch (e: Exception) { - Timber.e(e, "## isEventAlreadyKnown() : failed to check if the event was already defined " + e.message) + Timber.e(e, "## isEventAlreadyKnown() : failed to check if the event was already defined") } } @@ -209,44 +206,39 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { return } else { - val event = parseEvent(data) - if (event?.roomId == null) { - //unsupported event - Timber.e("Received an event with no room id") - return + val event = parseEvent(data) ?: return + + val notifiableEvent = notifiableEventResolver.resolveEvent(event, session) + + if (notifiableEvent == null) { + Timber.e("Unsupported notifiable event ${eventId}") + if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { + Timber.e("--> ${event}") + } } else { - var notifiableEvent = notifiableEventResolver.resolveEvent(event, session) - if (notifiableEvent == null) { - Timber.e("Unsupported notifiable event ${eventId}") - if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.e("--> ${event}") + if (notifiableEvent is NotifiableMessageEvent) { + if (TextUtils.isEmpty(notifiableEvent.senderName)) { + notifiableEvent.senderName = data["sender_display_name"] + ?: data["sender"] ?: "" } - } else { - - - if (notifiableEvent is NotifiableMessageEvent) { - if (TextUtils.isEmpty(notifiableEvent.senderName)) { - notifiableEvent.senderName = data["sender_display_name"] - ?: data["sender"] ?: "" - } - if (TextUtils.isEmpty(notifiableEvent.roomName)) { - notifiableEvent.roomName = findRoomNameBestEffort(data, session) ?: "" - } + if (TextUtils.isEmpty(notifiableEvent.roomName)) { + notifiableEvent.roomName = findRoomNameBestEffort(data, session) ?: "" } - - notifiableEvent.isPushGatewayEvent = true - notifiableEvent.matrixID = session.sessionParams.credentials.userId - notificationDrawerManager.onNotifiableEventReceived(notifiableEvent) - notificationDrawerManager.refreshNotificationDrawer() } + + notifiableEvent.isPushGatewayEvent = true + notifiableEvent.matrixID = session.sessionParams.credentials.userId + notificationDrawerManager.onNotifiableEventReceived(notifiableEvent) + notificationDrawerManager.refreshNotificationDrawer() } } + } private fun findRoomNameBestEffort(data: Map, session: Session?): String? { - var roomName: String? = data["room_name"] + val roomName: String? = data["room_name"] val roomId = data["room_id"] if (null == roomName && null != roomId) { // Try to get the room name from our store @@ -281,7 +273,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { // TODO content = data.getValue("content"), originServerTs = System.currentTimeMillis()) } catch (e: Exception) { - Timber.e(e, "buildEvent fails " + e.localizedMessage) + Timber.e(e, "buildEvent fails ") } return null diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt index f26d2c3eb1..85f0d3a584 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt @@ -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 { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/format/NoticeEventFormatter.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/format/NoticeEventFormatter.kt index 595fa766c3..cf2dc4786b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/format/NoticeEventFormatter.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/format/NoticeEventFormatter.kt @@ -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() ?: return null return if (!TextUtils.isEmpty(content.name)) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotifiableEventResolver.kt index 1854ccd098..650a62f8e1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotifiableEventResolver.kt @@ -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()?.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()?.body + ?: event.root.getClearContent().toModel()?.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()?.body - ?: context.getString(R.string.notification_unknown_new_event) - val roomName = event.roomId ?: "room" - val senderDisplayName = tEvent?.senderName ?: "?" + val body = event.root.getClearContent().toModel()?.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() ?: 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 - } */ + } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt index 5bf7caa7d0..d1ff76f77a 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt @@ -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 ") diff --git a/vector/src/main/java/im/vector/riotredesign/features/notifications/OutdatedEventDetector.kt b/vector/src/main/java/im/vector/riotredesign/features/notifications/OutdatedEventDetector.kt index 4ebbe68651..067ab9e77c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/notifications/OutdatedEventDetector.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/notifications/OutdatedEventDetector.kt @@ -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.