Add ActiveRoomsHolder to manage the active rooms for a session (#4758)
This commit is contained in:
parent
630e1d19c0
commit
9b9d75aa5f
19 changed files with 240 additions and 30 deletions
|
|
@ -23,6 +23,7 @@ import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
|||
import io.element.android.libraries.push.impl.R
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||
import io.element.android.libraries.push.impl.push.OnNotifiableEventReceived
|
||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -44,6 +45,7 @@ class NotificationBroadcastReceiverHandler @Inject constructor(
|
|||
private val onNotifiableEventReceived: OnNotifiableEventReceived,
|
||||
private val stringProvider: StringProvider,
|
||||
private val replyMessageExtractor: ReplyMessageExtractor,
|
||||
private val activeRoomsHolder: ActiveRoomsHolder,
|
||||
) {
|
||||
fun onReceive(intent: Intent) {
|
||||
val sessionId = intent.getStringExtra(NotificationBroadcastReceiver.KEY_SESSION_ID)?.let(::SessionId) ?: return
|
||||
|
|
@ -117,13 +119,15 @@ class NotificationBroadcastReceiverHandler @Inject constructor(
|
|||
return@launch
|
||||
}
|
||||
val client = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: return@launch
|
||||
client.getJoinedRoom(roomId)?.let { room ->
|
||||
val room = activeRoomsHolder.getActiveRoomMatching(sessionId, roomId) ?: client.getJoinedRoom(roomId)
|
||||
|
||||
room?.let {
|
||||
sendMatrixEvent(
|
||||
sessionId = sessionId,
|
||||
roomId = roomId,
|
||||
replyToEventId = replyToEventId,
|
||||
threadId = threadId,
|
||||
room = room,
|
||||
room = it,
|
||||
message = message,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom
|
|||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent
|
||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -30,28 +31,43 @@ class SyncOnNotifiableEvent @Inject constructor(
|
|||
private val featureFlagService: FeatureFlagService,
|
||||
private val appForegroundStateService: AppForegroundStateService,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
private val activeRoomsHolder: ActiveRoomsHolder,
|
||||
) {
|
||||
suspend operator fun invoke(notifiableEvent: NotifiableEvent) = withContext(dispatchers.io) {
|
||||
val isRingingCallEvent = notifiableEvent is NotifiableRingingCallEvent
|
||||
if (!featureFlagService.isFeatureEnabled(FeatureFlags.SyncOnPush) && !isRingingCallEvent) {
|
||||
return@withContext
|
||||
}
|
||||
val client = matrixClientProvider.getOrRestore(notifiableEvent.sessionId).getOrNull() ?: return@withContext
|
||||
|
||||
client.getJoinedRoom(notifiableEvent.roomId)?.use { room ->
|
||||
room.subscribeToSync()
|
||||
val activeRoom = activeRoomsHolder.getActiveRoomMatching(notifiableEvent.sessionId, notifiableEvent.roomId)
|
||||
|
||||
// If the app is in foreground, sync is already running, so we just add the subscription above.
|
||||
if (!appForegroundStateService.isInForeground.value) {
|
||||
if (isRingingCallEvent) {
|
||||
room.waitsUntilUserIsInTheCall(timeout = 60.seconds)
|
||||
} else {
|
||||
try {
|
||||
appForegroundStateService.updateIsSyncingNotificationEvent(true)
|
||||
room.waitsUntilEventIsKnown(eventId = notifiableEvent.eventId, timeout = 10.seconds)
|
||||
} finally {
|
||||
appForegroundStateService.updateIsSyncingNotificationEvent(false)
|
||||
}
|
||||
if (activeRoom != null) {
|
||||
// If the room is already active, we can use it directly
|
||||
activeRoom.subscribeToSyncAndWait(notifiableEvent, isRingingCallEvent)
|
||||
} else {
|
||||
// Otherwise, we need to get the room from the matrix client
|
||||
val room = matrixClientProvider
|
||||
.getOrRestore(notifiableEvent.sessionId)
|
||||
.mapCatching { it.getJoinedRoom(notifiableEvent.roomId) }
|
||||
.getOrNull()
|
||||
|
||||
room?.use { it.subscribeToSyncAndWait(notifiableEvent, isRingingCallEvent) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun JoinedRoom.subscribeToSyncAndWait(notifiableEvent: NotifiableEvent, isRingingCallEvent: Boolean) {
|
||||
subscribeToSync()
|
||||
|
||||
// If the app is in foreground, sync is already running, so we just add the subscription above.
|
||||
if (!appForegroundStateService.isInForeground.value) {
|
||||
if (isRingingCallEvent) {
|
||||
waitsUntilUserIsInTheCall(timeout = 60.seconds)
|
||||
} else {
|
||||
try {
|
||||
appForegroundStateService.updateIsSyncingNotificationEvent(true)
|
||||
waitsUntilEventIsKnown(eventId = notifiableEvent.eventId, timeout = 10.seconds)
|
||||
} finally {
|
||||
appForegroundStateService.updateIsSyncingNotificationEvent(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import io.element.android.libraries.push.impl.notifications.model.NotifiableEven
|
|||
import io.element.android.libraries.push.impl.push.FakeOnNotifiableEventReceived
|
||||
import io.element.android.libraries.push.impl.push.OnNotifiableEventReceived
|
||||
import io.element.android.libraries.push.test.notifications.FakeNotificationCleaner
|
||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||
|
|
@ -477,6 +478,7 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
onNotifiableEventReceived: OnNotifiableEventReceived = FakeOnNotifiableEventReceived(),
|
||||
stringProvider: StringProvider = FakeStringProvider(),
|
||||
replyMessageExtractor: ReplyMessageExtractor = FakeReplyMessageExtractor(),
|
||||
activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
|
||||
): NotificationBroadcastReceiverHandler {
|
||||
return NotificationBroadcastReceiverHandler(
|
||||
appCoroutineScope = this,
|
||||
|
|
@ -494,6 +496,7 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
onNotifiableEventReceived = onNotifiableEventReceived,
|
||||
stringProvider = stringProvider,
|
||||
replyMessageExtractor = replyMessageExtractor,
|
||||
activeRoomsHolder = activeRoomsHolder,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
|||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableCallEvent
|
||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
|
|
@ -199,7 +200,8 @@ class SyncOnNotifiableEventTest {
|
|||
isSyncOnPushEnabled: Boolean = true,
|
||||
appForegroundStateService: FakeAppForegroundStateService = FakeAppForegroundStateService(
|
||||
initialForegroundValue = true,
|
||||
)
|
||||
),
|
||||
activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
|
||||
): SyncOnNotifiableEvent {
|
||||
val featureFlagService = FakeFeatureFlagService(
|
||||
initialState = mapOf(
|
||||
|
|
@ -212,6 +214,7 @@ class SyncOnNotifiableEventTest {
|
|||
featureFlagService = featureFlagService,
|
||||
appForegroundStateService = appForegroundStateService,
|
||||
dispatchers = testCoroutineDispatchers(),
|
||||
activeRoomsHolder = activeRoomsHolder,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue