Device location

Most navigation experiences rely on knowing the location of the device being used. Device location is often used as the origin in route requests and is used to provide location updates that are essential to computing route progress. This guide walks through how the Mapbox Navigation SDK uses device location information, how to customize the device location puck's UI, how to use a custom LocationEngine, and how to use the Navigation SDK with the Maps SDK's LocationComponent.

Navigation UI SDK

The Navigation UI SDK listens to device location changes to update many UI components as the user progresses along a route including displaying a device location puck on the map using the Maps SDK's LocationComponent.

More on LocationEngine

For more details on how LocationEngine works, see the LocationEngine documentation.

Observe location changes

The Navigation SDK's LocationObserver interface listener is for receiving device location updates. Using the LocationObserver interface is optional. It's available in case you want to track device location yourself and do something with the returned Location object’s coordinates or altitude values.

Navigation UI SDK

By default, the Navigation UI SDK will automatically listen to location updates if highly-abstracted Navigation UI SDK classes, for example NavigationMapboxMap or NavigationView, are used. If these classes aren't used, a developer's custom LocationEngine implementation code will need to push Location updates to the Navigation UI SDK.

The LocationObserver’s two methods, onRawLocationChanged and onEnhancedLocationChanged, will fire whenever the device changes location. These updates are only available after the trip session is started.

private val locationObserver = object : LocationObserver {

    override fun onRawLocationChanged(rawLocation: Location) {

    }

    override fun onEnhancedLocationChanged(
        enhancedLocation: Location, keyPoints: List<Location>) {

    }
}

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

mapboxNavigation.registerLocationObserver(locationObserver)

Don’t forget to unregister the LocationObserver interface:

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

onRawLocationChanged

The onRawLocationChanged method delivers a raw Location object from the developer-provided or default internal LocationEngine.

onEnhancedLocationChanged

The onEnhancedLocationChanged method provides the most accurate location update possible. The location is snapped to the route, or if possible, to the road network. The snapping is based on various algorithms in the Navigation SDK's logic.

This Navigation SDK enhanced location logic helps to solve common navigation issues such as:

  • Loss of location coordinate precision in cities with tall buildings
  • Frequency issues
  • Loss of signal in tunnels

If the Navigation SDK isn't able to compute a better Location update, the raw Location will be returned.

keyPoints is a potentially-empty list of predicted Location coordinates that lead up to the latest Location update coordinate. If the list isn't empty, the last coordinate in the list is always equal to enhancedLocation object.

These coordinates are snapped to a route or road. This is especially helpful for making sure the device location puck doesn't cut intersection corners as it traverses through a turn maneuver.

Combine with LocationComponent

To show the a device location puck on a map in a Navigation SDK project, you can use the Maps SDK's LocationComponent. Read more about the Maps SDK's LocationComponent and customizing its look with its styling options.

Navigation UI SDK

By default, the style of the device location puck that is added to the map is inherited by default from the Mapbox Maps SDK for Android LocationComponent. Read more about the Maps SDK's LocationComponent and customizing its look with its styling options.

When using the LocationComponent in combination with the Navigation SDK's LocationObserver interface (described above), you'll need to pass false through the LocationComponentActivationOptions.builder()’s useDefaultLocationEngine() method. This way, you can give the correct Location object to the LocationComponent inside of the onEnhancedLocationChanged() callback method. Once you pass the Location object, the Navigation SDK will move the LocationComponent puck to the appropriate place on the map and make other adjustments.

To activate the LocationComponent:

mapboxMap.setStyle(Style.MAPBOX_STREETS) { style ->
    locationComponent = mapboxMap.locationComponent.apply {
        activateLocationComponent(
LocationComponentActivationOptions.builder(context, style)
            .useDefaultLocationEngine(false)
            .build()
        )
    }
}

Pass the LocationComponent the Location object returned by the LocationObserver:

private val locationObserver = object : LocationObserver {

    override fun onRawLocationChanged(rawLocation: Location) {
    }

    override fun onEnhancedLocationChanged(
        enhancedLocation: Location,
        keyPoints: List<Location>
    ) {
        if (keyPoints.isNotEmpty()) {
            locationComponent?.forceLocationUpdate(keyPoints, false)
        } else {
            locationComponent?.forceLocationUpdate(listOf(enhancedLocation), false)
        }
    }
}
example
Basic Navigation + Maps SDK integration

See how to combine the Navigation SDK with the Maps SDK's LocationComponent

LocationEngine

When a MapboxNavigation object is created, it:

  • Takes LocationEngine as a parameter. When creating the MapboxNavigation object, it requests a LocationEngine instance that will be used to obtain raw Location updates. As described in the section below, you can create and give it a custom LocationEngine.
  • Creates a default LocationEngine if no engine is provided. It runs LocationEngineProvider.getBestLocationEngine(this) to retrieve a LocationEngine.

Location engine request

You can create your own location engine request if you'd like precise control over Location querying and receiving Location updates in your project.

First, create a LocationEngineRequest to specify parameters such as the querying frequency or preferred accuracy:

val locationEngineRequest = LocationEngineRequest.Builder(DESIRED_INTERVAL_BETWEEN_LOCATION_UPDATES_IN_MILLISECONDS)
    .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
    .setMaxWaitTime(DEFAULT_MAX_WAIT_TIME) // sets the maximum wait time in milliseconds for location updates. Locations determined at intervals but delivered in batch based on wait time. Batching is not supported by all engines.
    .build()

Then pass the LocationEngineRequest as MapboxNavigation's constructor parameter.

Listen for raw location updates independently

If you still want to receive location updates when the trip session is stopped, create a custom class that implements the LocationEngineCallback interface. This interface comes from Mapbox's Core library for Android:

private class CustomLocationEngineCallback(activity: Activity) :
    LocationEngineCallback<LocationEngineResult> {

    private val activityRef = WeakReference(activity)

    override fun onSuccess(result: LocationEngineResult?) {

    }

    override fun onFailure(exception: Exception) {

    }
}

Create an instance of the custom callback class:

val customLocationEngineCallback = CustomLocationEngineCallback(activity)

Start requesting Location updates now that you have your LocationEngineRequest and CustomLocationEngineCallback objects:

mapboxNavigation?.locationEngine?.requestLocationUpdates(
    locationEngineRequest,
    customLocationEngineCallback,
    mainLooper // returns your project's main looper, which lives in your project's main thread.
)

Make sure to remove location updating:

override fun onStop() {
    super.onStop()

    mapboxNavigation?.locationEngine?.removeLocationUpdates(locationListenerCallback)
}
Was this page helpful?