From 7999bd75233d22e73bab2d9dd5c40b056c7e0aaf Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 29 Mar 2022 15:34:50 +0300 Subject: [PATCH] Show a banner in timeline while location sharing service is running. --- .../home/room/detail/RoomDetailViewEvents.kt | 3 + .../home/room/detail/TimelineFragment.kt | 10 +++ .../home/room/detail/TimelineViewModel.kt | 16 ++++- .../location/LocationSharingService.kt | 11 +++- .../LocationSharingServiceConnection.kt | 63 +++++++++++++++++++ 5 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/location/LocationSharingServiceConnection.kt diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt index d08a27324c..a7819d3ddf 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewEvents.kt @@ -82,4 +82,7 @@ sealed class RoomDetailViewEvents : VectorViewEvents { data class StartChatEffect(val type: ChatEffect) : RoomDetailViewEvents() object StopChatEffects : RoomDetailViewEvents() object RoomReplacementStarted : RoomDetailViewEvents() + + object ShowLocationSharingIndicator : RoomDetailViewEvents() + object HideLocationSharingIndicator : RoomDetailViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index 9c754e042c..00ddd8dcbd 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -482,6 +482,8 @@ class TimelineFragment @Inject constructor( RoomDetailViewEvents.StopChatEffects -> handleStopChatEffects() is RoomDetailViewEvents.DisplayAndAcceptCall -> acceptIncomingCall(it) RoomDetailViewEvents.RoomReplacementStarted -> handleRoomReplacement() + RoomDetailViewEvents.ShowLocationSharingIndicator -> handleShowLocationSharingIndicator() + RoomDetailViewEvents.HideLocationSharingIndicator -> handleHideLocationSharingIndicator() } } @@ -616,6 +618,14 @@ class TimelineFragment @Inject constructor( ) } + private fun handleShowLocationSharingIndicator() { + views.locationLiveStatusIndicator.isVisible = true + } + + private fun handleHideLocationSharingIndicator() { + views.locationLiveStatusIndicator.isVisible = false + } + private fun displayErrorMessage(error: RoomDetailViewEvents.Failure) { if (error.showInDialog) displayErrorDialog(error.throwable) else showErrorInSnackbar(error.throwable) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index 6933adc758..024c42e503 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -52,6 +52,7 @@ import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandle import im.vector.app.features.home.room.detail.timeline.factory.TimelineFactory import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever import im.vector.app.features.home.room.typing.TypingHelper +import im.vector.app.features.location.LocationSharingServiceConnection import im.vector.app.features.notifications.NotificationDrawerManager import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.session.coroutineScope @@ -124,10 +125,11 @@ class TimelineViewModel @AssistedInject constructor( private val activeConferenceHolder: JitsiActiveConferenceHolder, private val decryptionFailureTracker: DecryptionFailureTracker, private val notificationDrawerManager: NotificationDrawerManager, + private val locationSharingServiceConnection: LocationSharingServiceConnection, timelineFactory: TimelineFactory, appStateHandler: AppStateHandler ) : VectorViewModel(initialState), - Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener { + Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener, LocationSharingServiceConnection.Callback { private val room = session.getRoom(initialState.roomId)!! private val eventId = initialState.eventId @@ -219,6 +221,9 @@ class TimelineViewModel @AssistedInject constructor( // Threads initThreads() + + // Observe location service lifecycle to be able to warn the user + locationSharingServiceConnection.bind(this) } /** @@ -1218,6 +1223,14 @@ class TimelineViewModel @AssistedInject constructor( _viewEvents.post(RoomDetailViewEvents.OnNewTimelineEvents(eventIds)) } + override fun onLocationServiceRunning() { + _viewEvents.post(RoomDetailViewEvents.ShowLocationSharingIndicator) + } + + override fun onLocationServiceStopped() { + _viewEvents.post(RoomDetailViewEvents.HideLocationSharingIndicator) + } + override fun onCleared() { timeline.dispose() timeline.removeAllListeners() @@ -1231,6 +1244,7 @@ class TimelineViewModel @AssistedInject constructor( // we should also mark it as read here, for the scenario that the user // is already in the thread timeline markThreadTimelineAsReadLocal() + locationSharingServiceConnection.unbind() super.onCleared() } } 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 a2a68e4188..bcbda9ecf4 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 @@ -17,6 +17,7 @@ package im.vector.app.features.location import android.content.Intent +import android.os.Binder import android.os.IBinder import android.os.Parcelable import dagger.hilt.android.AndroidEntryPoint @@ -41,6 +42,8 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { @Inject lateinit var notificationUtils: NotificationUtils @Inject lateinit var locationTracker: LocationTracker + private val binder = LocalBinder() + private var roomArgsList = mutableListOf() private var timers = mutableListOf() @@ -120,8 +123,12 @@ class LocationSharingService : VectorService(), LocationTracker.Callback { destroyMe() } - override fun onBind(intent: Intent?): IBinder? { - return null + override fun onBind(intent: Intent?): IBinder { + return binder + } + + inner class LocalBinder : Binder() { + fun getService(): LocationSharingService = this@LocationSharingService } companion object { diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingServiceConnection.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingServiceConnection.kt new file mode 100644 index 0000000000..9af6b1539a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingServiceConnection.kt @@ -0,0 +1,63 @@ +/* + * 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 im.vector.app.features.location + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import javax.inject.Inject + +class LocationSharingServiceConnection @Inject constructor( + private val context: Context +) : ServiceConnection { + + interface Callback { + fun onLocationServiceRunning() + fun onLocationServiceStopped() + } + + private var callback: Callback? = null + private var isBound = false + + fun bind(callback: Callback) { + this.callback = callback + + if (isBound) { + callback.onLocationServiceRunning() + } else { + Intent(context, LocationSharingService::class.java).also { intent -> + context.bindService(intent, this, 0) + } + } + } + + fun unbind() { + callback = null + } + + override fun onServiceConnected(className: ComponentName, binder: IBinder) { + isBound = true + callback?.onLocationServiceRunning() + } + + override fun onServiceDisconnected(className: ComponentName) { + isBound = false + callback?.onLocationServiceStopped() + } +}