> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/android/ja/navigation/llms.txt)

# Coordination Layer

The **Coordination Layer** is an experimental module that helps you build a navigation experience using customizable high-level components.

As compared to classic NavSDK, the Coordination Layer offers multiple advantages:

1.  Its API is higher-level, consisting of multiple customizable building blocks that implement certain scenarios (like active navigation or routes preview), while giving the app full control of entering and exiting these scenarios and the ability to configure them.
2.  It provides better performance and synchronization between the components (route line, camera and location indicator): the Coordination Layer is able to achieve it because it has better control of the components as opposed to classic NavSDK.

3.  Ability to use HD Lite experience with active navigation. In HD Lite experience the route line and the location indicator are aligned with HD roads, elevated intersections and tunnels.

See the [Releases page](https://docs.mapbox.com/android/ja/navigation/releases/coordination) for detailed release notes.

## SDK Installation

> **Note: Get access to Coordination Layer**
> 
> The `Coordination Layer` is a private module. [Contact us](https://www.mapbox.com/support/) to request access.

### 1. Configure credentials and set up repositories

To configure credentials refer to the [Get started](https://docs.mapbox.com/android/ja/navigation/guides/install/) page and to initialize the SDK check the [Initialization guide](https://docs.mapbox.com/android/ja/navigation/guides/initialization/).

### 2. Add the dependency

Add the library dependency to your `build.gradle`. The Coordination Layer module version matches the version of all other [Navigation SDK modules](https://docs.mapbox.com/android/ja/navigation/guides/install/#add-sdk-dependencies) and they have the same release cadence. To ensure version compatibility, make sure your Coordination Layer module version matches the version of the other Navigation SDK modules in your project.

```kotlin
dependencies {
  implementation "com.mapbox.navigationcore:coordination:3.28.2"
}
```

> **Note**
> 
> The Coordination Layer artifact is available starting from version `3.7.0-rc.1`.

#### Possible issues

Depending on the versions of `kotlin-stdlib`, `kotlin-stdlib-jdk7`, `kotlin-stdlib-jdk8` that you use in your project, you might run into the issue that has a similar error message:

```
Duplicate class kotlin.text.jdk8.RegexExtensionsJDK8Kt found in modules kotlin-stdlib-x.y.z.jar and kotlin-stdlib-jdk8-x.y.z.jar.
```

To fix this, exclude the dependencies by adding the following lines into your module's `build.gradle`:

```kotlin
configurations.all {
    resolutionStrategy {
        exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib-jdk8"
        exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib-jdk7"
    }
}
```

## Responsibilities of the Coordination Layer

The Coordination Layer's purpose is to simplify the development of basic navigation scenarios, while still being highly customizable.

Currently supported scenarios are active navigation and routes preview.

### Active navigation

**Responsibilities:**

1.  Control the presentation of the navigation scenario.
2.  Display current vehicle location on the map, animate its movement.
3.  Display navigation routes on the map and erase the traveled part as the vehicle moves.
4.  Display waypoint markers and route arrows.
5.  Handle clicks on alternative routes and automatically switch to the selected alternative.
6.  Implement navigation camera modes to either follow current vehicle location or overview current route.
7.  Support HD Lite mode.
8.  Automatically switch between SD and HD Lite modes based on internal factors (coverage availability, etc.).
9.  Allow to configure visibility and presentation options of location indicator, routes and waypoint markers.

### Routes preview

Note: `RoutesPreviewPresenter` is available starting from NavSDK 3.18.0-beta.1.

**Responsibilities:**

1.  Control the presentation of the routes preview scenario.
2.  Display preview routes on the map.
3.  Display waypoint markers.
4.  Handle clicks on alternative routes and automatically switch to the selected alternative.
5.  Overview previewed routes with camera.
6.  Allow to configure visibility and presentation options routes and waypoint markers.
7.  Promote routes to the navigator (start active guidance by moving them from preview presenter to `MapboxNavigation` and seamlessly transfer the route line to the navigation presenter).

> **Note**
> 
> The Coordination Layer is an alternative simplified way to implement the functionalities listed above. All the other features (requesting routes, loading map style, etc.) should be implemented using the regular NavSDK API.

## Integrate The Coordination Layer module

> **Note (warning): Experimental API**
> 
> The Coordination Layer API is in a preview state and has a high chance of being changed in the future.

The Coordination Layer has 3 main entities:

1.  [`PresentersNavigationContext`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-presenters-navigation-context/)
2.  [`PresentersScreenContext`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-presenters-screen-context/)
3.  Presenter (there are different types of presenters, currently supported ones are: [`NavigationPresenter`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-navigation-presenter/) and [`RoutesPreviewPresenter`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter/).

## `PresentersNavigationContext`

`PresentersNavigationContext` is an entity that holds and interacts with `MapboxNavigation` instance. It should be created once per `MapboxNavigation` instance and reused for multiple presenters (see [Retrieve instances](#retrieve-instances) section).

It can be used to configure and access HD Lite specific navigation options like predictive cache and HD route object matcher.

`PresentersNavigationContext` is required to create instances of `NavigationPresenter` and `RoutesPreviewPresenter`. The way you create it depends on whether you use `MapboxNavigation` directly or create it via `MapboxNavigationApp` (see [Retrieve instances](#retrieve-instances) section for details):

-   When using `MapboxNavigation` directly: [`PresentersNavigationContext.create(mapboxNavigation)`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-presenters-navigation-context/-companion/create.html)
-   When using `MapboxNavigationApp`: [`PresentersNavigationContext.create()`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-presenters-navigation-context/-companion/create.html) (returns `PresentersNavigationContextAppBased`)

## `PresentersScreenContext`

`PresentersScreenContext` is an entity that holds at most one `MapView`. If you have multiple `MapView` instances at the same time (for example, 2 different screens with a map), each one should have its own `PresentersScreenContext`. If `MapView` is re-created due to a configuration change, you can use the same `PresentersScreenContext` instance and update the `MapView` it holds via [`PresentersScreenContext#setMap`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-presenters-screen-context/set-map.html) method.

`PresentersScreenContext` holds a `PresentersCameraManager` that can be used to activate or deactivate camera from a specific presenter (see [`PresentersCameraManager`](#presenterscameramanager) section.)

`PresentersScreenContext` is required to create instances of `NavigationPresenter` and `RoutesPreviewPresenter`.

## Presenters

Presenter is an entity that manages a single UI composition consisting of a map and its visual components within a single scenario (use case). Currently 2 scenarios are supported: active navigation and routes preview. For active navigation scenario, you should use `NavigationPresenter` (see [`NavigationPresenter`](#navigationpresenter) section). For routes preview scenario - `RoutesPreviewPresenter` (see [`RoutesPreviewPresenter`](#routespreviewpresenter) section).

You may choose to only implement the active navigation scenario, in this case you don't have to create a `RoutesPreviewPresenter` instance at all. Another possibility is to use both: while the user plans the trip, you activate `RoutesPreviewPresenter` and when they press a "Start navigation" button, you deactivate `RoutesPreviewPresenter` and activate `NavigationPresenter`. Read the sections below for the detailed description of each presenter.

## `NavigationPresenter`

### Overview

`NavigationPresenter` is the presenter to use in the active navigation use case. It provides a high-level interface to configure presentation options and observe the navigation state.

**Key features:**

-   **Configuration management**: Customize route line, location indicator, and camera appearance
-   **State monitoring**: Access current presenter state through [`NavigationPresenter#state`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-navigation-presenter/state.html), see [`NavigationPresenterState`](#navigationpresenterstate) for more details
-   **Event handling**: Receive events via [`NavigationPresenter#events`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-navigation-presenter/events.html)

Each `NavigationPresenter` holds its own state and can be configured independently. You can create multiple presenters for different UI compositions (e.g., cluster display and head unit) that share the same navigation context.

### Configuration

All the possible configuration options are listed in the [`NavigationPresenterConfig`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-navigation-presenter-config/). You can pass the configuration on initial presenter creation:

```kotlin
val presenter: NavigationPresenter = NavigationPresenter.create(
    screenContext = screenContext,
    navigationContext = navigationContext,
) {
    routeLine {
        vanishingRouteLineStyle(VanishingRouteLineStyle.TRAVELED_COLORS)
        routeLineColorResources(
            RouteLineColorResources.Builder()
                .routeLineTraveledColor(Color.GRAY)
                .routeLineTraveledCasingColor(Color.DKGRAY)
                .build(),
        )
        callouts {
            visible(true)
        }
    }
    locationIndicator {
        sd(
            config2D {
                bearingImage = ImageHolder.from(R.drawable.mapbox_navigation_puck_icon)
            }
        )
        hdLite(
            config3D {
                uri = "asset://3d-location-indicator.glb"
                scale = ScaleValue(listOf(40.0, 40.0, 40.0))
            }
        )
    }
    camera {
        following {
            padding(EdgeInsets(200.0, 200.0, 200.0, 200.0))
        }
        overview {
            overviewAlternativeRoutes(true)
        }
    }
}
```

and you can re-configure it at any point at runtime:

```kotlin
presenter.configure {
    navigationQuality(NavigationDefinitionQuality.HD_LITE)
}
```

### Navigation Presenter Camera

[`NavigationPresenterCamera`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map/-navigation-presenter-camera/) is a sub-controller of `NavigationPresenter` that controls the camera.

The `NavigationPresenterCamera` supports camera handling for navigation and route overview modes. Note that for routes preview case there is a separate `RoutesPreviewPresenterCamera` (see [`RoutesPreviewPresenter`](#routespreviewpresenter) section). You can configure camera options using `NavigationPresenter#configure`:

```kotlin
presenter.configure {
    camera {
        following {
            padding(EdgeInsets(200.0, 200.0, 200.0, 200.0))
            focalPoint(FollowingFrameOptions.FocalPoint(0.5, 0.8))
        }
    }
}
```

Full list of configuration options can be found in [`CameraConfig`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.camera/-camera-config/).

You can also control the mode the camera is in.

#### Set camera mode

`NavigationPresenterCamera` supports 2 modes: `NAVIGATION` and `ROUTE_OVERVIEW`.

In `NAVIGATION` the camera follows the location indicator (both in Free Drive and Active Guidance).

In `ROUTE_OVERVIEW` the camera overviews the current active route. Note that the `ROUTE_OVERVIEW` mode only makes sense when there is an active navigation route. If there's no route (or the route disappears while the camera is in `ROUTE_OVERVIEW` mode), `NavigationPresenterCamera` will fallback to `NAVIGATION` mode, but will animate back to `ROUTE_OVERVIEW` when the route appears.

By default it's in `NAVIGATION` mode. You can change it via invoking:

```kotlin
presenter.camera.setMode(CameraMode.ROUTE_OVERVIEW)
```

and set it back via:

```kotlin
presenter.camera.setMode(CameraMode.NAVIGATION)
```

#### Camera activation/deactivation

Camera activation/deactivation API is located at `PresentersScreenContext` level. See [`PresentersCameraManager`](#presenterscameramanager) section.

### `NavigationPresenterState`

`NavigationPresenter` exposes presenter state: what is currently shown and how. You can access this information like this:

```kotlin
presenter.state.collect {
    // explore the presenter state
}
```

This information can be used to retrieve the routes that are currently being displayed (handled by the presenter) and whether they are visible. Additionally, you can access the layers the routes are attached to. This information might be useful if you want to attach a custom DVA to route line. Find more information in the [`Callouts`](#callouts) section. Also, use this API to understand whether HD Lite mode is currently active or not (see [HD Lite](#hd-lite)).

Full information on what is exposed can be found in the API reference documentation for [NavigationPresenterState](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.store/-navigation-presenter-state/).

## `RoutesPreviewPresenter`

`RoutesPreviewPresenter` is available starting from NavSDK 3.18.0-beta.1.

### Overview

`RoutesPreviewPresenter` is the presenter to use in the preview use case. It provides a high-level interface to configure presentation options and control the routes that are currently being previewed.

**Key features:**

-   **Routes management**: Set the routes to preview via [`RoutesPreviewPresenter#setRoutes`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter/set-routes.html) without setting them to `MapboxNavigation` (i. e. without starting Active Guidance session)
-   **Routes promotion**: Promote previewed routes to navigation via [`RoutesPreviewPresenter#promoteRoutesToNavigation`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter/promote-routes-to-navigation.html). This will under the hood start Active Guidance session, set routes to `MapboxNavigation` and seamlessly transfer the route line to the `NavigationPresenter`
-   **Configuration management**: Customize route line and camera appearance
-   **State monitoring**: Access current presenter state through [`RoutesPreviewPresenter#state`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter/state.html), see [`RoutesPreviewPresenterState`](#routespreviewpresenterstate) for more details
-   **Event handling**: Receive events via [`RoutesPreviewPresenter#events`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter/events.html)

### Configuration

All the possible configuration options are listed in the [`RoutesPreviewPresenterConfig`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter-config/). Note that the configuration options for `RoutesPreviewPresenter` are independent of those for `NavigationPresenter`, meaning that you can configure them differently.

You can pass the configuration on initial presenter creation:

```kotlin
val presenter: RoutesPreviewPresenter = RoutesPreviewPresenter.create(
    screenContext = screenContext,
    navigationContext = navigationContext,
) {
    routeLine {
        routeLineColorResources(
            RouteLineColorResources.Builder()
                .routeLineTraveledColor(Color.BLUE)
                .routeLineTraveledCasingColor(Color.BLACK)
                .build(),
        )
        callouts {
            visible(true)
        }
    }
    camera {
        overview {
            overviewAlternativeRoutes(true)
        }
    }
}
```

and you can re-configure it at any point at runtime:

```kotlin
presenter.configure {
    routeLine {
        originAndDestinationPinsVisible(false)
    }
}
```

### Routes Preview Presenter Camera

[`RoutesPreviewPresenterCamera`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter-camera/) is a sub-controller of `RoutesPreviewPresenter` that controls the camera.

The `RoutesPreviewPresenterCamera` supports overview of the routes that are currently set to `RoutesPreviewPresenter`. Note that for routes that are set to `MapboxNavigation` there is a separate `NavigationPresenterCamera` (see [`NavigationPresenter`](#navigationpresenter) section).

You can configure camera options using `RoutesPreviewPresenter#configure`:

```kotlin
presenter.configure {
    camera {
        overview {
            padding(EdgeInsets(200.0, 200.0, 200.0, 200.0))
            overviewAlternativeRoutes(true)
        }
    }
}
```

Full list of configuration options can be found in [`PreviewCameraConfig`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-preview-camera-config/).

#### Camera activation/deactivation

Camera activation/deactivation API is located at `PresentersScreenContext` level. See [`PresentersCameraManager`](#presenterscameramanager) section.

### `RoutesPreviewPresenterState`

`RoutesPreviewPresenter` exposes presenter state: what is currently shown and how. You can access this information like this:

```kotlin
presenter.state.collect {
    // explore the presenter state
}
```

This information can be used to retrieve the routes that are currently being displayed (handled by the presenter) and whether they are visible.

Additionally, you can access the layers the routes are attached to. This information might be useful if you want to attach a custom DVA to route line. More information can be found in the [`Callouts`](#callouts) section.

Explore the all options exposed in `RoutesPreviewPresenterState` in the [API reference documentation](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter-state/).

## Retrieve instances

The way to retrieve the instances of `PresentersNavigationContext` and `NavigationPresenter` depends on whether you create `MapboxNavigation` instance directly ([`MapboxNavigationProvider#create`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core/-mapbox-navigation-provider/create.html)) or use [`MapboxNavigationApp`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.lifecycle/-mapbox-navigation-app/).

### If you create `MapboxNavigation` directly

If you create a `MapboxNavigation` instance directly, use the following code to retrieve `PresentersScreenContext`, `PresentersNavigationContext`, and `NavigationPresenter`/`RoutesPreviewPresenter` instances:

```kotlin
val screenContext: PresentersScreenContext = PresentersScreenContext.create()
val navigationContext: PresentersNavigationContext = PresentersNavigationContext.create(mapboxNavigation)
val navigationPresenter: NavigationPresenter = NavigationPresenter.create(screenContext, navigationContext)
val routesPreviewPresenter: RoutesPreviewPresenter = RoutesPreviewPresenter.create(screenContext, navigationContext)
```

> **Note (warning): Remove strong references to PresentersNavigationContext**
> 
> When using `MapboxNavigation` directly, it's your responsibility to remove all strong references to `PresentersNavigationContext` when no longer needed (generally when `MapboxNavigation` is destroyed or recreated) to avoid native memory leaks. When using `MapboxNavigationApp`, the lifecycle is managed automatically.

### If you use `MapboxNavigationApp`

If you use `MapboxNavigationApp`, use the following code to retrieve `PresentersScreenContext`, `PresentersNavigationContextAppBased`, and `NavigationPresenter`/`RoutesPreviewPresenter` instances:

```kotlin
val screenContext: PresentersScreenContext = PresentersScreenContext.create()
val appBasedNavigationContext: PresentersNavigationContextAppBased = PresentersNavigationContext.create()
val navigationPresenter: NavigationPresenter = NavigationPresenter.create(screenContext, appBasedNavigationContext)
val routesPreviewPresenter: RoutesPreviewPresenter = RoutesPreviewPresenter.create(screenContext, appBasedNavigationContext)
```

## Lifecycle

### `PresentersNavigationContext`

`PresentersNavigationContext`'s lifecycle can be tied to the Application lifecycle.

1.  If you create `MapboxNavigation` directly (i. e. use `PresentersNavigationContext` and not `PresentersNavigationContextAppBased`), your `PresentersNavigationContext` should live as long as the `MapboxNavigation` instance lives (it dies when you invoke `MapboxNavigationProvider#destroy`).

**Important**: when you destroy `MapboxNavigation`, make sure to not hold a strong reference to `PresentersNavigationContext` to avoid memory leaks.

2.  If you use `MapboxNavigationApp`, your `PresentersNavigationContext` may live as long as your application lives: it will handle the `MapboxNavigation` lifecycle under the hood.

### `PresentersScreenContext` and presenters

`PresentersScreenContext` and presenters instances can be created, for example, inside a ViewModel. If you have multiple presenters (for example, one `NavigationPresenter` and one `RoutesPreviewPresenter`) for one screen, you need only one `PresentersScreenContext` that will be passed as a dependency to both presenter instances. These instances can outlive configuration changes and they should live as long as the screen they correspond to is still relevant. To handle configuration changes, make sure you provide a valid `MapView` instance to `PresentersScreenContext`:

1.  When the view is created (in your `Activity#onCreate` or `Fragment#onViewCreated`), set the map to `PresentersScreenContext`:

```kotlin
presentersScreenContext.setMap(mapView)
```

2.  When the view is destroyed (in your `Activity#onDestroy` or `Fragment#onDestroyView`), nullify the map:

```kotlin
presentersScreenContext.setMap(null)
```

> **Note**
> 
> Make sure to reset the map to avoid memory leaks.

When your screen is fully destroyed, destroy the presenters to clean up resources. You can do that, for example, in your `ViewModel#onCleared`:

```kotlin
navigationPresenter.destroy()
routesPreviewPresenter.destroy()
```

## `PresentersCameraManager`

Different presenters provide their own camera sub-controllers ([`NavigationPresenter#camera`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-navigation-presenter/camera.html) and [`RoutesPreviewPresenter#camera`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter/camera.html)).

To activate a specific camera, use [`PresentersCameraManager`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.camera/-presenters-camera-manager/) API. This is a camera manager that is available on `PresentersScreenContext` level ([`PresentersScreenContext#camera`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-presenters-screen-context/camera.html)) and that handles camera activation/deactivation.

Only one camera may be active at once and `PresentersCameraManager` handles this under the hood: if you activate camera B, but camera A is active, camera A will be deactivated automatically.

For example, if you want to activate Navigation Presenter Camera, you may do it like this:

```kotlin
screenContext.camera.activateCamera(navigationPresenter.camera)
```

To deactivate the currently active camera, use:

```kotlin
screenContext.camera.deactivateCurrentCamera()
```

After this the Coordination Layer will not manipulate the map camera anymore and you may give the control over it to some other (custom) component.

## `Callouts`

### Default callouts

`Callouts` are small views attached to the route line that can be used to display additional information about the route. They are supported for both active navigation (`NavigationPresenter`) and routes preview (`RoutesPreviewPresenter`) scenarios. The Coordination Layer supports rendering callouts for *view-based* map out of the box. You can enable callouts via `RouteLineConfig`:

```kotlin
presenter.configure {
    routeLine {
        callouts {
            visible(true)
        }
    }
}
```

Callouts can be displayed in 2 modes: [`ROUTES_OVERVIEW`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/ui-maps/com.mapbox.navigation.ui.maps.route.callout.model/-route-callout-type/-r-o-u-t-e-s_-o-v-e-r-v-i-e-w.html) and [`NAVIGATION`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/ui-maps/com.mapbox.navigation.ui.maps.route.callout.model/-route-callout-type/-n-a-v-i-g-a-t-i-o-n.html). In `ROUTES_OVERVIEW` mode a callout with ETA is attached to all routes:

![A screenshot showing callouts in overview mode.](https://docs.mapbox.com/android/ja/assets/ideal-img/callouts-overview.eb70a6c.480.jpg)

In `NAVIGATION` mode callouts are attached to alternative routes only, displaying the ETA difference between the alternative and the primary route:

![A screenshot showing callouts in navigation mode.](https://docs.mapbox.com/android/ja/assets/ideal-img/callouts-navigation.3d39bd6.480.jpg)

The callouts design is customizable, see [`CalloutsConfig`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.routeline/-callouts-config/) documentation for details.

Note that rendering callouts with Compose Map is not supported directly in the Coordination Layer, but it exposes all the necessary data to attach the callouts on the app side, see the next section.

### Custom callouts

If you need to attach a callout to route on your side (for example, you use Maps SDK Compose extensions), you can use the information exposed in [`NavigationPresenterState`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.store/-navigation-presenter-state/) or [`RoutesPreviewPresenterState`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.preview/-routes-preview-presenter-state/) to do that.

With every route the callout data (including the layer id the route is attached to) is exposed: [`RouteInfo#callout`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-presenter-route-callout-ui-state/), so you can use it to attach your callout to the route. The layer id might be null if the route does not currently have a layer associated with it (for example, during `MapView` recreation when configuration is changing or if route is not rendered). When layer id is null, you should not attach the callout anywhere and remove any existing callouts for this route.

Example of usage (inside a Composable function):

```kotlin
val routeInfo = presenter.state.map { it.routesInfo }.collectAsState(null).value ?: return
routeInfo.allRoutes.forEach { routeInfo ->
    if (routeInfo.callout != null) {
        ViewAnnotation(
            options = viewAnnotationOptions {
                annotatedLayerFeature(routeInfo.callout!!.layerId)
                // other options
            },
        ) {
            MyRouteCalloutView(
                routeDuration = routeInfo.route.directionsRoute.duration(),
                diffWithPrimary = routeInfo.callout!!.durationDifferenceWithPrimary,
            }
        }
    }
}
```

## HD Lite

The Coordination Layer supports HD Lite mode **for active navigation scenario** (`NavigationPresenter`). For routes preview scenario `RoutesPreviewPresenter` HD Lite mode is not supported.

The look of the HD lite route components is very similar to the existing SD navigation. The difference is that the geometry of the route line and the location indicator position are aligned with the HD road surface.

HD Lite renders elevated roads and positions the route line and location indicator directly on them. It dynamically trims tunnels, overpasses, and buildings so you see your route with greater clarity.

Here are some screenshots that demonstrate features available in HD Lite mode:

![A screenshot showing elevated roads rendered in HD Lite mode.](https://docs.mapbox.com/android/ja/assets/ideal-img/hdlite-bridge-example-1.96b0f2b.480.png)

![A screenshot showing elevated roads rendered in HD Lite mode.](https://docs.mapbox.com/android/ja/assets/ideal-img/hdlite-bridge-example-2.9455bc1.480.png)

If you use HD Lite mode, make sure to use a compatible HD style. [Contact us](https://www.mapbox.com/support/) to get a suitable style.

HD Lite mode is disabled by default, you can enable it via a configuration flag:

```kotlin
presenter.configure {
    navigationQuality(NavigationDefinitionQuality.HD_LITE)
}
```

If you enable HD Lite mode, the Coordination Layer will under the hood switch between SD and HD Lite based on internal factors (coverage availability, HD tiles readiness, zoom levels (you can configure zoom threshold via `hdLiteZoomThreshold` configuration option, see [HD Lite Configuration](#hd-lite-configuration) section for an example)).

When HD Lite mode is active, the map components in the presenters (route line, camera and location indicator) will use HD data (HD geometry of a route and HD-matched location). Location indicator and route line components will also be styled differently (see [Configuration](#hd-lite-configuration) section for details). However, the camera will not automatically change its zooming strategy in HD Lite mode to zoom in more closely to be able to see HD roads in details. Switching camera to a more suitable mode for HD Lite is not yet covered by the Coordination Layer and must be done by the app (see an example below). It is recommended to use higher zoom levels in HD Lite mode to see the HD effect more clearly.

You can observe whether HD Lite mode is active or not via `NavigationPresenterState`:

```kotlin
presenter.state.map { it.navDefinitionQuality }.distinctUntilChanged().collect { navDefinitionQuality ->
    val idHdLiteActive = navDefinitionQuality == NavigationDefinitionQuality.HD_LITE
    if (idHdLiteActive) {
        // configure zooms to be higher, for example, via zoom override
        hdZoomJob = currentSpeed.collect { speed ->
            // for example, if you use speed-based zoom strategy, make sure you adjust it return higher zoom levels in HD Lite mode
            val hdZoom = getHdZoom(speed)
            presenter.configure {
                camera {
                    following {
                        overrides {
                            zoom(hdZoom)
                        }
                    }
                }
            }
        }
    } else {
        hdZoomJob?.cancel()
        // reset zoom overrides or use another strategy
        presenter.configure {
            camera {
                following {
                    overrides {
                        zoom(null)
                    }
                }
            }
        }
    }
}
```

Note that `NavigationPresenterState#navDefinitionQuality` is not equivalent to the flag set in `NavigationPresenterConfig`. As mentioned above, it also takes into account all the internal factors like HD coverage and zoom threshold that affect the possibility of displaying HD Lite components.

### HD Lite configuration

There are multiple configuration options for HD Lite mode:

1.  **Enable/disable HD Lite:**

```kotlin
presenter.configure {
    if (enabled) {
        navigationQuality(NavigationDefinitionQuality.HD_LITE)
    } else {
        navigationQuality(NavigationDefinitionQuality.SD)
    }
}
```

2.  **Configure `PresentersNavigationContext`:**

When creating `PresentersNavigationContext` it is possible to specify custom [`PredictiveCacheLocationOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-location-options/) which will apply to HD navigation only:

```kotlin
val presentersNavigationContext = PresentersNavigationContext.create {
    loadPredictiveCacheForAlternativeRoutes(true)
    // other options if needed
}
```

3.  **Configure HD Lite location indicator using custom model asset:**

```kotlin
presenter.configure {
    locationIndicator {
        hdLite(
            config3D {
                uri = "asset://3d-location-indicator.glb"
                scale = ScaleValue(listOf(40.0, 40.0, 40.0))
            }
        )
    }
}
```

4.  **Configure SD / HD Lite switch zoom threshold**

The Coordination Layer under the hood switches between SD and HD Lite modes based on multiple internal factors including current zoom level.

By default this zoom level is set to 15.0, because on lower zooms HD roads are not shown so the HD Lite mode doesn't make any sense there.

You can configure this threshold:

```kotlin
presenter.configure {
    camera {
        hdLiteZoomThreshold(18.0)
    }
}
```

5.  **Adjust `NavigationOptions`**

For HD matching to work correctly, you need to set a proper custom config and HD tiles options when activating `MapboxNavigation`. Note that these configuration options belong to [`NavigationOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-navigation-options/) and not to [`NavigationPresenterConfig`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-navigation-presenter-config/).

First, extend your custom config (if you use any) or create a new one in a way that it includes the following options:

```kotlin
    const val HD_LITE_CUSTOM_CONFIG = """
{
  "navigation": {
    "hd": {
      "enabled": true,
      "mapMatcher": {
        "emissionCost": {
          "camera": {
            "enableLanesComparison": false,
            "enableRoadMarkingsComparison": false
          }
        }
      },
      "offRoad": {
        "transitionPointOffRoadDetector": {
          "percentAlongMultiplier": 1.5
        }
      },
      "route": {
        "adaptableCandidateFinder": {
          "mediumRoadClassFilter": {
            "headingTolerance": 55.0
          }
        },
        "alternatives": {
          "adaptableCandidateFinder": {
            "mediumRoadClassFilter": {
              "headingTolerance": 55.0
            }
          },
          "routeLaneGuidance": {
            "maxForwardDistance":2000
          },
          "viterbiRouteMatcher": {
            "lookAheadInAdvance":2500
          }
        },
        "routeLaneGuidance": {
          "maxForwardDistance":2000
        },
        "viterbiRouteMatcher": {
          "lookAheadInAdvance":2500
        }
      }
    }
  }
}
    """
```

Then create HD tiles options. Create the default options to always pick the latest HD tiles or specify a custom version:

```kotlin
val hdTilesOptions = DomainTilesOptions.defaultHdTilesOptionsBuilder()
    .tilesBaseUri(URI("https://api-3dln-tiles-production.mapbox.com"))
    .build()
```

Finally, pass the custom config together with the tile options to `NavigationOptions`:

```kotlin
val mapboxNavigation = MapboxNavigationProvider.create(
    NavigationOptions.Builder(this)
        .deviceProfile(
            DeviceProfile.Builder()
                .customConfig(HD_LITE_CUSTOM_CONFIG)
                .build()
        )
        .routingTilesOptions(
            RoutingTilesOptions.Builder()
                .hdTilesOptions(hdTilesOptions)
                .build()
        )
        .build()
)
```

### Share PresentersNavigationContext for optimal performance

> **Note (warning): Critical for performance**
> 
> Always share the same [`PresentersNavigationContext`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-presenters-navigation-context/) instance across multiple [`NavigationPresenter`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-navigation-presenter/) instances when you have multiple screens displaying navigation data.

This architecture is essential for optimal performance because:

-   **All complex native calculations are performed once**: HD map-matching, route matching, and location processing happen in the navigation context, not in individual presenters
-   **Multiple screens with different visual styles**: Each [`NavigationPresenter`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter/-navigation-presenter/) can have its own [`MapView`](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.maps/-map-view/) and visual configuration while sharing the underlying data
-   **Significant performance improvement**: When you have multiple screens (e.g., main display and instrument cluster), expensive calculations run once instead of being duplicated per presenter

### Route objects matching

`PresentersNavigationContext` can be used to do route object matching (such as incidents, maneuvers etc.) from SD to HD and elevate the objects on top of elevated bridges or tunnels.

![A screenshot showing HD matched objects on top of the elevated road.](https://docs.mapbox.com/android/ja/assets/ideal-img/hd-matched-elevated-objects.8c982f9.480.png)

Red circles display original matchable points on the SD route and green markers HD matched elevated objects.

> **Note: HD Matcher usage notes**
> 
> -   Recommended and easiest way is to provide the full list of matchable objects for the whole route at once
> -   If a route changes, objects won't be rematched automatically - you need to invoke `RouteObjectMatcher` again with the new route

Steps to match route objects to HD route and apply an elevation to render the objects on top of elevated roads :

1.  Configure map source and layer :

```kotlin
val matchedObjectsSourceId = "matched-objects-source"
val matchedObjectsLayerId = "matched-objects-layer"

mapView.mapboxMap.loadStyle(styleUri) { style ->
    // Add source
    style.addSource(
        geoJsonSource(matchedObjectsSourceId) {
            featureCollection(FeatureCollection.fromFeatures(emptyList()))
        }
    )

    // Add layer (can be SymbolLayer, CircleLayer, or LineLayer)
    val matchedObjectsLayer = SymbolLayer(matchedObjectsLayerId, matchedObjectsSourceId).apply {
        iconImage("marker-icon")
    }
    style.addLayer(matchedObjectsLayer)

    // Enable elevation for the layer
    mapView.mapboxMap.addLayerElevationProperty(matchedObjectsLayer)
}
```

> **Note (warning): Elevating the HD objects**
> 
> The [MapboxMap.addLayerElevationProperty](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map/add-layer-elevation-property.html) function is required for objects to be properly elevated on top of HD road layers. It supports [SymbolLayer](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.maps.extension.style.layers.generated/-symbol-layer/), [CircleLayer](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.maps.extension.style.layers.generated/-circle-layer/) and [LineLayer](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.maps.extension.style.layers.generated/-line-layer/).

2.  Observe matched objects and add elevated features to the source:

```kotlin
// Store matched objects
private val matchedObjects = mutableListOf<MatchedRouteObject>()

presentersNavigationContext
    .getHdRouteObjectMatcher()
    .addMatchingObserver(
        object : RouteObjectMatcherObserver {
            override fun onRouteObjectsMatched(result: Expected<List<MatchedRouteObjectError>, List<MatchedRouteObject>>) {
                result.fold(
                    { errors ->
                        // handle map-matching errors for multiple objects
                        errors.forEach { error ->
                            Log.e("RouteObjectMatcher",
                                "Error matching object ${error.matchableRouteObject.id}: ${error.error}")
                        }
                    },
                    { newMatchedRouteObjects ->
                        // Add newly matched objects to our collection
                        matchedObjects.addAll(newMatchedRouteObjects)

                        // Convert to features with elevation data
                        val features = matchedObjects.map { matchedObject ->
                            matchedObject.buildElevatedFeature()
                        }

                        // Update the map source
                        updateMatchedObjectsSource(FeatureCollection.fromFeatures(features))
                    }
                )
            }

            override fun onMatchingCancelled(matchableRouteObjects: List<MatchableRouteObject>) {
                // handle cancellation of multiple objects
                matchableRouteObjects.forEach { matchableRouteObject ->
                    // handle individual cancellation
                }
            }
        },
    )
```

> **Note (warning): Add elevated property to the source**
> 
> To apply the elevation for the matched objects, generate the features using [matchedObject.buildElevatedFeature](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.dto/-matched-route-object/build-elevated-feature.html).

3.  Request matching for route objects:

```kotlin
val routeObjects: Set<MatchableRouteObject> = setOf()
presentersNavigationContext
    .getHdRouteObjectMatcher()
    .matchRouteObjects(routeObjects)
```

### Configure Lane Level Guidance (LLG)

Lane Level Guidance (LLG) highlights the lanes which should be used for driving during active navigation. It will show up instead of the route line when the zoom level is higher than the configurable threshold. LLG is disabled by default for HD Lite and can be enabled via configuration:

```kotlin
presenter.configure {
    laneLevelGuidance {
        theme {
            color(literal("yellow"))
            glowAdditiveColor(literal("#FF0000"))
            glowBackdropColor(rgb(0.0, 1.0, 0.0))
        }
        position(/* ... */)
        zoomThreshold(19.5)
        enabledInHdLite(true)
    }
}
```

-   `theme` sets the visual appearance with [`LaneLevelGuidanceTheme`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.llg/-lane-level-guidance-theme/).
-   `position` sets the position of the LLG component on the map.
-   `zoomThreshold` sets the zoom level at which the LLG will show up instead of the route line. The effective value is clamped between `CameraConfig.hdLiteZoomThreshold` and `CameraConfig.hdFullZoomThreshold`.
-   `enabledInHdLite` controls whether LLG renders in HD Lite quality. In HD Full quality LLG is always enabled regardless of this value. By default, LLG is disabled in HD Lite quality and always enabled in HD Full quality.

See [`LaneLevelGuidanceThemeUpdateBuilder`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.llg/-lane-level-guidance-theme-update-builder/) for all theming options.

> **Note**
> 
> LLG configuration is shared across HD Lite and HD Full quality.

### Configure cutout

The Coordination Layer supports cutout around the location indicator. This feature creates a cutout in the elevated roads, tunnels, bridges and other 3D objects to improve visual clarity. Cutout settings are shared across HD Lite and HD Full quality. The cutout behavior differs between free drive and active guidance modes.

The cutout is highly customizable with different distances and fade effects.

#### Free drive cutout

In free drive mode (when not navigating a route), the cutout follows the predicted path ahead of the vehicle. Configure free drive cutout using [`CutoutAroundLocationIndicatorFreeDriveConfig`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.cutout/-cutout-around-location-indicator-free-drive-config/):

```kotlin
presenter.configure {
    cutout {
        aroundLocationIndicator {
            freeDrive {
                enabled(true)
                aheadDistance(100)
                aheadFadeDistance(100)
                behindFadeDistance(100)
                width(CutoutWidth.Auto)
                widthFadeFraction(0.2)
                maxNumberOfForkOnPath(1)
            }
        }
    }
}
```

See [`CutoutAroundLocationIndicatorFreeDriveConfigUpdateBuilder`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.cutout/-cutout-around-location-indicator-free-drive-config-update-builder/) for all configuration options and their descriptions.

#### Active guidance cutout

During active guidance (when navigating a route), the cutout follows the route line ahead and behind the location indicator. Configure active guidance cutout using [`CutoutAroundLocationIndicatorActiveGuidanceConfig`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.cutout/-cutout-around-location-indicator-active-guidance-config/):

```kotlin
presenter.configure {
    cutout {
        aroundLocationIndicator {
            activeGuidance {
                enabled(true)
                aheadDistance(100)
                aheadFadeDistance(100)
                behindFadeDistance(100)
                width(CutoutWidth.Auto)
                widthFadeFraction(0.2)
            }
        }
    }
}
```

See [`CutoutAroundLocationIndicatorActiveGuidanceConfigUpdateBuilder`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.cutout/-cutout-around-location-indicator-active-guidance-config-update-builder/) for all configuration options and their descriptions.

#### Width configuration

The cutout width can be configured in two ways for both free drive and active guidance modes:

1.  **Auto width** ([`CutoutWidth.Auto`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.cutout/-cutout-width/-auto/)): The width is automatically calculated based on the HD road width of the current lane group.
2.  **Fixed width** ([`CutoutWidth.Fixed`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/private_preview/coordination/com.mapbox.navigation.coordination.scope.presenter.map.cutout/-cutout-width/-fixed/)): The width is fixed to a specific value in meters.

Example:

```kotlin
// Using automatic width
width(CutoutWidth.Auto)

// Using fixed width of 10 meters
width(CutoutWidth.Fixed(10.0))
```

## Sample application

To get a sample application that showcases the Coordination Layer integration, [contact us](https://www.mapbox.com/support/).