Extended visual guidance

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 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. This guide covers two types of detailed visual instructions you can present to the driver in addition to the default written and audio instructions:

  • Signboards
  • Junction views
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.

Signboards

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.

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 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, which converts the SVG to Bitmap using a third-party rendering engine. MapboxSvgToBitmapParser is a default implementation of SvgToBitmapParser used by MapboxSignboardApi. The Navigation SDK also exposes a standalone widget, MapboxSignboardView, 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:

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:

class MySvgToBitmapParser : SvgToBitmapParser() {

  override fun parse(
        svg: ByteArray,
        options: MapboxSignboardOptions
    ): Expected<Bitmap, String> {
        // your logic to convert svg to bitmap
    }  
}
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. 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:

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

With the default Mapbox SVG parser:

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

With a custom SVG parser:

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

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:

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

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

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

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

Invoke API call

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

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

Create an instance of signboard callback

MapboxSignboardApi.generateSignboard expects a callback as one of its parameters. The callback is of the type MapboxNavigationConsumer, which informs you about the state of signboard.

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 to your layout file:

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

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

Junction views

More information on junction views coming soon

More details on adding junction views to your project are coming soon. For information on junction views, see the API reference.