# Route progress

> **Note (legacy): A newer version of the Navigation SDK is available**
> 
> This page uses v1.6.2 of the Mapbox Navigation SDK. A newer version of the SDK is available. Learn about the latest version, v2.22.2, in the [Navigation SDK documentation](https://docs.mapbox.com/android/navigation/v2/guides/turn-by-turn-navigation/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.

**Java**

```java

private RouteProgressObserver routeProgressObserver = new RouteProgressObserver() {
  @Override
  public void onRouteProgressChanged(RouteProgress routeProgress) {

  }  
};
```

**Kotlin**

```kt

private val routeProgressObserver = object : RouteProgressObserver {
  override fun 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()`:

**Java**

```java

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

**Kotlin**

```kt

val 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](https://docs.mapbox.com/android/legacy/navigation/guides/install/#create-a-mapboxnavigation-object).

**Java**

```java

mapboxNavigation.registerRouteProgressObserver(routeProgressObserver);
```

**Kotlin**

```kt

mapboxNavigation.registerRouteProgressObserver(routeProgressObserver)
```

2.  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.

**Java**

```java

@Override
public void onStop() {
  super.onStop();
  mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver);
}
```

**Kotlin**

```kt

override fun 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`:

**Java**

```java

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

**Kotlin**

```kt

val mapboxNavigation = MapboxNavigation(...)
val navigationMapRoute = NavigationMapRoute.Builder(...)
  .withMapboxNavigation(mapboxNavigation)
  .withVanishRouteLineEnabled(true)
  .build()
```

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

**Java**

```java

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

**Kotlin**

```kt

val 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](https://docs.mapbox.com/android/legacy/navigation/guides/styles/#map-route) for more information about the route line appearance.

> **Related content (example): [Navigation MapRoute Activity](https://github.com/mapbox/mapbox-navigation-android/blob/v1.6.0/examples/src/main/java/com/mapbox/navigation/examples/core/NavigationMapRouteActivity.java)**
> 
> 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 navigation experience.

The [`RouteProgressObserver`](#listen-to-progress-change) returns a [`RouteProgress` object](#routeprogress). Check the current state with the `RouteProgressState` object inside the returned `RouteProgress` object:

**Java**

```java

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

**Kotlin**

```kt

private val routeProgressObserver = object : RouteProgressObserver {
  override fun onRouteProgressChanged(routeProgress: RouteProgress) {
    routeProgress.currentState()?.let { currentState ->
      val state = 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 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, 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:

| RouteProgressState | Puck Drawable Image |
| --- | --- |
| Invalid |  |
| Initialized |  |
| Tracking |  |
| Arrived |  |
| Stale |  |
| Uncertain |  |

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

If you are using `NavigationView`:

**Java**

```java

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

**Kotlin**

```kt

override fun onNavigationReady(isRunning: Boolean) {
  val optionsBuilder = NavigationViewOptions.builder()
  optionsBuilder.puckDrawableSupplier(DefaultMapboxPuckDrawableSupplier())
  navigationView.startNavigation(optionsBuilder.build())
}
```

If you are using `NavigationMapboxMap`:

**Java**

```java

navigtionMapboxMap.setPuckDrawableSupplier(new DefaultMapboxPuckDrawableSupplier());
```

**Kotlin**

```kt

navigtionMapboxMap.setPuckDrawableSupplier(DefaultMapboxPuckDrawableSupplier())
```

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

**Java**

```java

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;
    }
  }
}
```

**Kotlin**

```kt

class MyPuckDrawableSupplier : PuckDrawableSupplier {
  override fun getPuckDrawable(routeProgressState: RouteProgressState): Int = when (routeProgressState) {
    RouteProgressState.ROUTE_INVALID -> R.drawable.custom_puck_icon_uncertain_location
    RouteProgressState.ROUTE_INITIALIZED -> R.drawable.custom_user_puck_icon
    RouteProgressState.LOCATION_TRACKING -> R.drawable.custom_user_puck_icon
    RouteProgressState.ROUTE_ARRIVED -> R.drawable.custom_puck_icon_uncertain_location
    RouteProgressState.LOCATION_STALE -> R.drawable.custom_user_puck_icon
    else -> 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.

**Java**

```java

ArrivalObserver arrivalObserver = new ArrivalObserver() {
    @Override public void onNextRouteLegStart(@NotNull RouteLegProgress routeLegProgress) {

    }

    @Override public void onFinalDestinationArrival(@NotNull RouteProgress routeProgress) {

    }
};
```

**Kotlin**

```kt

val arrivalObserver = object : 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](https://docs.mapbox.com/android/legacy/navigation/guides/install/#create-a-mapboxnavigation-object).

**Java**

```java

mapboxNavigation.registerArrivalObserver(arrivalObserver);
```

**Kotlin**

```kt

mapboxNavigation.registerArrivalObserver(arrivalObserver)
```

Don't forget to unregister the `ArrivalObserver` interface:

**Java**

```java

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

**Kotlin**

```kt

override fun onStop() {
    super.onStop()
  	mapView.onStop()
  	mapboxNavigation.unregisterArrivalObserver(locationObserver)
}
```

### `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:

**Java**

```java

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;
  }
});
```

**Kotlin**

```kt

mapboxNavigation.attachArrivalController(object : ArrivalController {
    override fun arrivalOptions(): ArrivalOptions = ArrivalOptions.Builder()
        .arriveInSeconds(10.0)
        .arriveInMeters(50.0)
        .build()

    override fun navigateNextRouteLeg(routeLegProgress: RouteLegProgress): Boolean {

        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](https://docs.mapbox.com/android/legacy/navigation/guides/route-progress/#arrivalobserver).

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.

The only building `Feature`s that are eligible for highlighting are ones whose `Feature` properties meet all 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.

![screenshot of a highlighted building footprint](https://docs.mapbox.com/android/assets/ideal-img/navigation-building-footprint.762c8a8.480.png)

**Java**

```java

MapboxMap mapboxMap = navigationView.retrieveNavigationMapboxMap().retrieveMap();

BuildingFootprintHighlightLayer buildingFootprintHighlightLayer = new BuildingFootprintHighlightLayer(mapboxMap);

buildingFootprintHighlightLayer.setQueryLatLng(new LatLng(latitude,longitude));

buildingFootprintHighlightLayer.updateVisibility(true);
```

**Kotlin**

```kt

var mapboxMap = navigationView.retrieveNavigationMapboxMap().retrieveMap()

var buildingFootprintHighlightLayer = BuildingFootprintHighlightLayer(mapboxMap)

buildingFootprintHighlightLayer.queryLatLng = LatLng(latitude,longitude)

buildingFootprintHighlightLayer.updateVisibility(true)
```

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

**Java**

```java

buildingFootprintHighlightLayer.setOpacity(0.5f);
buildingFootprintHighlightLayer.setColor(Color.BLUE);
```

**Kotlin**

```kt

buildingFootprintHighlightLayer.opacity = 0.5f
buildingFootprintHighlightLayer.color = Color.BLUE
```

> **Related content (example): [Highlight a building footprint](https://github.com/mapbox/mapbox-navigation-android/blob/v1.6.0/examples/src/main/java/com/mapbox/navigation/examples/ui/BuildingFootprintHighlightActivity.kt)**
> 
> 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.

![screenshot of a highlighted building extrusion](https://docs.mapbox.com/android/assets/ideal-img/navigation-building-extrusion.a036cb0.480.png)

**Java**

```java

MapboxMap mapboxMap = navigationView.retrieveNavigationMapboxMap().retrieveMap();

BuildingExtrusionHighlightLayer buildingExtrusionHighlightLayer = new BuildingExtrusionHighlightLayer(mapboxMap);

buildingExtrusionHighlightLayer.setQueryLatLng(new LatLng(latitude,longitude));

buildingExtrusionHighlightLayer.updateVisibility(true);
```

**Kotlin**

```kt

var mapboxMap = navigationView.retrieveNavigationMapboxMap().retrieveMap()

var buildingExtrusionHighlightLayer = BuildingExtrusionLayer(mapboxMap)

buildingExtrusionHighlightLayer.queryLatLng = LatLng(latitude,longitude)

buildingExtrusionHighlightLayer.updateVisibility(true)
```

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

**Java**

```java

buildingExtrusionLayer.setOpacity(0.5f);
buildingExtrusionLayer.setColor(Color.BLUE);
```

**Kotlin**

```kt

buildingExtrusionLayer.opacity = 0.5f
buildingExtrusionLayer.color = Color.BLUE
```

> **Related content (example): [Highlight a building extrusion](https://github.com/mapbox/mapbox-navigation-android/blob/v1.6.0/examples/src/main/java/com/mapbox/navigation/examples/ui/BuildingExtrusionHighlightActivity.kt)**
> 
> See a complete working example of how to highlight a single 3D building extrusion.