From 96153fe92a3e865ecdb8164609ddd0400fcb36ef Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Mar 2021 18:48:25 +0100 Subject: [PATCH] Get Event after a Push for a faster notification display in some conditions --- CHANGES.md | 1 + .../matrix/android/sdk/api/session/Session.kt | 2 + .../sdk/api/session/events/EventService.kt | 28 ++++++++++ .../internal/database/query/ReadQueries.kt | 23 ++++---- .../sdk/internal/session/DefaultSession.kt | 3 ++ .../sdk/internal/session/SessionModule.kt | 7 ++- .../session/call/CallEventProcessor.kt | 13 ++++- .../session/call/CallSignalingHandler.kt | 20 ++++--- .../session/events/DefaultEventService.kt | 40 ++++++++++++++ .../sdk/internal/session/room/RoomModule.kt | 5 ++ .../session/room/timeline/GetEventTask.kt | 43 +++++++++++---- .../fcm/VectorFirebaseMessagingService.kt | 54 ++++++++++++++++--- .../notifications/NotifiableEventResolver.kt | 30 +++++++++-- .../NotificationDrawerManager.kt | 6 ++- 14 files changed, 234 insertions(+), 41 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/events/DefaultEventService.kt diff --git a/CHANGES.md b/CHANGES.md index 13385123e6..86ba91c9df 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,7 @@ Improvements 🙌: - Add better support for empty room name fallback (#3106) - Room list improvements (paging) - Fix quick click action (#3127) + - Get Event after a Push for a faster notification display in some conditions Bugfix 🐛: - Fix bad theme change for the MainActivity diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index 7a24ccac11..a15799d862 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.session.call.CallSignalingService import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.api.session.crypto.CryptoService +import org.matrix.android.sdk.api.session.events.EventService import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.group.GroupService @@ -68,6 +69,7 @@ interface Session : SignOutService, FilterService, TermsService, + EventService, ProfileService, PushRuleService, PushersService, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt new file mode 100644 index 0000000000..41bc0a1a62 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/EventService.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.api.session.events + +import org.matrix.android.sdk.api.session.events.model.Event + +interface EventService { + + /** + * Ask the homeserver for an event content. The SDK will try to decrypt it if it is possible + * The result will not be stored into cache + */ + suspend fun getEvent(roomId: String, eventId: String): Event +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt index a3c741ad55..5423025823 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/ReadQueries.kt @@ -38,16 +38,21 @@ internal fun isEventRead(realmConfiguration: RealmConfiguration, Realm.getInstance(realmConfiguration).use { realm -> val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@use val eventToCheck = liveChunk.timelineEvents.find(eventId) - isEventRead = if (eventToCheck == null || eventToCheck.root?.sender == userId) { - true - } else { - val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() - ?: return@use - val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.displayIndex - ?: Int.MIN_VALUE - val eventToCheckIndex = eventToCheck.displayIndex + isEventRead = when { + eventToCheck == null -> { + // This can happen in case of fast lane Event + false + } + eventToCheck.root?.sender == userId -> true + else -> { + val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() + ?: return@use + val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.displayIndex + ?: Int.MIN_VALUE + val eventToCheckIndex = eventToCheck.displayIndex - eventToCheckIndex <= readReceiptIndex + eventToCheckIndex <= readReceiptIndex + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 45fcc5af2d..821a9cba8c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.session.call.CallSignalingService import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.api.session.crypto.CryptoService +import org.matrix.android.sdk.api.session.events.EventService import org.matrix.android.sdk.api.session.file.ContentDownloadStateTracker import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.group.GroupService @@ -114,6 +115,7 @@ internal class DefaultSession @Inject constructor( private val accountDataService: Lazy, private val _sharedSecretStorageService: Lazy, private val accountService: Lazy, + private val eventService: Lazy, private val defaultIdentityService: DefaultIdentityService, private val integrationManagerService: IntegrationManagerService, private val thirdPartyService: Lazy, @@ -129,6 +131,7 @@ internal class DefaultSession @Inject constructor( FilterService by filterService.get(), PushRuleService by pushRuleService.get(), PushersService by pushersService.get(), + EventService by eventService.get(), TermsService by termsService.get(), InitialSyncProgressService by initialSyncProgressService.get(), SecureStorageService by secureStorageService.get(), diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index f10eb67921..e61e4ecd89 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -32,10 +32,11 @@ import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.auth.data.sessionId import org.matrix.android.sdk.api.crypto.MXCryptoConfig -import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.AccountDataService +import org.matrix.android.sdk.api.session.events.EventService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService +import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.securestorage.SecureStorageService import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService @@ -75,6 +76,7 @@ import org.matrix.android.sdk.internal.network.token.AccessTokenProvider import org.matrix.android.sdk.internal.network.token.HomeserverAccessTokenProvider import org.matrix.android.sdk.internal.session.call.CallEventProcessor import org.matrix.android.sdk.internal.session.download.DownloadProgressInterceptor +import org.matrix.android.sdk.internal.session.events.DefaultEventService import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapabilitiesService import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService import org.matrix.android.sdk.internal.session.initsync.DefaultInitialSyncProgressService @@ -357,6 +359,9 @@ internal abstract class SessionModule { @Binds abstract fun bindAccountDataService(service: DefaultAccountDataService): AccountDataService + @Binds + abstract fun bindEventService(service: DefaultEventService): EventService + @Binds abstract fun bindSharedSecretStorageService(service: DefaultSharedSecretStorageService): SharedSecretStorageService diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt index 4887351709..a190ff62ac 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt @@ -21,9 +21,11 @@ import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.internal.database.model.EventInsertType import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor +import org.matrix.android.sdk.internal.session.SessionScope import timber.log.Timber import javax.inject.Inject +@SessionScope internal class CallEventProcessor @Inject constructor(private val callSignalingHandler: CallSignalingHandler) : EventInsertLiveProcessor { @@ -51,6 +53,15 @@ internal class CallEventProcessor @Inject constructor(private val callSignalingH eventsToPostProcess.add(event) } + fun shouldProcessFastLane(eventType: String): Boolean { + return eventType == EventType.CALL_INVITE + } + + suspend fun processFastLane(event: Event) { + eventsToPostProcess.add(event) + onPostProcess() + } + override suspend fun onPostProcess() { eventsToPostProcess.forEach { dispatchToCallSignalingHandlerIfNeeded(it) @@ -60,7 +71,7 @@ internal class CallEventProcessor @Inject constructor(private val callSignalingH private fun dispatchToCallSignalingHandlerIfNeeded(event: Event) { val now = System.currentTimeMillis() - // TODO might check if an invite is not closed (hangup/answsered) in the same event batch? + // TODO might check if an invite is not closed (hangup/answered) in the same event batch? event.roomId ?: return Unit.also { Timber.w("Event with no room id ${event.eventId}") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index 7e54301f63..8d7e9e819a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -56,25 +56,25 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa fun onCallEvent(event: Event) { when (event.getClearType()) { - EventType.CALL_ANSWER -> { + EventType.CALL_ANSWER -> { handleCallAnswerEvent(event) } - EventType.CALL_INVITE -> { + EventType.CALL_INVITE -> { handleCallInviteEvent(event) } - EventType.CALL_HANGUP -> { + EventType.CALL_HANGUP -> { handleCallHangupEvent(event) } - EventType.CALL_REJECT -> { + EventType.CALL_REJECT -> { handleCallRejectEvent(event) } - EventType.CALL_CANDIDATES -> { + EventType.CALL_CANDIDATES -> { handleCallCandidatesEvent(event) } EventType.CALL_SELECT_ANSWER -> { handleCallSelectAnswerEvent(event) } - EventType.CALL_NEGOTIATE -> { + EventType.CALL_NEGOTIATE -> { handleCallNegotiateEvent(event) } } @@ -168,6 +168,14 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa return } val content = event.getClearContent().toModel() ?: return + + content.callId ?: return + if (activeCallHandler.getCallWithId(content.callId) != null) { + // Call is already known, maybe due to fast lane. Ignore + Timber.d("Ignoring already known call invite") + return + } + val incomingCall = mxCallFactory.createIncomingCall( roomId = event.roomId, opponentUserId = event.senderId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/events/DefaultEventService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/events/DefaultEventService.kt new file mode 100644 index 0000000000..d7e9ef2ee0 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/events/DefaultEventService.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.session.events + +import org.matrix.android.sdk.api.session.events.EventService +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.internal.session.call.CallEventProcessor +import org.matrix.android.sdk.internal.session.room.timeline.GetEventTask +import javax.inject.Inject + +internal class DefaultEventService @Inject constructor( + private val getEventTask: GetEventTask, + private val callEventProcessor: CallEventProcessor +) : EventService { + + override suspend fun getEvent(roomId: String, eventId: String): Event { + val event = getEventTask.execute(GetEventTask.Params(roomId, eventId)) + + // Fast lane to the call event processors: try to make the incoming call ring faster + if (callEventProcessor.shouldProcessFastLane(event.getClearType())) { + callEventProcessor.processFastLane(event) + } + + return event + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index 66b7272360..5133f72932 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -79,9 +79,11 @@ import org.matrix.android.sdk.internal.session.room.tags.DefaultDeleteTagFromRoo import org.matrix.android.sdk.internal.session.room.tags.DeleteTagFromRoomTask import org.matrix.android.sdk.internal.session.room.timeline.DefaultFetchTokenAndPaginateTask import org.matrix.android.sdk.internal.session.room.timeline.DefaultGetContextOfEventTask +import org.matrix.android.sdk.internal.session.room.timeline.DefaultGetEventTask import org.matrix.android.sdk.internal.session.room.timeline.DefaultPaginationTask import org.matrix.android.sdk.internal.session.room.timeline.FetchTokenAndPaginateTask import org.matrix.android.sdk.internal.session.room.timeline.GetContextOfEventTask +import org.matrix.android.sdk.internal.session.room.timeline.GetEventTask import org.matrix.android.sdk.internal.session.room.timeline.PaginationTask import org.matrix.android.sdk.internal.session.room.typing.DefaultSendTypingTask import org.matrix.android.sdk.internal.session.room.typing.SendTypingTask @@ -228,4 +230,7 @@ internal abstract class RoomModule { @Binds abstract fun bindPeekRoomTask(task: DefaultPeekRoomTask): PeekRoomTask + + @Binds + abstract fun bindGetEventTask(task: DefaultGetEventTask): GetEventTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt index a9b8683a28..f1a20e8057 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt @@ -16,28 +16,49 @@ package org.matrix.android.sdk.internal.session.room.timeline +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.internal.crypto.EventDecryptor +import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject -// TODO Add parent task - -internal class GetEventTask @Inject constructor( - private val roomAPI: RoomAPI, - private val globalErrorReceiver: GlobalErrorReceiver -) : Task { - - internal data class Params( +internal interface GetEventTask : Task { + data class Params( val roomId: String, - val eventId: String + val eventId: String, ) +} - override suspend fun execute(params: Params): Event { - return executeRequest(globalErrorReceiver) { +internal class DefaultGetEventTask @Inject constructor( + private val roomAPI: RoomAPI, + private val globalErrorReceiver: GlobalErrorReceiver, + private val eventDecryptor: EventDecryptor +) : GetEventTask { + + override suspend fun execute(params: GetEventTask.Params): Event { + val event = executeRequest(globalErrorReceiver) { roomAPI.getEvent(params.roomId, params.eventId) } + + // Try to decrypt the Event + if (event.isEncrypted()) { + tryOrNull(message = "Unable to decrypt the event") { + eventDecryptor.decryptEvent(event, "") + } + ?.let { result -> + event.mxDecryptionResult = OlmDecryptionResult( + payload = result.clearEvent, + senderKey = result.senderCurve25519Key, + keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, + forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain + ) + } + } + + return event } } diff --git a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt index 4d2cbecfe4..7f54be56fb 100755 --- a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -40,6 +40,9 @@ import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.notifications.SimpleNotifiableEvent import im.vector.app.features.settings.VectorPreferences import im.vector.app.push.fcm.FcmHelper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.pushrules.Action import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.Event @@ -56,6 +59,8 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { private lateinit var activeSessionHolder: ActiveSessionHolder private lateinit var vectorPreferences: VectorPreferences + private val coroutineScope = CoroutineScope(SupervisorJob()) + // UI handler private val mUIHandler by lazy { Handler(Looper.getMainLooper()) @@ -78,6 +83,11 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { * @param message the message */ override fun onMessageReceived(message: RemoteMessage) { + if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { + Timber.d("## onMessageReceived() %s", message.data.toString()) + } + Timber.d("## onMessageReceived() from FCM with priority %s", message.priority) + // Diagnostic Push if (message.data["event_id"] == PushersManager.TEST_EVENT_ID) { val intent = Intent(NotificationUtils.PUSH_ACTION) @@ -90,14 +100,10 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { return } - if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - 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)) { // we are in foreground, let the sync do the things? - Timber.v("PUSH received in a foreground state, ignore") + Timber.d("PUSH received in a foreground state, ignore") } else { onMessageReceivedInternal(message.data) } @@ -140,7 +146,9 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { private fun onMessageReceivedInternal(data: Map) { try { if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.i("## onMessageReceivedInternal() : $data") + Timber.d("## onMessageReceivedInternal() : $data") + } else { + Timber.d("## onMessageReceivedInternal() : $data") } // update the badge counter @@ -156,9 +164,13 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { val roomId = data["room_id"] if (isEventAlreadyKnown(eventId, roomId)) { - Timber.i("Ignoring push, event already known") + Timber.d("Ignoring push, event already known") } else { - Timber.v("Requesting background sync") + // Try to get the Event content faster + Timber.d("Requesting event in fast lane") + getEventFastLane(session, roomId, eventId) + + Timber.d("Requesting background sync") session.requireBackgroundSync() } } @@ -167,6 +179,32 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { } } + private fun getEventFastLane(session: Session, roomId: String?, eventId: String?) { + roomId?.takeIf { it.isNotEmpty() } ?: return + eventId?.takeIf { it.isNotEmpty() } ?: return + + // If the room is currently displayed, we will not show a notification, so no need to get the Event faster + if (notificationDrawerManager.shouldIgnoreMessageEventInRoom(roomId)) { + return + } + + coroutineScope.launch { + Timber.d("Fast lane: start request") + val event = session.getEvent(roomId, eventId) + + val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event) + + // TODO Test the Event against the push rules + resolvedEvent + ?.also { Timber.d("Fast lane: notify drawer") } + ?.let { + it.isPushGatewayEvent = true + notificationDrawerManager.onNotifiableEventReceived(it) + notificationDrawerManager.refreshNotificationDrawer() + } + } + } + // check if the event was not yet received // a previous catchup might have already retrieved the notified event private fun isEventAlreadyKnown(eventId: String?, roomId: String?): Boolean { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt index a4f617bf5b..d5862f3a85 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt @@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomMemberContent +import org.matrix.android.sdk.api.session.room.sender.SenderInfo import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.getEditedEventId import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult @@ -42,9 +43,10 @@ import javax.inject.Inject * 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 @Inject constructor(private val stringProvider: StringProvider, - private val noticeEventFormatter: NoticeEventFormatter, - private val displayableEventFormatter: DisplayableEventFormatter) { +class NotifiableEventResolver @Inject constructor( + private val stringProvider: StringProvider, + private val noticeEventFormatter: NoticeEventFormatter, + private val displayableEventFormatter: DisplayableEventFormatter) { // private val eventDisplay = RiotEventDisplay(context) @@ -84,6 +86,28 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St } } + fun resolveInMemoryEvent(session: Session, event: Event): NotifiableEvent? { + if (event.getClearType() != EventType.MESSAGE) return null + + // TODO Ignore message edition + val user = session.getUser(event.senderId!!) ?: return null + + val timelineEvent = TimelineEvent( + root = event, + localId = -1, + eventId = event.eventId!!, + displayIndex = 0, + senderInfo = SenderInfo( + userId = user.userId, + displayName = user.getBestName(), + isUniqueDisplayName = true, + avatarUrl = user.avatarUrl + ) + ) + + return resolveMessageEvent(timelineEvent, session) + } + 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.root.roomId!! /*roomID cannot be null*/) diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt index 36b69a7958..7ac9b28b9a 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt @@ -89,7 +89,9 @@ class NotificationDrawerManager @Inject constructor(private val context: Context // If we support multi session, event list should be per userId // Currently only manage single session if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.v("%%%%%%%% onNotifiableEventReceived $notifiableEvent") + Timber.d("onNotifiableEventReceived(): $notifiableEvent") + } else { + Timber.d("onNotifiableEventReceived(): is push: ${notifiableEvent.isPushGatewayEvent}") } synchronized(eventList) { val existing = eventList.firstOrNull { it.eventId == notifiableEvent.eventId } @@ -550,7 +552,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context return bitmapLoader.getRoomBitmap(roomAvatarPath) } - private fun shouldIgnoreMessageEventInRoom(roomId: String?): Boolean { + fun shouldIgnoreMessageEventInRoom(roomId: String?): Boolean { return currentRoomId != null && roomId == currentRoomId }