Route progress

Once turn-by-turn navigation begins, your project will need to follow the user's progress along the route to deliver contextual information in the correct way at the correct time. The Navigation SDK's RouteProgress object contains this information and this page teaches you about using it.

Navigation UI SDK

The Navigation UI SDK consumes the RouteProgress object to display the user's progress along the route across several different UI components, including:

  • Display route information like total duration and distance remaining in the bottom bar.
  • Display information about the next step in the instructions banner.
  • Animate the progress bar.
  • Show error messages when appropriate.
  • Display the arrival screen.

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.

RouteLegProgress

The RouteLegProgress class is specific to the current leg the user is on. If there is only one leg in the directions route, much of this information will be the same as in the parent RouteProgress.

RouteStepProgress

The RouteStepProgress class is a progress object specific to the current step the user is on.

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 can typically be used to refresh most of your application's user interface when a change occurs. For example, if you're displaying the user's current progress until the user needs to do the next maneuver. Every time this interface's onRouteProgressChanged() method fires, you can update your view with the new information inside the RouteProgress object.

private RouteProgressObserver routeProgressObserver = new RouteProgressObserver() {
@Override
public void onRouteProgressChanged(RouteProgress routeProgress) {
}
};
Navigation UI SDK

By default, the Navigation UI SDK automatically uses the information in the RouteProgress object to update various UI components as the device moves along the route.

If you want to use a custom RouteProgressObserver object with NavigationView, pass the RouteProgressObserver object to the NavigationViewOptions.builder():

NavigationViewOptions.Builder optionsBuilder = NavigationViewOptions.builder();
optionsBuilder.routeProgressObserver(routeProgressObserver);
navigationView.startNavigation(optionsBuilder.build());

If you've created your own RouteProgressObserver object, you'll need to:

  1. Register the RouteProgressObserver with your already-instantiated MapboxNavigation object.
mapboxNavigation.registerRouteProgressObserver(routeProgressObserver);
  1. Don’t forget to unregister the observer with mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver). This line isn't needed if you're already running MapboxNavigation's onDestroy() method, which automatically unregisters the observer for you.
@Override
public void onStop() {
super.onStop();
mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver);
}

Show Route Progress

Navigation UI SDK

