Beta
Navigation SDK for Android v2

Route generation

Before a user can begin turn-by-turn navigation with your application, you must provide the Navigation SDK with a route. You can generate a route from the Mapbox Directions API using the Navigation SDK by providing both an origin and a destination Point object. There are several ways you can customize the returned route and how it is displayed in your application including:

  • Adding stops (or waypoints) between the origin and destination.
  • Making sure the route begins in the direction in which the driver is already traveling to prevent needing a u-turn.
  • Specifying the side of the road to approach when arriving at the destination or at stops along the route.

If you need complete route customization, you can provide a custom already-generated route that is not from the Mapbox Directions API, then transform it into the correct format to be used with the Navigation SDK using the Mapbox Java SDK's Map Matching wrapper. For instructions on this process, see the Use a custom route section.

Note

If you provide both a DirectionsRoute and a pair of coordinates (origin and destination), only the DirectionsRoute will be used.

Request a route

The Navigation SDK uses routes generated by the Mapbox Directions API. After you’ve created a MapboxNavigation object, you can use its requestRoutes() method to request routes from the Mapbox Directions API.

The method requires a built RouteOptions object as defined in the Mapbox Java SDK's Directions wrapper. The RouteOptions class has convenient methods for setting the various route parameters. You can find full descriptions of each parameter in the Directions API documentation.

You can use the Java SDK's RouteOptions.builder class to create a RouteOptions class as you create a new route request. There are many methods that can be used to customize your request, three of which are required:

  • accessToken()
  • coordinates()
  • applyDefaultParams(): if you don't want to customize other options, explicitly use the defaults
mapboxNavigation.requestRoutes(
    RouteOptions.builder()
        .applyDefaultParams()
        .accessToken(MAPBOX_TOKEN)
        .coordinates(listOf(originPoint, destinationPoint))
        .build()
)

The origin and destination are Point coordinates that need to be in a single list of Points. The origin should be the first Point in the list and the destination should be the last Point. If there are any other Points in the list between the origin and destination, these Points are considered waypoints.

Include waypoint stops

If your navigation experience involves several stops along the way to the final destination, you can add up to 25 coordinates (including the origin and destination) to the RouteOptions builder. The coordinates are treated as stops in between the origin and destination Points in the order that you add them (the first waypoint Point is the first stop along the route):

mapboxNavigation.requestRoutes(
    RouteOptions.builder()
        .accessToken(MAPBOX_TOKEN)
        .coordinates(listOf(originPoint, firstWaypoint, secondWaypoint, thirdWaypoint, destinationPoint))
        .geometries(RouteUrl.GEOMETRY_POLYLINE6)
        .profile(RouteUrl.PROFILE_DRIVING)
        .build()
)

Request a route in a specific direction

The Navigation SDK can make a Directions API request that takes into account the direction the device is facing. The returned route will be ideal for the device's particular bearing.

Device location: In the adjacent diagram, the blue dot with white stroke is the device location.

Bearing: The bearing tells you the direction that a device is facing. It is an angle clockwise from true north between 0 and 359. For example, if the device is facing north, the bearing will be 0°, and if the device is facing due east, the bearing will be 90°. In the adjacent diagram, the pink arrow is the direction that the device is facing (which is due west or 270°).

Tolerance: Tolerance is the range of degrees by which a route can deviate from the bearing angle and still be recommended. The semi-transparent blue area illustrates tolerance. In this example tolerance is 90° (45° in either direction from the bearing angle).

The RouteOptions.builder()'s bearingsList() method is a list of a double lists. The first double value in a single list, the bearing, should be an angle clockwise from true north between 0 and 355. The second value in a single list, the tolerance, should be the range of degrees by which the angle can deviate (recommended value is 45 or 90).

If the bearingsList() method is used, the list of double pairs must be the same length as the list of Points passed through the coordinates() method. However, you can skip a coordinate and show its position in the double list with the null value.

mapboxNavigation.requestRoutes(
    RouteOptions.builder()
        .applyDefaultParams()
        .accessToken(MAPBOX_TOKEN)
        .coordinates(listOf(originPoint, destinationPoint))
        .profile(RouteUrl.PROFILE_DRIVING)
        .bearingsList(listOf(listOf(bearing, tolerance)))
        .build()
)

Request a route including the bearing value from the device's last known Location object:

