From c2c58f81d840a77e788348625ea6b7cb7d41aee8 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 21 Jun 2022 17:25:06 +0200 Subject: [PATCH] Stopping existing active live when starting a new one --- .../sdk/internal/session/room/RoomModule.kt | 10 ++++ .../location/CheckIfExistingActiveLiveTask.kt | 46 ++++++++++++++++ .../location/DefaultLocationSharingService.kt | 12 ++++ .../GetActiveBeaconInfoForUserTask.kt | 55 +++++++++++++++++++ .../location/StopLiveLocationShareTask.kt | 27 +++------ .../location/LocationSharingService.kt | 35 +++++++----- 6 files changed, 151 insertions(+), 34 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/CheckIfExistingActiveLiveTask.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/GetActiveBeaconInfoForUserTask.kt 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 271e82a1e0..c4d37d124b 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 @@ -51,10 +51,14 @@ import org.matrix.android.sdk.internal.session.room.directory.DefaultSetRoomDire import org.matrix.android.sdk.internal.session.room.directory.GetPublicRoomTask import org.matrix.android.sdk.internal.session.room.directory.GetRoomDirectoryVisibilityTask import org.matrix.android.sdk.internal.session.room.directory.SetRoomDirectoryVisibilityTask +import org.matrix.android.sdk.internal.session.room.location.CheckIfExistingActiveLiveTask +import org.matrix.android.sdk.internal.session.room.location.DefaultCheckIfExistingActiveLiveTask +import org.matrix.android.sdk.internal.session.room.location.DefaultGetActiveBeaconInfoForUserTask import org.matrix.android.sdk.internal.session.room.location.DefaultSendLiveLocationTask import org.matrix.android.sdk.internal.session.room.location.DefaultSendStaticLocationTask import org.matrix.android.sdk.internal.session.room.location.DefaultStartLiveLocationShareTask import org.matrix.android.sdk.internal.session.room.location.DefaultStopLiveLocationShareTask +import org.matrix.android.sdk.internal.session.room.location.GetActiveBeaconInfoForUserTask import org.matrix.android.sdk.internal.session.room.location.SendLiveLocationTask import org.matrix.android.sdk.internal.session.room.location.SendStaticLocationTask import org.matrix.android.sdk.internal.session.room.location.StartLiveLocationShareTask @@ -319,4 +323,10 @@ internal abstract class RoomModule { @Binds abstract fun bindSendLiveLocationTask(task: DefaultSendLiveLocationTask): SendLiveLocationTask + + @Binds + abstract fun bindGetActiveBeaconInfoForUserTask(task: DefaultGetActiveBeaconInfoForUserTask): GetActiveBeaconInfoForUserTask + + @Binds + abstract fun bindCheckIfExistingActiveLiveTask(task: DefaultCheckIfExistingActiveLiveTask): CheckIfExistingActiveLiveTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/CheckIfExistingActiveLiveTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/CheckIfExistingActiveLiveTask.kt new file mode 100644 index 0000000000..3fa1da2677 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/CheckIfExistingActiveLiveTask.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 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.room.location + +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface CheckIfExistingActiveLiveTask : Task { + data class Params( + val roomId: String, + ) +} + +// TODO unit tests +internal class DefaultCheckIfExistingActiveLiveTask @Inject constructor( + private val getActiveBeaconInfoForUserTask: GetActiveBeaconInfoForUserTask, +) : CheckIfExistingActiveLiveTask { + + override suspend fun execute(params: CheckIfExistingActiveLiveTask.Params): Boolean { + val getActiveBeaconTaskParams = GetActiveBeaconInfoForUserTask.Params( + roomId = params.roomId + ) + return getActiveBeaconInfoForUserTask.execute(getActiveBeaconTaskParams) + ?.getClearContent() + ?.toModel() + ?.isLive + .orFalse() + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt index 8e67142c52..ef1d6f5ff0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/DefaultLocationSharingService.kt @@ -41,6 +41,7 @@ internal class DefaultLocationSharingService @AssistedInject constructor( private val sendLiveLocationTask: SendLiveLocationTask, private val startLiveLocationShareTask: StartLiveLocationShareTask, private val stopLiveLocationShareTask: StopLiveLocationShareTask, + private val stopCheckIfExistingActiveLiveTask: CheckIfExistingActiveLiveTask, private val liveLocationShareAggregatedSummaryMapper: LiveLocationShareAggregatedSummaryMapper, ) : LocationSharingService { @@ -72,6 +73,10 @@ internal class DefaultLocationSharingService @AssistedInject constructor( } override suspend fun startLiveLocationShare(timeoutMillis: Long): UpdateLiveLocationShareResult { + // Ensure to stop any active live before starting a new one + if (checkIfExistingActiveLive()) { + stopLiveLocationShare() + } val params = StartLiveLocationShareTask.Params( roomId = roomId, timeoutMillis = timeoutMillis @@ -79,6 +84,13 @@ internal class DefaultLocationSharingService @AssistedInject constructor( return startLiveLocationShareTask.execute(params) } + private suspend fun checkIfExistingActiveLive(): Boolean { + val params = CheckIfExistingActiveLiveTask.Params( + roomId = roomId + ) + return stopCheckIfExistingActiveLiveTask.execute(params) + } + override suspend fun stopLiveLocationShare(): UpdateLiveLocationShareResult { val params = StopLiveLocationShareTask.Params( roomId = roomId, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/GetActiveBeaconInfoForUserTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/GetActiveBeaconInfoForUserTask.kt new file mode 100644 index 0000000000..b16d0d7f4a --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/GetActiveBeaconInfoForUserTask.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 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.room.location + +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.query.QueryStringValue +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.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent +import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface GetActiveBeaconInfoForUserTask : Task { + data class Params( + val roomId: String, + ) +} + +// TODO unit tests +internal class DefaultGetActiveBeaconInfoForUserTask @Inject constructor( + @UserId private val userId: String, + private val stateEventDataSource: StateEventDataSource, +) : GetActiveBeaconInfoForUserTask { + + override suspend fun execute(params: GetActiveBeaconInfoForUserTask.Params): Event? { + return EventType.STATE_ROOM_BEACON_INFO + .mapNotNull { + stateEventDataSource.getStateEvent( + roomId = params.roomId, + eventType = it, + stateKey = QueryStringValue.Equals(userId) + ) + } + .firstOrNull { beaconInfoEvent -> + beaconInfoEvent.getClearContent()?.toModel()?.isLive.orFalse() + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/StopLiveLocationShareTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/StopLiveLocationShareTask.kt index d0e7ff3f82..e11bc87389 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/StopLiveLocationShareTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/location/StopLiveLocationShareTask.kt @@ -16,17 +16,13 @@ package org.matrix.android.sdk.internal.session.room.location -import org.matrix.android.sdk.api.extensions.orFalse -import org.matrix.android.sdk.api.query.QueryStringValue 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.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.location.UpdateLiveLocationShareResult import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent -import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.room.state.SendStateTask -import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource import org.matrix.android.sdk.internal.task.Task import javax.inject.Inject @@ -36,14 +32,14 @@ internal interface StopLiveLocationShareTask : Task() ?: return getResultForIncorrectBeaconInfoEvent() val updatedContent = content.copy(isLive = false).toContent() @@ -68,17 +64,10 @@ internal class DefaultStopLiveLocationShareTask @Inject constructor( private fun getResultForIncorrectBeaconInfoEvent() = UpdateLiveLocationShareResult.Failure(Exception("incorrect last beacon info event")) - private fun getLiveLocationBeaconInfoForUser(userId: String, roomId: String): Event? { - return EventType.STATE_ROOM_BEACON_INFO - .mapNotNull { - stateEventDataSource.getStateEvent( - roomId = roomId, - eventType = it, - stateKey = QueryStringValue.Equals(userId) - ) - } - .firstOrNull { beaconInfoEvent -> - beaconInfoEvent.getClearContent()?.toModel()?.isLive.orFalse() - } + private suspend fun getActiveLiveLocationBeaconInfoForUser(roomId: String): Event? { + val params = GetActiveBeaconInfoForUserTask.Params( + roomId = roomId + ) + return getActiveBeaconInfoForUserTask.execute(params) } } diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt index 0ba9e2134c..0035af084a 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingService.kt @@ -63,10 +63,11 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { private val roomArgsMap = mutableMapOf() var callback: Callback? = null private val jobs = mutableListOf() + private var startInProgress = false override fun onCreate() { super.onCreate() - Timber.i("### LocationSharingService.onCreate") + Timber.i("onCreate") initLocationTracking() } @@ -85,9 +86,11 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + startInProgress = true + val roomArgs = intent?.getParcelableExtra(EXTRA_ROOM_ARGS) as? RoomArgs - Timber.i("### LocationSharingService.onStartCommand. sessionId - roomId ${roomArgs?.sessionId} - ${roomArgs?.roomId}") + Timber.i("onStartCommand. sessionId - roomId ${roomArgs?.sessionId} - ${roomArgs?.roomId}") if (roomArgs != null) { // Show a sticky notification @@ -100,6 +103,8 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { } } + startInProgress = false + return START_STICKY } @@ -124,19 +129,19 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { } } ?: run { - Timber.w("### LocationSharingService.sendStartingLiveBeaconInfo error, no received beacon info id") + Timber.w("sendStartingLiveBeaconInfo error, no received beacon info id") tryToDestroyMe() } } - private fun stopSharingLocation(roomId: String) { - Timber.i("### LocationSharingService.stopSharingLocation for $roomId") - removeRoomArgs(roomId) + private fun stopSharingLocation(beaconEventId: String) { + Timber.i("stopSharingLocation for beacon $beaconEventId") + removeRoomArgs(beaconEventId) tryToDestroyMe() } private fun onLocationUpdate(locationData: LocationData) { - Timber.i("### LocationSharingService.onLocationUpdate. Uncertainty: ${locationData.uncertainty}") + Timber.i("onLocationUpdate. Uncertainty: ${locationData.uncertainty}") // Emit location update to all rooms in which live location sharing is active roomArgsMap.toMap().forEach { item -> @@ -167,7 +172,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { } private fun tryToDestroyMe() { - if (roomArgsMap.isEmpty()) { + if (startInProgress.not() && roomArgsMap.isEmpty()) { Timber.i("### LocationSharingService. Destroying self, time is up for all rooms") stopSelf() } @@ -182,21 +187,21 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { } private fun addRoomArgs(beaconEventId: String, roomArgs: RoomArgs) { + Timber.i("adding roomArgs for beaconEventId: $beaconEventId") roomArgsMap[beaconEventId] = roomArgs } - private fun removeRoomArgs(roomId: String) { - roomArgsMap.toMap() - .filter { it.value.roomId == roomId } - .forEach { roomArgsMap.remove(it.key) } + private fun removeRoomArgs(beaconEventId: String) { + Timber.i("removing roomArgs for beaconEventId: $beaconEventId") + roomArgsMap.remove(beaconEventId) } - private fun listenForLiveSummaryChanges(roomId: String, eventId: String) { + private fun listenForLiveSummaryChanges(roomId: String, beaconEventId: String) { launchWithActiveSession { session -> - val job = getLiveLocationShareSummaryUseCase.execute(roomId, eventId) + val job = getLiveLocationShareSummaryUseCase.execute(roomId, beaconEventId) .distinctUntilChangedBy { it.isActive } .filter { it.isActive == false } - .onEach { stopSharingLocation(roomId) } + .onEach { stopSharingLocation(beaconEventId) } .launchIn(session.coroutineScope) jobs.add(job) }