Skip to content

Commit

Permalink
Improve replay route session
Browse files Browse the repository at this point in the history
  • Loading branch information
kmadsen committed Feb 2, 2023
1 parent f90a47b commit 5b86726
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.mapbox.navigation.base.route.NavigationRoute
import com.mapbox.navigation.base.trip.model.RouteProgress
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.directions.session.RoutesObserver
import com.mapbox.navigation.core.history.MapboxHistoryReaderProvider
import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp
import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver
import com.mapbox.navigation.core.replay.MapboxReplayer
Expand All @@ -20,6 +21,17 @@ import com.mapbox.navigation.core.replay.history.ReplayEventUpdateLocation
import com.mapbox.navigation.core.replay.history.ReplayEventsObserver
import com.mapbox.navigation.core.trip.session.RouteProgressObserver
import com.mapbox.navigation.utils.internal.logW
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import java.util.Collections

/**
Expand Down Expand Up @@ -54,13 +66,13 @@ import java.util.Collections
@ExperimentalPreviewMapboxNavigationAPI
class ReplayRouteSession : MapboxNavigationObserver {

private var options = ReplayRouteSessionOptions.Builder().build()

private lateinit var replayRouteMapper: ReplayRouteMapper
private val optionsFlow = MutableStateFlow(ReplayRouteSessionOptions.Builder().build())
private var mapboxNavigation: MapboxNavigation? = null
private var lastLocationEvent: ReplayEventUpdateLocation? = null
private var polylineDecodeStream: ReplayPolylineDecodeStream? = null
private var currentRoute: NavigationRoute? = null
private var coroutineScope: CoroutineScope? = null

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

/**
* Set new options for the [ReplayRouteSession]. This will not effect previously simulated
* events, the end behavior will depend on the values you have used. If you want to guarantee
* the effect of the options, you need to set options before [MapboxNavigation] is attached.
*/
fun setOptions(options: ReplayRouteSessionOptions) = apply {
this.options = options
if (::replayRouteMapper.isInitialized) {
replayRouteMapper.options = this.options.replayRouteOptions
}
this.optionsFlow.value = options
}

override fun onAttached(mapboxNavigation: MapboxNavigation) {
this.replayRouteMapper = ReplayRouteMapper(options.replayRouteOptions)
val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
.also { this.coroutineScope = it }
this.mapboxNavigation = mapboxNavigation
mapboxNavigation.startReplayTripSession()
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
mapboxNavigation.registerRoutesObserver(routesObserver)
mapboxNavigation.mapboxReplayer.registerObserver(replayEventsObserver)
mapboxNavigation.mapboxReplayer.play()
observeStateFlow(mapboxNavigation).launchIn(coroutineScope)
}

private fun observeStateFlow(mapboxNavigation: MapboxNavigation): Flow<*> {
return optionsFlow.mapDistinct { it.replayRouteOptions }.onEach { replayRouteOptions ->
mapboxNavigation.mapboxReplayer.clearEvents()
this.replayRouteMapper = ReplayRouteMapper(replayRouteOptions)
val routes = mapboxNavigation.getNavigationRoutes()
mapboxNavigation.setNavigationRoutes(emptyList())
mapboxNavigation.setNavigationRoutes(routes)
}
}

private inline fun <T, R> Flow<T>.mapDistinct(
crossinline transform: suspend (value: T) -> R
): Flow<R> = map(transform).distinctUntilChanged()

private fun MapboxNavigation.resetReplayLocation() {
mapboxReplayer.clearEvents()
resetTripSession {
if (options.locationResetEnabled) {
if (optionsFlow.value.locationResetEnabled) {
val context = navigationOptions.applicationContext
if (PermissionsManager.areLocationPermissionsGranted(context)) {
pushRealLocation(context)
Expand Down Expand Up @@ -174,7 +199,7 @@ class ReplayRouteSession : MapboxNavigationObserver {
}

private fun pushMorePoints() {
val nextPoints = polylineDecodeStream?.decode(options.decodeMinDistance) ?: return
val nextPoints = polylineDecodeStream?.decode(optionsFlow.value.decodeMinDistance) ?: return
val nextReplayLocations = replayRouteMapper.mapPointList(nextPoints)
lastLocationEvent = nextReplayLocations.lastOrNull { it is ReplayEventUpdateLocation }
as? ReplayEventUpdateLocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,8 @@ class MapboxTripStarter internal constructor(
private val tripType = MutableStateFlow<MapboxTripStarterType>(
MapboxTripStarterType.MapMatching
)
private val replayRouteSessionOptions = MutableStateFlow(
ReplayRouteSessionOptions.Builder().build()
)
private val isLocationPermissionGranted = MutableStateFlow(false)
private var replayRouteSession: ReplayRouteSession? = null
private val replayRouteSession = services.getReplayRouteSession()
private val replayHistorySession = services.getReplayHistorySession()
private var mapboxNavigation: MapboxNavigation? = null

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

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

Expand Down Expand Up @@ -155,7 +153,7 @@ class MapboxTripStarter internal constructor(
onMapMatchingEnabled(mapboxNavigation, granted)
}
MapboxTripStarterType.ReplayRoute ->
replayRouteSessionOptions.onEach { options ->
replayRouteSession.getOptions().onEach { options ->
onReplayRouteEnabled(mapboxNavigation, options)
}
MapboxTripStarterType.ReplayHistory ->
Expand All @@ -175,8 +173,7 @@ class MapboxTripStarter internal constructor(
@SuppressLint("MissingPermission")
private fun onMapMatchingEnabled(mapboxNavigation: MapboxNavigation, granted: Boolean) {
if (granted) {
replayRouteSession?.onDetached(mapboxNavigation)
replayRouteSession = null
replayRouteSession.onDetached(mapboxNavigation)
replayHistorySession.onDetached(mapboxNavigation)
mapboxNavigation.startTripSession()
mapboxNavigation.resetTripSession { }
Expand All @@ -200,11 +197,8 @@ class MapboxTripStarter internal constructor(
options: ReplayRouteSessionOptions
) {
replayHistorySession.onDetached(mapboxNavigation)
replayRouteSession?.onDetached(mapboxNavigation)
replayRouteSession = services.getReplayRouteSession().also {
it.setOptions(options)
it.onAttached(mapboxNavigation)
}
replayRouteSession.setOptions(options)
replayRouteSession.onAttached(mapboxNavigation)
}

/**
Expand All @@ -217,8 +211,7 @@ class MapboxTripStarter internal constructor(
mapboxNavigation: MapboxNavigation,
options: ReplayHistorySessionOptions
) {
replayRouteSession?.onDetached(mapboxNavigation)
replayRouteSession = null
replayRouteSession.onDetached(mapboxNavigation)
replayHistorySession.setOptions(options)
replayHistorySession.onAttached(mapboxNavigation)
}
Expand All @@ -229,8 +222,7 @@ class MapboxTripStarter internal constructor(
* @param mapboxNavigation
*/
private fun onTripDisabled(mapboxNavigation: MapboxNavigation) {
replayRouteSession?.onDetached(mapboxNavigation)
replayRouteSession = null
replayRouteSession.onDetached(mapboxNavigation)
replayHistorySession.onDetached(mapboxNavigation)
mapboxNavigation.stopTripSession()
}
Expand Down

0 comments on commit 5b86726

Please sign in to comment.