Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Mapbox welcomes participation and contributions from everyone.
- Fixed memory leak in `ReplayProgressObserver` which happened after route refresh. [#6691](https://github.com/mapbox/mapbox-navigation-android/pull/6691)
- Fixed a rare issue where a reroute relative to old routes might have occurred after setting new routes. [#6693](https://github.com/mapbox/mapbox-navigation-android/pull/6693)
- Added experimental `MapboxRouteLineOptions#shareLineGeometrySources` option to enable route line's GeoJson source data sharing between multiple instances of the map. [#6680](https://github.com/mapbox/mapbox-navigation-android/pull/6680)
- Fixed issues in `ReplayRouteSession`. The routes observer was never unregistered. Alternative route selection resets replay to the beginning. DropInUi changing portrait and landscape modes resets replay to the beginning. [#6675](https://github.com/mapbox/mapbox-navigation-android/pull/6675)

## Mapbox Navigation SDK 2.9.4 - 08 December, 2022
### Changelog
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,15 @@ class ReplayPolylineDecodeStream(
}
return points
}

/**
* Skip the next [count] points of the geometry. Less points are skipped if there are less than
* [count] points left in the iterator.
*
* @param count the number of points to skip.
*/
fun skip(count: Int) {
var skipped = 0
while (skipped++ <= count && hasNext()) { next() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.mapbox.android.core.permissions.PermissionsManager
import com.mapbox.api.directions.v5.DirectionsCriteria
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
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.lifecycle.MapboxNavigationApp
Expand All @@ -17,6 +18,7 @@ import com.mapbox.navigation.core.replay.MapboxReplayer
import com.mapbox.navigation.core.replay.history.ReplayEventBase
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 java.util.Collections

Expand Down Expand Up @@ -54,15 +56,29 @@ class ReplayRouteSession : MapboxNavigationObserver {

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

private lateinit var polylineDecodeStream: ReplayPolylineDecodeStream
private lateinit var replayRouteMapper: ReplayRouteMapper
private var mapboxNavigation: MapboxNavigation? = null
private var lastLocationEvent: ReplayEventUpdateLocation? = null
private var routesObserver: RoutesObserver? = null
private var currentRouteId: String? = null
private var polylineDecodeStream: ReplayPolylineDecodeStream? = null
private var currentRoute: NavigationRoute? = null

private val routeProgressObserver = RouteProgressObserver { routeProgress ->
if (currentRoute?.id != routeProgress.navigationRoute.id) {
currentRoute = routeProgress.navigationRoute
onRouteChanged(routeProgress)
}
}

private val routesObserver = RoutesObserver { result ->
if (result.navigationRoutes.isEmpty()) {
mapboxNavigation?.resetReplayLocation()
currentRoute = null
polylineDecodeStream = null
}
}

private val replayEventsObserver = ReplayEventsObserver { events ->
if (isLastEventPlayed(events)) {
if (currentRoute != null && isLastEventPlayed(events)) {
pushMorePoints()
}
}
Expand Down Expand Up @@ -92,45 +108,44 @@ class ReplayRouteSession : MapboxNavigationObserver {
this.mapboxNavigation = mapboxNavigation
mapboxNavigation.stopTripSession()
mapboxNavigation.startReplayTripSession()

routesObserver = RoutesObserver { result ->
if (result.navigationRoutes.isEmpty()) {
currentRouteId = null
mapboxNavigation.resetReplayLocation()
} else if (result.navigationRoutes.first().id != currentRouteId) {
onRouteChanged(result.navigationRoutes.first())
}
}.also { mapboxNavigation.registerRoutesObserver(it) }
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
mapboxNavigation.registerRoutesObserver(routesObserver)
mapboxNavigation.mapboxReplayer.registerObserver(replayEventsObserver)
mapboxNavigation.resetReplayLocation()
mapboxNavigation.mapboxReplayer.play()
}

private fun MapboxNavigation.resetReplayLocation() {
mapboxReplayer.clearEvents()
resetTripSession()
if (options.locationResetEnabled) {
val context = navigationOptions.applicationContext
if (PermissionsManager.areLocationPermissionsGranted(context)) {
pushRealLocation(context)
} else {
logW(LOG_CATEGORY) {
"Location permission have not been accepted. If this is intentional, disable" +
" this warning with ReplayRouteSessionOptions.locationResetEnabled."
resetTripSession {
if (options.locationResetEnabled) {
val context = navigationOptions.applicationContext
if (PermissionsManager.areLocationPermissionsGranted(context)) {
pushRealLocation(context)
} else {
logW(LOG_CATEGORY) {
"Location permissions have not been accepted. If this is intentional, " +
"disable this warning with " +
"ReplayRouteSessionOptions.locationResetEnabled."
}
}
}
mapboxReplayer.play()
}
mapboxReplayer.play()
}

override fun onDetached(mapboxNavigation: MapboxNavigation) {
this.mapboxNavigation = null
mapboxNavigation.unregisterRoutesObserver(routesObserver)
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
mapboxNavigation.mapboxReplayer.unregisterObserver(replayEventsObserver)
mapboxNavigation.mapboxReplayer.stop()
mapboxNavigation.mapboxReplayer.clearEvents()
mapboxNavigation.stopTripSession()
this.mapboxNavigation = null
this.currentRoute = null
}

private fun onRouteChanged(navigationRoute: NavigationRoute) {
private fun onRouteChanged(routeProgress: RouteProgress) {
val navigationRoute = routeProgress.navigationRoute
val mapboxReplayer = mapboxNavigation?.mapboxReplayer ?: return
mapboxReplayer.clearEvents()
mapboxReplayer.play()
Expand All @@ -144,9 +159,12 @@ class ReplayRouteSession : MapboxNavigationObserver {
}
return
}
currentRouteId = navigationRoute.id
polylineDecodeStream = ReplayPolylineDecodeStream(geometry, 6)
mapboxNavigation?.resetTripSession()

// Skip up to the current geometry index. There is some imprecision here because the
// distance traveled is not equal to a route index.
polylineDecodeStream?.skip(routeProgress.currentRouteGeometryIndex)

pushMorePoints()
}

Expand All @@ -158,7 +176,7 @@ class ReplayRouteSession : MapboxNavigationObserver {
}

private fun pushMorePoints() {
val nextPoints = polylineDecodeStream.decode(options.decodeMinDistance)
val nextPoints = polylineDecodeStream?.decode(options.decodeMinDistance) ?: return
val nextReplayLocations = replayRouteMapper.mapPointList(nextPoints)
lastLocationEvent = nextReplayLocations.lastOrNull { it is ReplayEventUpdateLocation }
as? ReplayEventUpdateLocation
Expand Down
Loading