mapboxMap.locationComponent.lastKnownLocation?.let { location ->

    val lastKnownBearing = location.bearing
    val tolerance = 90

    mapboxNavigation.requestRoutes(
    RouteOptions.builder()
      .applyDefaultParams()
      .accessToken(MAPBOX_TOKEN)
      .coordinates(listOf(originPoint, destinationPoint))
      .profile(RouteUrl.PROFILE_DRIVING)
      .bearingsList(listOf(listOf(lastKnownBearing, tolerance))
      .build()
  )
}

Specify a side of the road to approach

You can state from which side of the road to approach a waypoint by adding approaches to the RouteOptions builder. There are three options found in the DirectionsCriteria class:

  • "unrestricted" (default): the route can approach waypoints from either side of the road. Use DirectionsCriteria.APPROACH_UNRESTRICTED.
  • "curb": the route will be returned so that on arrival, the waypoint will be found on the side that corresponds with the driving_side of the region in which the returned route is located. Use DirectionsCriteria.APPROACH_CURB.
  • null: if no option is specified, it is translated internally to "", which has the same result as setting an approach to "unrestricted". Use null.

If provided, the list of approaches must be the same length as the list of coordinates (including the origin and the destination) and in that particular order (origin, waypoints, destination).

If a re-route occurs and approaches were used to fetch the first DirectionsRoute, the new route fetched will take the same approaches criteria into account.

mapboxNavigation.requestRoutes(
    RouteOptions.builder()
        .applyDefaultParams()
        .accessToken(MAPBOX_TOKEN)
        .coordinates(listOf(originPoint, firstWaypoint, secondWaypoint, thirdWaypoint, destinationPoint))
        .profile(RouteUrl.PROFILE_DRIVING)
        .approachesList(listOf(DirectionsCriteria.APPROACH_UNRESTRICTED,
        DirectionsCriteria.APPROACH_UNRESTRICTED, DirectionsCriteria.APPROACH_CURB, null, DirectionsCriteria.APPROACH_CURB))
        .build()
)

Check the status of a route request

The Navigation SDK's mapboxNavigation.requestRoutes() method requires two parameters: a RouteOptions object and a RouterCallback interface object. The Navigation SDK’s RouterCallback interface provides methods, which inform you about the status of a route request.

private val routesReqCallback = object : RouterCallback {

    override fun onRoutesReady(routes: List<DirectionsRoute>) {

    }

    override fun onFailure(reasons: List<RouterFailure>, routeOptions: RouteOptions) {

    }

    override fun onCanceled(routeOptions: RouteOptions) {

    }
}

Add the RouterCallback object to the mapboxNavigation.requestRoutes() method:

mapboxNavigation.requestRoutes(
    RouteOptions.builder()
        .applyDefaultParams()
        .accessToken(MAPBOX_TOKEN)
        .coordinates(listOf(originPoint, destinationPoint))
        .geometries(RouteUrl.GEOMETRY_POLYLINE6)
        .profile(RouteUrl.PROFILE_DRIVING)
        .build(),

        routesReqCallback
)
Trip session state

Calling requestRoutes() affects the TripSessionState. If you call startTripSession() without calling requestRoutes(), you'll be in "Free-drive" state. If you call requestRoutes() after startTripSession(), you'll be in "Active Guidance" state.

Listen for route changes

Use the Navigation SDK’s RoutesObserver interface if you want to know when the routes list has changed.

private val routesObserver = object : RoutesObserver {
    override fun onRoutesChanged(routes: List<DirectionsRoute>) {

    }
}

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

mapboxNavigation.registerRoutesObserver(routesObserver)

Don’t forget to unregister the RoutesObserver interface:

override fun onStop() {
    super.onStop()
    mapView.onStop()
    mapboxNavigation.unregisterRoutesObserver(routeProgressObserver)
}

Use a custom route

In some cases, you may want your user to navigate along a route that doesn't match the Mapbox Directions API route's structure while still using the Mapbox Navigation SDK. The Mapbox Java SDK's Map Matching wrapper is an appropriate tool for turning your custom route into a route that the Navigation SDK can process.

Map match to generate a route

Map matching is the art of taking coordinates and aligning them along a road network. After providing coordinates to the Java SDK's MapboxMapMatching.builder(), the Java SDK makes the request to the Mapbox Map Matching API, and then the API returns a route that can be used in the Navigation SDK for Android.

To get started with creating a map matched DirectionsRoute, first install the Java SDK's services module into your project.

Your MapboxMapMatching request will need a List of Point geometry objects that represent the custom route you want to match with the road network.

val singlePoint = Point.fromLngLat()

Create a MapboxMapMatching request:

val mapboxMapMatchingRequest = MapboxMapMatching.builder()
    .accessToken(getString(R.string.mapbox_access_token))
    .coordinates(customRoutePointList)
    .steps(true)
    .voiceInstructions(true)
    .bannerInstructions(true)
    .profile(DirectionsCriteria.PROFILE_DRIVING)
    .build()

If successful, the response will have a matched route. Convert this route to a DirectionsRoute and give it to the already-instantiated MapboxNavigation object:

mapboxMapMatchingRequest.enqueueCall(object : Callback<MapMatchingResponse> {
    override fun onResponse(call: Call<MapMatchingResponse>, response: Response<MapMatchingResponse>) {
        if (response.isSuccessful) {
            response.body()?.matchings()?.let { matchingList ->
                matchingList[0].toDirectionRoute().apply {
                    mapboxNavigation?.setRoutes(listOf(this))
                }
            }

        }
    }

    override fun onFailure(call: Call<MapMatchingResponse>, throwable: Throwable) {

    }
})

When using MapboxMapMatching with the Navigation SDK, you need to make a few changes to your setup to make sure re-routes are successful. A custom RerouteController must be set to your MapboxNavigation or rerouting needs to be disabled entirely. Otherwise, Navigation SDK would try to request a new route directly from Mapbox Directions API.