Skip to content

Commit bc34e46

Browse files
committed
Improve replay route session
1 parent 2c314df commit bc34e46

File tree

2 files changed

+45
-28
lines changed

2 files changed

+45
-28
lines changed

libnavigation-core/src/main/java/com/mapbox/navigation/core/replay/route/ReplayRouteSession.kt

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.mapbox.navigation.base.route.NavigationRoute
1212
import com.mapbox.navigation.base.trip.model.RouteProgress
1313
import com.mapbox.navigation.core.MapboxNavigation
1414
import com.mapbox.navigation.core.directions.session.RoutesObserver
15+
import com.mapbox.navigation.core.history.MapboxHistoryReaderProvider
1516
import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp
1617
import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver
1718
import com.mapbox.navigation.core.replay.MapboxReplayer
@@ -20,6 +21,17 @@ import com.mapbox.navigation.core.replay.history.ReplayEventUpdateLocation
2021
import com.mapbox.navigation.core.replay.history.ReplayEventsObserver
2122
import com.mapbox.navigation.core.trip.session.RouteProgressObserver
2223
import com.mapbox.navigation.utils.internal.logW
24+
import kotlinx.coroutines.CoroutineScope
25+
import kotlinx.coroutines.Dispatchers
26+
import kotlinx.coroutines.SupervisorJob
27+
import kotlinx.coroutines.flow.Flow
28+
import kotlinx.coroutines.flow.MutableStateFlow
29+
import kotlinx.coroutines.flow.StateFlow
30+
import kotlinx.coroutines.flow.asStateFlow
31+
import kotlinx.coroutines.flow.distinctUntilChanged
32+
import kotlinx.coroutines.flow.launchIn
33+
import kotlinx.coroutines.flow.map
34+
import kotlinx.coroutines.flow.onEach
2335
import java.util.Collections
2436

2537
/**
@@ -54,13 +66,13 @@ import java.util.Collections
5466
@ExperimentalPreviewMapboxNavigationAPI
5567
class ReplayRouteSession : MapboxNavigationObserver {
5668

57-
private var options = ReplayRouteSessionOptions.Builder().build()
58-
5969
private lateinit var replayRouteMapper: ReplayRouteMapper
70+
private val optionsFlow = MutableStateFlow(ReplayRouteSessionOptions.Builder().build())
6071
private var mapboxNavigation: MapboxNavigation? = null
6172
private var lastLocationEvent: ReplayEventUpdateLocation? = null
6273
private var polylineDecodeStream: ReplayPolylineDecodeStream? = null
6374
private var currentRoute: NavigationRoute? = null
75+
private var coroutineScope: CoroutineScope? = null
6476

6577
private val routeProgressObserver = RouteProgressObserver { routeProgress ->
6678
if (currentRoute?.id != routeProgress.navigationRoute.id) {
@@ -89,34 +101,47 @@ class ReplayRouteSession : MapboxNavigationObserver {
89101
* setOptions(getOptions().toBuilder().locationResetEnabled(false).build())
90102
* ```
91103
*/
92-
fun getOptions(): ReplayRouteSessionOptions = options
104+
fun getOptions(): StateFlow<ReplayRouteSessionOptions> = optionsFlow.asStateFlow()
93105

94106
/**
95107
* Set new options for the [ReplayRouteSession]. This will not effect previously simulated
96108
* events, the end behavior will depend on the values you have used. If you want to guarantee
97109
* the effect of the options, you need to set options before [MapboxNavigation] is attached.
98110
*/
99111
fun setOptions(options: ReplayRouteSessionOptions) = apply {
100-
this.options = options
101-
if (::replayRouteMapper.isInitialized) {
102-
replayRouteMapper.options = this.options.replayRouteOptions
103-
}
112+
this.optionsFlow.value = options
104113
}
105114

106115
override fun onAttached(mapboxNavigation: MapboxNavigation) {
107-
this.replayRouteMapper = ReplayRouteMapper(options.replayRouteOptions)
116+
val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
117+
.also { this.coroutineScope = it }
108118
this.mapboxNavigation = mapboxNavigation
109119
mapboxNavigation.startReplayTripSession()
110120
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
111121
mapboxNavigation.registerRoutesObserver(routesObserver)
112122
mapboxNavigation.mapboxReplayer.registerObserver(replayEventsObserver)
113123
mapboxNavigation.mapboxReplayer.play()
124+
observeStateFlow(mapboxNavigation).launchIn(coroutineScope)
125+
}
126+
127+
private fun observeStateFlow(mapboxNavigation: MapboxNavigation): Flow<*> {
128+
return optionsFlow.mapDistinct { it.replayRouteOptions }.onEach { replayRouteOptions ->
129+
mapboxNavigation.mapboxReplayer.clearEvents()
130+
this.replayRouteMapper = ReplayRouteMapper(replayRouteOptions)
131+
val routes = mapboxNavigation.getNavigationRoutes()
132+
mapboxNavigation.setNavigationRoutes(emptyList())
133+
mapboxNavigation.setNavigationRoutes(routes)
134+
}
114135
}
115136

