diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt index c4dccc1b73..15f91d1f47 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt @@ -16,11 +16,13 @@ package im.vector.app.features.location +import android.content.Intent import android.graphics.drawable.Drawable import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.content.ContextCompat import androidx.core.view.isGone import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.fragmentViewModel @@ -83,9 +85,10 @@ class LocationSharingFragment @Inject constructor( viewModel.observeViewEvents { when (it) { - LocationSharingViewEvents.Close -> locationSharingNavigator.quit() - LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError() - is LocationSharingViewEvents.ZoomToUserLocation -> handleZoomToUserLocationEvent(it) + LocationSharingViewEvents.Close -> locationSharingNavigator.quit() + LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError() + is LocationSharingViewEvents.ZoomToUserLocation -> handleZoomToUserLocationEvent(it) + is LocationSharingViewEvents.StartLiveLocationService -> handleStartLiveLocationService(it) }.exhaustive } } @@ -177,6 +180,17 @@ class LocationSharingFragment @Inject constructor( views.mapView.zoomToLocation(event.userLocation.latitude, event.userLocation.longitude) } + private fun handleStartLiveLocationService(event: LocationSharingViewEvents.StartLiveLocationService) { + Intent(requireContext(), LocationSharingService::class.java) + .apply { + putExtra(LocationSharingService.EXTRA_SESSION_ID, event.sessionId) + putExtra(LocationSharingService.EXTRA_ROOM_ID, event.roomId) + } + .also { + ContextCompat.startForegroundService(requireContext(), it) + } + } + private fun initOptionsPicker() { // set no option at start views.shareLocationOptionsPicker.render() 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 4c565ac2bb..e0faebe528 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 @@ -16,12 +16,45 @@ package im.vector.app.features.location -import android.app.Service import android.content.Intent import android.os.IBinder +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.services.VectorService +import im.vector.app.features.notifications.NotificationUtils +import timber.log.Timber +import javax.inject.Inject + +@AndroidEntryPoint +class LocationSharingService : VectorService() { + + @Inject lateinit var notificationUtils: NotificationUtils + + private var sessionId: String? = null + private var roomId: String? = null + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + sessionId = intent?.getStringExtra(EXTRA_SESSION_ID) + roomId = intent?.getStringExtra(EXTRA_ROOM_ID) + + Timber.d("LocationSharingService $sessionId - $roomId") + + if (sessionId == null || roomId == null) { + stopForeground(true) + stopSelf() + } + + val notification = notificationUtils.buildLiveLocationSharingNotification() + startForeground(roomId!!.hashCode(), notification) + + return START_STICKY + } -class LocationSharingService : Service() { override fun onBind(intent: Intent?): IBinder? { return null } + + companion object { + const val EXTRA_SESSION_ID = "EXTRA_SESSION_ID" + const val EXTRA_ROOM_ID = "EXTRA_ROOM_ID" + } } diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewEvents.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewEvents.kt index 8d31db1119..a7204f02c1 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewEvents.kt @@ -22,4 +22,5 @@ sealed class LocationSharingViewEvents : VectorViewEvents { object Close : LocationSharingViewEvents() object LocationNotAvailableError : LocationSharingViewEvents() data class ZoomToUserLocation(val userLocation: LocationData) : LocationSharingViewEvents() + data class StartLiveLocationService(val sessionId: String, val roomId: String) : LocationSharingViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt index 639666e63f..893eee6f70 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt @@ -160,8 +160,10 @@ class LocationSharingViewModel @AssistedInject constructor( } private fun handleStartLiveLocationSharingAction() { - // TODO start sharing live location and update view state - Timber.d("live location sharing started") + _viewEvents.post(LocationSharingViewEvents.StartLiveLocationService( + sessionId = session.sessionId, + roomId = room.roomId + )) } override fun onLocationUpdate(locationData: LocationData) { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index d39926f620..0366b160ee 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -521,6 +521,18 @@ class NotificationUtils @Inject constructor(private val context: Context, return builder.build() } + /** + * Creates a notification that indicates the application is retrieving location even if it is in background or killed. + */ + fun buildLiveLocationSharingNotification(): Notification { + return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) + .setContentTitle(stringProvider.getString(R.string.live_location_sharing_notification_title)) + .setContentText(stringProvider.getString(R.string.live_location_sharing_notification_description)) + .setSmallIcon(R.drawable.ic_location_pin) + .setCategory(NotificationCompat.CATEGORY_LOCATION_SHARING) + .build() + } + fun buildDownloadFileNotification(uri: Uri, fileName: String, mimeType: String): Notification { return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) .setGroup(stringProvider.getString(R.string.app_name)) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 428be3209f..9a30e89948 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2946,6 +2946,8 @@ Once enabled you will be able to send your location to any room Render user locations in the timeline Failed to load map + ${app_name} Live Location + Location sharing is in progress Show Message bubbles