Route progress
When turn-by-turn navigation starts, your project must track the user's progress along the route to provide relevant information appropriately and prompt. The RouteProgress
object in the Navigation SDK contains this essential information, and this page will guide you on how to use it effectively.
Levels of route progress
The Mapbox Navigation SDK's model for tracking route progress has three pieces with different levels of granularity: the route, the leg, and the step.
Route: The blue line is a route. A route stretches between the origin and the final destination.
Leg: The larger circles with a pink stroke represent waypoints, or stops, along the route. A leg is the part of the route between two waypoints.
Step: The smaller circles with a green stroke represent maneuvers. A step is the part of the leg between two maneuvers.
The Navigation SDK uses three classes to communicate information on the user's progress at these three different levels: RouteProgress
, RouteLegProgress
, and RouteStepProgress
.
RouteProgress
The RouteProgress
class contains all the progress information at any time during a navigation session. A new RouteProgress
object is generated whenever there's a new valid Location
update or if no new Location
update is received in the past second.
RouteProgress
information includes distance measurements, the percentage of the route that's been completed, the current step index, the remaining number of route legs, and much more. For further information on data encapsulated in RouteProgress
, you can view the API reference docs here.
RouteLegProgress
The RouteLegProgress
class is specific to the current leg the user is on. For further information on data encapsulated in RouteLegProgress
, you can view the API reference docs here.
RouteStepProgress
The RouteStepProgress
class is a progress object specific to the current step the user is on. For further information on data encapsulated in RouteStepProgress
, you can view the API reference docs here.
Route progress and UI components
Several of the Navigation SDK's default UI components use route progress data to present guidance information to your users. Here's how each component uses route progress data:
- Maneuvers: Invoke the Maneuver API when route progress changes to receive updated banner instruction data any time the route progress changes. Read more in the Maneuver instructions guide.
- Trip progress: Invoke the Trip Progress API when route progress changes to keep the estimated arrival time, distance remaining, and time remaining up to date as the user progresses along the route. Read more in the Trip progress guide.
- Route line: Invoke the Route Line API to render a route line on a map.
- Route arrow: Invoke the Route Arrow API when route progress changes to determine when to show an arrow on the route line.
- Buildings: Invoke the Buildings API when route progress changes to highlight the building upon arrival at a waypoint or final destination.
- Notifications: Invoke the
MapboxNavigation#updateNotification
when route progress changes to receive updated maneuver instructions when the app is running in background. Read more in the Notifications guide.
Apart from leveraging route progress to drive the user interface elements offered by the SDK, you have the flexibility to tailor your application's behavior in response to the user's movement along the route. This can be achieved by monitoring progress changes, assessing the state of route progress, and executing customized code based on these factors.
Listen to progress change
Tracking a user's progress along a route is key to providing helpful and prompt navigation instructions. Implement the Navigation SDK's RouteProgressObserver
interface to receive a RouteProgress
object every time the user's location changes.
The RouteProgressObserver
is commonly utilized to update your application's user interface in response to changes in route progress. For instance, if you are showing the user's current progress up to their next maneuver, you can refresh your display whenever the onRouteProgressChanged()
method of this interface is triggered. Each time this occurs, you can update your view with the latest information contained in the RouteProgress
object.
private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
}
}
If you've created your own RouteProgressObserver
object, you'll need to:
- Register the
RouteProgressObserver
with your already-instantiatedMapboxNavigation
object.
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
- Don’t forget to unregister the observer with
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
.
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
RouteProgressState
The Navigation SDK's RouteProgressState
is an enum
that contains various states that can occur while navigating. Using RouteProgressState
helps you gain a better understanding of what's happening in the navigation experience.
The RouteProgressObserver
returns a RouteProgress
object. Check the current state with the RouteProgressState
object inside the returned RouteProgress
object:
private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
routeProgress.currentState()?.let { currentState ->
val state = currentState
}
}
}
There are five possible states: INITIALIZED
, TRACKING
, COMPLETE
, OFF_ROUTE
, and UNCERTAIN
.
Initialized
When a new route is first loaded and the DirectionsRoute
JSON is valid, route-following will start in the RouteProgressState.INITIALIZED
state. From there, route-following will try to gain confidence that the Location
objects being passed to the device are the user's location. To show this trust, at least a few location updates need to be delivered, and they must be consecutively coherent in both time and space. While it is establishing this trust, the route-following logic will report that it's still in the RouteProgressState.INITIALIZED
state.
Tracking
Once MapboxNavigation
is confidently tracking the Location
updates and processing them against the DirectionsRoute
. The state will change to RouteProgressState.TRACKING
.
Complete
When the user has arrived at the destination of the given RouteLeg
, the state will be RouteProgressState.COMPLETE
.
Off Route
The RouteProgressState.OFF_ROUTE
occurs when the navigation system determines the user has deviated from the established route.
Uncertain
The RouteProgressState.UNCERTAIN
state occurs when the Navigation SDK has already been tracking location updates (RouteProgressState.TRACKING
), but the route-snapping algorithm has temporarily lost confidence. For example, due to a rerouting when the device strays off the turn-by-turn directions route. After a couple of Location
updates after the rerouting, RouteProgressState
would return back to RouteProgressState.TRACKING
.
Visualizing the route progress state
The route progress state can be communicated to users by updating the style of the puck during navigation. In your RouteProgressObserver
check the state and update the drawable used for the puck. You can design your own custom drawables and use them as shown below.
private val routeProgressObserver = object : RouteProgressObserver {
override fun onRouteProgressChanged(routeProgress: RouteProgress) {
routeProgress.currentState.let { currentState ->
val puckDrawable = when (currentState) {
RouteProgressState.INITIALIZED -> R.drawable.your_drawable_for_initialized_state
RouteProgressState.TRACKING -> R.drawable.your_drawable_for_tracking_state
RouteProgressState.COMPLETE -> R.drawable.your_drawable_for_complete_state
RouteProgressState.OFF_ROUTE -> R.drawable.your_drawable_for_off_route_state
RouteProgressState.UNCERTAIN -> R.drawable.your_drawable_for_uncertain_state
}
mapView.location.apply {
this.locationPuck = LocationPuck2D(
bearingImage = ContextCompat.getDrawable(context, puckDrawable)
)
}
}
}
}