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

# Signboards

> **Note: Data access**
> 
> Detailed visual maneuver instructions are only available for select maneuvers and require an access token from an account with access to this feature. To request access to this feature, [contact the Mapbox support team](https://support.mapbox.com/hc/en-us).

The Navigation SDK provides information about what action a driver needs to take to get from one step to the next along a route in maneuver instructions. The [Maneuver instructions](https://docs.mapbox.com/android/navigation/v2/guides/ui-components/maneuver/) guide provides written instructions in the application's UI. But, sometimes additional context is helpful when a maneuver instruction takes place in a particularly complex part of the road network.

Signboards help the user navigate through complex maneuvers. They present a combination of textual and graphical data in a format that aligns with what a user sees on the street signs in reality. A signboard consists of following pieces of information:

-   A signboard or panel with a background color consistent with the color of physical road signs of that type in that region.
-   Text consistent with what appears on physical road signs. This might include exit, exit number, freeway number or name, road name, from route, to route, destination, and other tertiary data as available.
-   Road shields in the style of physical signs in that region.
-   Lane indicators in the form of arrows.
-   An exit icon.

![Mobile devices displaying signboard.](https://docs.mapbox.com/android/assets/ideal-img/navigation-signboard.efb409f.480.png)

When you request a route using the Navigation SDK, if a signboard is available for a step along the route it will be returned as a part of the banner instructions for that step in the `imageUrl` property of the [Mapbox Java SDK's](https://docs.mapbox.com/android/java/guides/) `BannerComponents` class.

When you request the image using the `imageUrl`, you will receive a signboard in a raw SVG format. The raw SVG cannot be rendered directly on the screen. To render the signboard, you will need to convert the raw SVG to Bitmap. As a convenience, Mapbox Navigation SDK exposes [`SvgToBitmapParser`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.guidance.signboard.api/-svg-to-bitmap-parser/), which converts the SVG to Bitmap using a third-party rendering engine. [`MapboxSvgToBitmapParser`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.guidance.signboard.api/-mapbox-svg-to-bitmap-parser/) is a default implementation of `SvgToBitmapParser` used by [`MapboxSignboardApi`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.guidance.signboard.api/-mapbox-signboard-api/). The Navigation SDK also exposes a standalone widget, [`MapboxSignboardView`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.guidance.signboard.view/-mapbox-signboard-view/), that renders the Bitmap on the screen.

Learn how to request a signboard and render it on top of your view below.

### Create an instance of signboard API

If you want to use the default `SvgToBitmapParser` included with the Navigation SDK, instantiate `MapboxSignboardApi`:

```kotlin
private val applicationContext = this@MyActivity
private val signboardApi: MapboxSignboardApi by lazy {
    MapboxSignboardApi(<YOUR_ACCESS_TOKEN_VALUE>),
    applicationContext
}
```

If you want to use your own implementation of `SvgToBitmapParser`, create an implementation of `SvgToBitmapParser` and then instantiate `MapboxSignboardApi`:

```kotlin
class MySvgToBitmapParser : SvgToBitmapParser() {

  override fun parse(
        svg: ByteArray,
        options: MapboxSignboardOptions
    ): Expected<Bitmap, String> {
        // your logic to convert svg to bitmap
    }  
}
```

```kotlin
private val mySvgParser = MySvgToBitmapParser()
private val signboardApi: MapboxSignboardApi by lazy {
    MapboxSignboardApi(<YOUR_ACCESS_TOKEN_VALUE>),
    mySvgParser,
    MapboxSignboardOptions.Builder().build()
}
```

The `MapboxSignboardApi` also takes an optional parameter, [`MapboxSignboardOptions`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.guidance.signboard.model/-mapbox-signboard-options/). The option allows you to specify the `desiredWidth` of the signboard you would want to display as well as the CSS styling. If not specified, the signboard will use a default width of `400px` and a default font family and font size in the CSS.

If you would like to define your own options:

```kotlin
private val signboardOptions: MapboxSignboardOptions by lazy {
    MapboxSignboardOptions.Builder()
        .desiredWidth(<YOUR_VALUE>)
        .cssStyle(<YOUR_VALUE>)
        .build()
}
```

With the default Mapbox SVG parser:

```kotlin
private val signboardApi: MapboxSignboardApi by lazy {
    MapboxSignboardApi(<YOUR_ACCESS_TOKEN_VALUE>),
    context,
    signboardOptions
}
```

With a custom SVG parser:

```kotlin
private val signboardApi: MapboxSignboardApi by lazy {
    MapboxSignboardApi(<YOUR_ACCESS_TOKEN_VALUE>),
    mySvgParser,
    signboardOptions
}
```

> **Note**
> 
> While you can specify a width with `MapboxSignboardOptions`, you can't specify a height. To make sure the image is scaled properly, we use the aspect ratio defined in the raw signboard SVG image to calculate the height based on the width.

The Navigation SDK uses [androidsvg](https://bigbadaboom.github.io/androidsvg/) to render SVG to Bitmap. To resolve fonts for signboards, the library exposes `SVGExternalFileResolver`. The Navigation SDK creates a wrapper around this resolver with a default implementation for reading font files. `SVGExternalFileResolver` is injected as a constructor parameter to `MapboxSvgToBitmapParser`.

To use your own resolver, instantiate `MapboxSignboardApi`:

```kotlin
class MyResolver : SVGExternalFileResolver() {

  override fun resolveFont(fontFamily: String?, fontWeight: Int, fontStyle: String?): Typeface? {

  }  
}

private val signboardApi: MapboxSignboardApi by lazy {
    MapboxSignboardApi(<YOUR_ACCESS_TOKEN_VALUE>),
    MapboxSvgToBitmapParser(MyResolver()),
    signboardOptions
}
```

### Listen to banner instruction changes

Once you have instantiated the API, add the code below to listen to new banner instruction events:

```kotlin
private val bannerInstructionsObserver = object : BannerInstructionsObserver {
    override fun onNewBannerInstructions(bannerInstructions: BannerInstructions) {
    }
}
```

Make sure you register and unregister `bannerInstructionsObserver` in the appropriate places:

```kotlin
override fun onStart() {
    super.onStart()
    mapboxNavigation.registerBannerInstructionsObserver(bannerInstructionsObserver)
}

override fun onStop() {
    super.onStart()
    mapboxNavigation.unregisterBannerInstructionsObserver(bannerInstructionsObserver)
}
```

Don't forget to cancel any potential in-flight `MapboxSignboardApi` requests in `onStop` or `onDestroy`:

```kotlin
override fun onDestroy() {
    super.onDestroy()
    signboardApi.cancelAll()
}
```

### Invoke API call

Now that you have registered to banner instruction event updates, every time `onNewBannerInstructions` is triggered, invoke the API:

```kotlin
private val bannerInstructionsObserver = object : BannerInstructionsObserver {
    override fun onNewBannerInstructions(bannerInstructions: BannerInstructions) {
        signboardApi.generateSignboard(bannerInstructions, signboardCallback)
    }
}
```

### Create an instance of signboard callback

[`MapboxSignboardApi.generateSignboard`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.guidance.signboard.api/-mapbox-signboard-api/generate-signboard.html) expects a callback as one of its parameters. The callback is of the type [`MapboxNavigationConsumer`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-base/com.mapbox.navigation.ui.base.util/-mapbox-navigation-consumer/), which informs you about the state of signboard.

```kotlin
private val signboardCallback = object :
    MapboxNavigationConsumer<Expected<SignboardValue, SignboardError>> {
    override fun accept(value: Expected<SignboardValue, SignboardError>) {
    }
}
```

This callback is triggered internally by the `generateSignboard` API and contains an `Expected` property, which is either of the type `SignboardValue` or `SignboardError`.

Now you have access to the raw SVG contained in `SignboardValue` in the form of `byteArray`.

### Render the signboard

Add [`MapboxSignboardView`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.guidance.signboard.view/-mapbox-signboard-view/) to your layout file:

```xml
<com.mapbox.navigation.ui.maps.guidance.signboard.view.MapboxSignboardView
    android:id="@+id/signboardView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="4dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent" />
```

Now that you have received the data inside the callback as `Expected` you need to invoke `render` on `MapboxSignboardView` to render the data. Inside `accept` invoke the call:

```kotlin
private val signboardCallback = object :
    MapboxNavigationConsumer<Expected<SignboardValue, SignboardError>> {
    override fun accept(value: Expected<SignboardValue, SignboardError>) {
        signboardView.render(value)
    }
}
```