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 362b82ccf5..8b9a1c75ae 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 @@ -55,7 +55,10 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { private val binder = LocalBinder() - private var roomArgsList = mutableListOf() + /** + * Keep track of a map between beacon event Id starting the live and RoomArgs. + */ + private var roomArgsMap = mutableMapOf() private var timers = mutableListOf() override fun onCreate() { @@ -73,8 +76,6 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { Timber.i("### LocationSharingService.onStartCommand. sessionId - roomId ${roomArgs?.sessionId} - ${roomArgs?.roomId}") if (roomArgs != null) { - roomArgsList.add(roomArgs) - // Show a sticky notification val notification = notificationUtils.buildLiveLocationSharingNotification() startForeground(roomArgs.roomId.hashCode(), notification) @@ -87,7 +88,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { .getSafeActiveSession() ?.let { session -> session.coroutineScope.launch(session.coroutineDispatchers.io) { - sendLiveBeaconInfo(session, roomArgs) + sendStartingLiveBeaconInfo(session, roomArgs) } } } @@ -95,7 +96,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { return START_STICKY } - private suspend fun sendLiveBeaconInfo(session: Session, roomArgs: RoomArgs) { + private suspend fun sendStartingLiveBeaconInfo(session: Session, roomArgs: RoomArgs) { val beaconContent = MessageBeaconInfoContent( timeout = roomArgs.durationMillis, isLive = true, @@ -103,7 +104,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { ).toContent() val stateKey = session.myUserId - session + val beaconEventId = session .getRoom(roomArgs.roomId) ?.stateService() ?.sendStateEvent( @@ -111,6 +112,16 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { stateKey = stateKey, body = beaconContent ) + + beaconEventId + ?.takeUnless { it.isEmpty() } + ?.let { + roomArgsMap[it] = roomArgs + locationTracker.requestLastKnownLocation() + } + ?: run { + Timber.w("### LocationSharingService.sendStartingLiveBeaconInfo error, no received beacon info id") + } } private fun scheduleTimer(roomId: String, durationMillis: Long) { @@ -134,9 +145,13 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { // Send a new beacon info state by setting live field as false sendStoppedBeaconInfo(roomId) - synchronized(roomArgsList) { - roomArgsList.removeAll { it.roomId == roomId } - if (roomArgsList.isEmpty()) { + synchronized(roomArgsMap) { + val beaconIds = roomArgsMap + .filter { it.value.roomId == roomId } + .map { it.key } + beaconIds.forEach { roomArgsMap.remove(it) } + + if (roomArgsMap.isEmpty()) { Timber.i("### LocationSharingService. Destroying self, time is up for all rooms") destroyMe() } @@ -156,16 +171,17 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { override fun onLocationUpdate(locationData: LocationData) { Timber.i("### LocationSharingService.onLocationUpdate. Uncertainty: ${locationData.uncertainty}") - val session = activeSessionHolder.getSafeActiveSession() // Emit location update to all rooms in which live location sharing is active - session?.coroutineScope?.launch(session.coroutineDispatchers.io) { - roomArgsList.toList().forEach { roomArg -> - sendLiveLocation(roomArg.roomId, locationData) - } + roomArgsMap.toMap().forEach { item -> + sendLiveLocation(item.value.roomId, item.key, locationData) } } - private suspend fun sendLiveLocation(roomId: String, locationData: LocationData) { + private fun sendLiveLocation( + roomId: String, + beaconInfoEventId: String, + locationData: LocationData + ) { val session = activeSessionHolder.getSafeActiveSession() val room = session?.getRoom(roomId) val userId = session?.myUserId @@ -174,18 +190,12 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { return } - room - .stateService() - .getLiveLocationBeaconInfo(userId, true) - ?.eventId - ?.let { - room.sendService().sendLiveLocation( - beaconInfoEventId = it, - latitude = locationData.latitude, - longitude = locationData.longitude, - uncertainty = locationData.uncertainty - ) - } + room.sendService().sendLiveLocation( + beaconInfoEventId = beaconInfoEventId, + latitude = locationData.latitude, + longitude = locationData.longitude, + uncertainty = locationData.uncertainty + ) } override fun onLocationProviderIsNotAvailable() { diff --git a/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt b/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt index b7006370a6..4e56e7954c 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt @@ -40,10 +40,12 @@ class LocationTracker @Inject constructor( fun onLocationProviderIsNotAvailable() } - private var callbacks = mutableListOf() + private val callbacks = mutableListOf() private var hasGpsProviderLiveLocation = false + private var lastLocation: LocationData? = null + @RequiresPermission(anyOf = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION]) fun start() { Timber.d("## LocationTracker. start()") @@ -92,6 +94,14 @@ class LocationTracker @Inject constructor( callbacks.clear() } + /** + * Request the last known location. It will be given async through Callback. + * Please ensure adding a callback to receive the value. + */ + fun requestLastKnownLocation() { + lastLocation?.let { location -> callbacks.forEach { it.onLocationUpdate(location) } } + } + fun addCallback(callback: Callback) { if (!callbacks.contains(callback)) { callbacks.add(callback) @@ -127,7 +137,9 @@ class LocationTracker @Inject constructor( } } } - callbacks.forEach { it.onLocationUpdate(location.toLocationData()) } + val locationData = location.toLocationData() + lastLocation = locationData + callbacks.forEach { it.onLocationUpdate(locationData) } } override fun onProviderDisabled(provider: String) {