Catching crash when offline during start of a live location share

This commit is contained in:
Maxime NATUREL 2022-06-15 10:01:35 +02:00
parent b16ccf5098
commit e55c378683
6 changed files with 71 additions and 14 deletions

View File

@ -46,9 +46,9 @@ interface LocationSharingService {
/** /**
* Starts sharing live location in the room. * Starts sharing live location in the room.
* @param timeoutMillis timeout of the live in milliseconds * @param timeoutMillis timeout of the live in milliseconds
* @return the id of the created beacon info event * @return the result of the update of the live
*/ */
suspend fun startLiveLocationShare(timeoutMillis: Long): String suspend fun startLiveLocationShare(timeoutMillis: Long): UpdateLiveLocationShareResult
/** /**
* Stops sharing live location in the room. * Stops sharing live location in the room.

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* 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.room.location
/**
* Represents the result of an update of live location share like a start or a stop.
*/
sealed interface UpdateLiveLocationShareResult {
/**
* @param beaconEventId event id of the updated state event
*/
data class Success(val beaconEventId: String) : UpdateLiveLocationShareResult
/**
* @param error thrown during the update
*/
data class Failure(val error: Throwable) : UpdateLiveLocationShareResult
}

View File

@ -22,6 +22,7 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import org.matrix.android.sdk.api.session.room.location.LocationSharingService import org.matrix.android.sdk.api.session.room.location.LocationSharingService
import org.matrix.android.sdk.api.session.room.location.UpdateLiveLocationShareResult
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.internal.database.mapper.LiveLocationShareAggregatedSummaryMapper import org.matrix.android.sdk.internal.database.mapper.LiveLocationShareAggregatedSummaryMapper
@ -66,7 +67,7 @@ internal class DefaultLocationSharingService @AssistedInject constructor(
return sendLiveLocationTask.execute(params) return sendLiveLocationTask.execute(params)
} }
override suspend fun startLiveLocationShare(timeoutMillis: Long): String { override suspend fun startLiveLocationShare(timeoutMillis: Long): UpdateLiveLocationShareResult {
val params = StartLiveLocationShareTask.Params( val params = StartLiveLocationShareTask.Params(
roomId = roomId, roomId = roomId,
timeoutMillis = timeoutMillis timeoutMillis = timeoutMillis

View File

@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.room.location
import org.matrix.android.sdk.api.session.events.model.EventType 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.toContent
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.api.session.room.model.message.MessageBeaconInfoContent
import org.matrix.android.sdk.internal.di.UserId 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.SendStateTask
@ -25,20 +26,21 @@ import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.time.Clock import org.matrix.android.sdk.internal.util.time.Clock
import javax.inject.Inject import javax.inject.Inject
internal interface StartLiveLocationShareTask : Task<StartLiveLocationShareTask.Params, String> { internal interface StartLiveLocationShareTask : Task<StartLiveLocationShareTask.Params, UpdateLiveLocationShareResult> {
data class Params( data class Params(
val roomId: String, val roomId: String,
val timeoutMillis: Long, val timeoutMillis: Long,
) )
} }
// TODO update unit test
internal class DefaultStartLiveLocationShareTask @Inject constructor( internal class DefaultStartLiveLocationShareTask @Inject constructor(
@UserId private val userId: String, @UserId private val userId: String,
private val clock: Clock, private val clock: Clock,
private val sendStateTask: SendStateTask, private val sendStateTask: SendStateTask,
) : StartLiveLocationShareTask { ) : StartLiveLocationShareTask {
override suspend fun execute(params: StartLiveLocationShareTask.Params): String { override suspend fun execute(params: StartLiveLocationShareTask.Params): UpdateLiveLocationShareResult {
val beaconContent = MessageBeaconInfoContent( val beaconContent = MessageBeaconInfoContent(
timeout = params.timeoutMillis, timeout = params.timeoutMillis,
isLive = true, isLive = true,
@ -51,6 +53,15 @@ internal class DefaultStartLiveLocationShareTask @Inject constructor(
eventType = eventType, eventType = eventType,
body = beaconContent body = beaconContent
) )
return sendStateTask.executeRetry(sendStateTaskParams, 3) return try {
val eventId = sendStateTask.executeRetry(sendStateTaskParams, 3)
if (eventId.isNotEmpty()) {
UpdateLiveLocationShareResult.Success(eventId)
} else {
UpdateLiveLocationShareResult.Failure(Exception("empty event id for new state event"))
}
} catch (error: Throwable) {
UpdateLiveLocationShareResult.Failure(error)
}
} }
} }

View File

@ -41,6 +41,7 @@ internal class DefaultStopLiveLocationShareTask @Inject constructor(
private val stateEventDataSource: StateEventDataSource, private val stateEventDataSource: StateEventDataSource,
) : StopLiveLocationShareTask { ) : StopLiveLocationShareTask {
@Throws
override suspend fun execute(params: StopLiveLocationShareTask.Params) { override suspend fun execute(params: StopLiveLocationShareTask.Params) {
val beaconInfoStateEvent = getLiveLocationBeaconInfoForUser(userId, params.roomId) ?: return val beaconInfoStateEvent = getLiveLocationBeaconInfoForUser(userId, params.roomId) ?: return
val stateKey = beaconInfoStateEvent.stateKey ?: return val stateKey = beaconInfoStateEvent.stateKey ?: return

View File

@ -30,6 +30,7 @@ import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.location.UpdateLiveLocationShareResult
import timber.log.Timber import timber.log.Timber
import java.util.Timer import java.util.Timer
import java.util.TimerTask import java.util.TimerTask
@ -95,13 +96,20 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
?.startLiveLocationShare(timeoutMillis = roomArgs.durationMillis) ?.startLiveLocationShare(timeoutMillis = roomArgs.durationMillis)
beaconEventId beaconEventId
?.takeUnless { it.isEmpty() } ?.let { result ->
?.let { when (result) {
roomArgsMap[it] = roomArgs is UpdateLiveLocationShareResult.Success -> {
locationTracker.requestLastKnownLocation() roomArgsMap[result.beaconEventId] = roomArgs
locationTracker.requestLastKnownLocation()
}
is UpdateLiveLocationShareResult.Failure -> {
tryToDestroyMe()
}
}
} }
?: run { ?: run {
Timber.w("### LocationSharingService.sendStartingLiveBeaconInfo error, no received beacon info id") Timber.w("### LocationSharingService.sendStartingLiveBeaconInfo error, no received beacon info id")
tryToDestroyMe()
} }
} }
@ -132,10 +140,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
.map { it.key } .map { it.key }
beaconIds.forEach { roomArgsMap.remove(it) } beaconIds.forEach { roomArgsMap.remove(it) }
if (roomArgsMap.isEmpty()) { tryToDestroyMe()
Timber.i("### LocationSharingService. Destroying self, time is up for all rooms")
destroyMe()
}
} }
} }
@ -178,6 +183,13 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
stopSelf() stopSelf()
} }
private fun tryToDestroyMe() {
if (roomArgsMap.isEmpty()) {
Timber.i("### LocationSharingService. Destroying self, time is up for all rooms")
destroyMe()
}
}
private fun destroyMe() { private fun destroyMe() {
locationTracker.removeCallback(this) locationTracker.removeCallback(this)
timers.forEach { it.cancel() } timers.forEach { it.cancel() }