The Navigation UI SDK's NavigationMapRoute class displays a route line on the map. You can style the route by passing in a style resource when first constructing an instance of this class. There is also an option to alter the appearance of the route line based on the user's current progress along the route, specifically whether to display the section of the route line the user has already completed (the route line behind the user's current location).

If you are using NavigationMapRoute, this behavior is controlled by the vanishRouteLineEnabled parameter. By default, the value is false and the route line will not vanish behind the puck during navigation. You can make the route line vanish behind the puck by setting the vanishRouteLineEnabled parameter to true and providing a reference to MapboxNavigation:

@Override
MapboxNavigation mapboxNavigation = new MapboxNavigation(...);
NavigationMapRoute navigationMapRoute = new NavigationMapRoute.Builder(...)
.withMapboxNavigation(mapboxNavigation)
.withVanishRouteLineEnabled(true)
.build();

If you are using NavigationView, you can enable this behavior with NavigationViewOptions using enableVanishingRouteLine:

NavigationViewOptions.Builder optionsBuilder = NavigationViewOptions.builder();
optionsBuilder.enableVanishingRouteLine(true)
navigationView.startNavigation(optionsBuilder.build())

If the vanishing route line option is enabled using either method, you can customize the color and transparency of the section of the route line the user has already completed. See the section on styling for more information about the route line appearance.

example
Navigation MapRoute Activity

This activity demonstrates turn by turn navigation using the NavigationMapRoute class. This can be used instead of the convenience class NavigationMapboxMap if it suits your needs.

RouteProgressState

The Navigation SDK's RouteProgressState enum contains various states that can occur while navigating. Using RouteProgressState helps you gain a better of understanding of what's happening in the overall navigation experience.

The RouteProgressObserver returns a RouteProgress object. Check the current state with the RouteProgressState object inside the returned RouteProgress object:

private RouteProgressObserver routeProgressObserver = new RouteProgressObserver() {
@Override
public void onRouteProgressChanged(RouteProgress routeProgress) {
if (routeProgress.currentState() != null) {
RouteProgressState state = routeProgress.currentState();
}
}
};

There are six possible states: ROUTE_INVALID, ROUTE_INITIALIZED, LOCATION_TRACKING, ROUTE_ARRIVED, LOCATION_STALE, and ROUTE_UNCERTAIN.

Invalid

If the DirectionsRoute provided via MapboxNavigation.startNavigation() is not valid, the state will be RouteProgressState.ROUTE_INVALID.

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 in the process of establishing this trust, the route-following logic will report that it's still in the RouteProgressState.ROUTE_INITIALIZED state.

Tracking

Once MapboxNavigation is confidently tracking the Location updates and processing them against the DirectionsRoute. The state will change to RouteProgressState.LOCATION_TRACKING.

Arrived

When the user has arrived at the destination of the given RouteLeg, the state will be RouteProgressState.ROUTE_ARRIVED.

Stale

If a lack of Location updates has caused a lack of confidence in the progress updates being sent, the state will be RouteProgressState.LOCATION_STALE.

Uncertain

The RouteProgressState.ROUTE_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 re-route when the device strays off the turn-by-turn directions route. After a couple of Location updates after the re-route, RouteProgressState would return back to RouteProgressState.TRACKING.

Navigation UI SDK

The Navigation UI SDK uses RouteProgressState to style the puck based on the current state. The Navigation UI SDK exposes APIs that allow you to use default Mapbox-provided drawables or specify custom drawables for the puck based on the current state.

By default, the Mapbox Navigation UI SDK provides the following puck drawables for each route progress state:

RouteProgressStatePuck Drawable Image
Invalid
Initialized
Tracking
Arrived
Stale
Uncertain

To use these default Mapbox-provided images, use PuckDrawableSupplier.

If you are using NavigationView:

@Override
public void onNavigationReady(boolean isRunning) {
NavigationViewOptions.Builder optionsBuilder = NavigationViewOptions.builder();
optionsBuilder.puckDrawableSupplier(new DefaultMapboxPuckDrawableSupplier());
navigationView.startNavigation(optionsBuilder.build());
}

If you are using NavigationMapboxMap:

navigtionMapboxMap.setPuckDrawableSupplier(new DefaultMapboxPuckDrawableSupplier());

You can also specify custom drawables for different route progress states. In order to create your own PuckDrawableSupplier, you will have to override the implementation as follows and replace DefaultMapboxPuckDrawableSupplier() with your implementation.

class MyPuckDrawableSupplier implements PuckDrawableSupplier {
@Override
public int getPuckDrawable(@NotNull RouteProgressState routeProgressState) {
switch (routeProgressState) {
case ROUTE_INITIALIZED:
case LOCATION_TRACKING:
case LOCATION_STALE:
return R.drawable.custom_user_puck_icon;
case ROUTE_INVALID:
case ROUTE_ARRIVED:
default:
return R.drawable.custom_puck_icon_uncertain_location;
}
}
}

Arrival experience

Show and create experiences when arriving at waypoints and destinations. There are a few options for customizing the arrival experience.

ArrivalObserver

The ArrivalObserver interface is a callback, and you can have many observers. Each observer will receive one callback for every state change.

ArrivalObserver arrivalObserver = new ArrivalObserver() {
@Override public void onNextRouteLegStart(@NotNull RouteLegProgress routeLegProgress) {
}
@Override public void onFinalDestinationArrival(@NotNull RouteProgress routeProgress) {
}
};
  • onNextRouteLegStart is called once the driver has arrived at a stop and has started navigating the next leg. navigateNextRouteLeg will also be true when this happens.
  • onFinalDestinationArrival is called once the driver has reached the final destination at the end of the route. routeProgress.currentState() will equal RouteProgressState.ROUTE_ARRIVED.

Register the ArrivalObserver interface with your already-instantiated MapboxNavigation object.

mapboxNavigation.registerArrivalObserver(arrivalObserver);

Don’t forget to unregister the ArrivalObserver interface:

@Override
public void onStop() {
super.onStop();
mapView.onStop();
mapboxNavigation.unregisterArrivalObserver(arrivalObserver);
}

ArrivalController

The ArrivalController allows you to decide when to navigate the next RouteLeg when navigating waypoints and routes with multiple stops. Use the ArrivalOptions class to decide when you want to receive navigateNextRouteLeg callbacks as you approach a stop.MapboxNavigation.attachArrivalController(yourArrivalController).

AutoArrivalController is the default and will automatically navigateNextRouteLeg. To override this behavior, attach your own ArrivalController or MapboxNavigation.removeArrivalController().

  • When your controller navigateNextRouteLeg returns true, the navigator will start navigating to the next stop.
  • When your controller navigateNextRouteLeg returns false forever, use MapboxNavigation.navigateNextRouteLeg directly to continue navigation.

You can attach your own ArrivalController. This example shows you can use both time and distance:

navigation.attachArrivalController(new ArrivalController() {
@NotNull @Override public ArrivalOptions arrivalOptions() {
return ArrivalOptions.Builder()
.arriveInSeconds(10.0)
.arriveInMeters(50.0)
.build();
}
@Override public boolean navigateNextRouteLeg(@NotNull RouteLegProgress routeLegProgress) {
return routeLegProgress.distanceRemaining() < 5.0;
}
});

Building highlighting

Navigation UI SDK

The Navigation UI SDK provides logic to highlight a particular building footprint Polgyon in the form of a Mapbox Maps SDK for Android FillLayer or extrude a footprint as a 3D building shape in the form of a Mapbox Maps SDK for Android FillExtrusionLayer.

In the context of navigation, this highlighting is especially good for visually representing your user's next stop or final destination. For example, a package delivery driver might want to see the exact building that's associated with a delivery address. In this case, showing the highlighting would happen inside of the Navigation Core SDK's ArrivalObserver callback methods.

By default, this highlight logic exposes methods to change the highlighting visibility, opacity, and color. Because the logic is adding a FillLayer or FillExtrusionLayer to the map's Style object, all of the Maps SDK data-driven styling properties are at your disposal for adjusting the layers.

The only building Features that are eligible for highlighting are ones whose Feature properties satisfy all of the following:

  • "extrude" = true
  • "underground" = false

Query coordinate

This highlighting logic depends on setting a query LatLng coordinate. Setting this coordinate tells the Navigation UI SDK to look for a building that's associated with the coordinate. If the coordinate doesn't fall within the building footprint (think of a single Point within a Polygon shape), then the highlighting won't work. Mapbox doesn't provide a way to connect an address with a coordinate that will consistently fall within the footprint of the building associated with that address. You must have your own data and a way to determine what coordinate should be used as the query LatLng coordinate.

Highlight a building footprint

The Navigation UI SDK's BuildingFootprintHighlightLayer handles the required code for adding and styling a FillLayer to highlight a building footprint.

MapboxMap mapboxMap = navigationView.retrieveNavigationMapboxMap().retrieveMap();
BuildingFootprintHighlightLayer buildingFootprintHighlightLayer = new BuildingFootprintHighlightLayer(mapboxMap);
buildingFootprintHighlightLayer.setQueryLatLng(new LatLng(latitude,longitude));
buildingFootprintHighlightLayer.updateVisibility(true);

You can change the color and opacity of the highlighted building footprint:

buildingFootprintHighlightLayer.setOpacity(0.5f);
buildingFootprintHighlightLayer.setColor(Color.BLUE);
example
Highlight a building footprint

See a complete working example of how to highlight a single building footprint.

Highlight a building extrusion

The Navigation UI SDK's BuildingExtrusionHighlightLayer handles the required code for adding and styling a FillExtrusionLayer to highlight a 3D building extrusion. The extrusion's height is based on the height property of the GeoJSON Feature associated with that particular building footprint.

MapboxMap mapboxMap = navigationView.retrieveNavigationMapboxMap().retrieveMap();
BuildingExtrusionHighlightLayer buildingExtrusionHighlightLayer = new BuildingExtrusionHighlightLayer(mapboxMap);
buildingExtrusionHighlightLayer.setQueryLatLng(new LatLng(latitude,longitude));
buildingExtrusionHighlightLayer.updateVisibility(true);

You can change the color and opacity of the highlighted building extrusions:

buildingExtrusionLayer.setOpacity(0.5f);
buildingExtrusionLayer.setColor(Color.BLUE);
example
Highlight a building extrusion

See a complete working example of how to highlight a single 3D building extrusion.