137+
private inline fun <T, R> Flow<T>.mapDistinct(
138+
crossinline transform: suspend (value: T) -> R
139+
): Flow<R> = map(transform).distinctUntilChanged()
140+
116141
private fun MapboxNavigation.resetReplayLocation() {
117142
mapboxReplayer.clearEvents()
118143
resetTripSession {
119-
if (options.locationResetEnabled) {
144+
if (optionsFlow.value.locationResetEnabled) {
120145
val context = navigationOptions.applicationContext
121146
if (PermissionsManager.areLocationPermissionsGranted(context)) {
122147
pushRealLocation(context)
@@ -174,7 +199,7 @@ class ReplayRouteSession : MapboxNavigationObserver {
174199
}
175200

176201
private fun pushMorePoints() {
177-
val nextPoints = polylineDecodeStream?.decode(options.decodeMinDistance) ?: return
202+
val nextPoints = polylineDecodeStream?.decode(optionsFlow.value.decodeMinDistance) ?: return
178203
val nextReplayLocations = replayRouteMapper.mapPointList(nextPoints)
179204
lastLocationEvent = nextReplayLocations.lastOrNull { it is ReplayEventUpdateLocation }
180205
as? ReplayEventUpdateLocation

libnavigation-core/src/main/java/com/mapbox/navigation/core/trip/MapboxTripStarter.kt

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,8 @@ class MapboxTripStarter internal constructor(
4343
private val tripType = MutableStateFlow<MapboxTripStarterType>(
4444
MapboxTripStarterType.MapMatching
4545
)
46-
private val replayRouteSessionOptions = MutableStateFlow(
47-
ReplayRouteSessionOptions.Builder().build()
48-
)
4946
private val isLocationPermissionGranted = MutableStateFlow(false)
50-
private var replayRouteSession: ReplayRouteSession? = null
47+
private val replayRouteSession = services.getReplayRouteSession()
5148
private val replayHistorySession = services.getReplayHistorySession()
5249
private var mapboxNavigation: MapboxNavigation? = null
5350

@@ -109,7 +106,8 @@ class MapboxTripStarter internal constructor(
109106
* Get the current [ReplayRouteSessionOptions]. This can be used with [enableReplayRoute] to
110107
* make minor adjustments to the current options.
111108
*/
112-
fun getReplayRouteSessionOptions(): ReplayRouteSessionOptions = replayRouteSessionOptions.value
109+
fun getReplayRouteSessionOptions(): ReplayRouteSessionOptions =
110+
replayRouteSession.getOptions().value
113111

114112
/**
115113
* Enables a mode where the primary route is simulated by an artificial driver. Set the route
@@ -121,7 +119,7 @@ class MapboxTripStarter internal constructor(
121119
fun enableReplayRoute(
122120
options: ReplayRouteSessionOptions? = null
123121
) = apply {
124-
options?.let { options -> replayRouteSessionOptions.value = options }
122+
options?.let { options -> replayRouteSession.setOptions(options) }
125123
tripType.value = MapboxTripStarterType.ReplayRoute
126124
}
127125

@@ -155,7 +153,7 @@ class MapboxTripStarter internal constructor(
155153
onMapMatchingEnabled(mapboxNavigation, granted)
156154
}
157155
MapboxTripStarterType.ReplayRoute ->
158-
replayRouteSessionOptions.onEach { options ->
156+
replayRouteSession.getOptions().onEach { options ->
159157
onReplayRouteEnabled(mapboxNavigation, options)
160158
}
161159
MapboxTripStarterType.ReplayHistory ->
@@ -175,8 +173,7 @@ class MapboxTripStarter internal constructor(
175173
@SuppressLint("MissingPermission")
176174
private fun onMapMatchingEnabled(mapboxNavigation: MapboxNavigation, granted: Boolean) {
177175
if (granted) {
178-
replayRouteSession?.onDetached(mapboxNavigation)
179-
replayRouteSession = null
176+
replayRouteSession.onDetached(mapboxNavigation)
180177
replayHistorySession.onDetached(mapboxNavigation)
181178
mapboxNavigation.startTripSession()
182179
mapboxNavigation.resetTripSession { }
@@ -200,11 +197,8 @@ class MapboxTripStarter internal constructor(
200197
options: ReplayRouteSessionOptions
201198
) {
202199
replayHistorySession.onDetached(mapboxNavigation)
203-
replayRouteSession?.onDetached(mapboxNavigation)
204-
replayRouteSession = services.getReplayRouteSession().also {
205-
it.setOptions(options)
206-
it.onAttached(mapboxNavigation)
207-
}
200+
replayRouteSession.setOptions(options)
201+
replayRouteSession.onAttached(mapboxNavigation)
208202
}
209203

210204
/**
@@ -217,8 +211,7 @@ class MapboxTripStarter internal constructor(
217211
mapboxNavigation: MapboxNavigation,
218212
options: ReplayHistorySessionOptions
219213
) {
220-
replayRouteSession?.onDetached(mapboxNavigation)
221-
replayRouteSession = null
214+
replayRouteSession.onDetached(mapboxNavigation)
222215
replayHistorySession.setOptions(options)
223216
replayHistorySession.onAttached(mapboxNavigation)
224217
}
@@ -229,8 +222,7 @@ class MapboxTripStarter internal constructor(
229222
* @param mapboxNavigation
230223
*/
231224
private fun onTripDisabled(mapboxNavigation: MapboxNavigation) {
232-
replayRouteSession?.onDetached(mapboxNavigation)
233-
replayRouteSession = null
225+
replayRouteSession.onDetached(mapboxNavigation)
234226
replayHistorySession.onDetached(mapboxNavigation)
235227
mapboxNavigation.stopTripSession()
236228
}

0 commit comments

Comments
 (0)