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

# Location tracking

The Mapbox Navigation SDK uses raw device location to power important navigation features including:

-   Enhancing location updates and snapping them to the road graph.
-   Determining which instruction to show next, and when to show it, based on where the user is along the route.
-   Detecting when the driver has deviated from the current route, prompting the SDK to generate a new route to get them back on track.
-   Proactively downloading map tiles and routing information ahead of the driver's current location in case the driver enters an area with no or poor network connection.

The Navigation SDK depends on two other Mapbox SDKs, the **Mapbox Android Core** library and the **Maps SDK for Android**, to handle location permissions, track location updates, and show device location on a map. These SDKs are bundled with the Navigation SDK, and you do not need to install them separately.

## Privacy and permissions

Users must grant your application permission before it can access information about their location. During this permission prompt, you can present a custom string explaining how location will be used.

If you're building your Android project targeting API level 23 or higher, your application will need to request permissions at runtime. Handling this directly in your activity produces boilerplate code and can often be hard to manage. One option is to use the Mapbox Core Library for Android's [`PermissionsManager`](https://docs.mapbox.com/android/core/guides/#permissionsmanager) class. When using the Mapbox Core Library, you can specify the text used in the permission prompt using [`onExplanationNeeded`](https://docs.mapbox.com/android/telemetry/api/libcore/3.1.0/com/mapbox/android/core/permissions/PermissionsListener.html#onExplanationNeeded-java.util.List-).

## Location provider

By default, the Navigation SDK utilizes the Mapbox Core Library for Android's [`LocationEngine`](https://docs.mapbox.com/android/telemetry/api/libcore/3.1.0/com/mapbox/android/core/location/LocationEngine.html) class to fetch the user's location. The `LocationEngine` class simplifies the process of getting location information and supports the following location providers:

-   Google's Fused Location Providers
-   Android GPS and Network Providers

> **Note: Use Google's Fused Location Provider**
> 
> By default, the Navigation SDK uses the Android GPS and Network Providers to get raw location updates. In applications using Android 11, the raw location updates might suffer from precision issues.The Navigation SDK also comes with support for the [Google's Fused Location Provider](https://developers.google.com/location-context/fused-location-provider). If your target devices support Google Play Services, add the following [Google Play Location Services dependency](https://developers.google.com/android/guides/setup) to your project, and the Navigation SDK will use the Google's Fused Location Provider in your application automatically:`groovyimplementation("com.google.android.gms:play-services-location:21.0.1")`

> **Note: More on LocationEngine**
> 
> For more details on how `LocationEngine` works, [see the `LocationEngine` documentation](https://docs.mapbox.com/android/telemetry/api/libcore/3.1.0/com/mapbox/android/core/location/LocationEngine.html).

## Enhanced location updates

To receive location updates while the trip session is running, you can subscribe to the [`LocationObserver`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavigation-core/com.mapbox.navigation.core.trip.session/-location-observer/). This will allow you to listen for two types of location updates:

-   **Raw location (`onNewRawLocation`)**: Invoked as soon as a new `Location` has been received.
-   **Enhanced location (`onNewLocationMatcherResult`)**: Invoked when a new `Location` is snapped to the route or map matched to the road.

```kotlin
private val locationObserver = object : LocationObserver {

	override fun onNewRawLocation(rawLocation: Location) {
        ...
	}

	override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {
	    ...
	}
}
```

Register the `LocationObserver` interface with [your already-instantiated `MapboxNavigation` object](https://docs.mapbox.com/android/navigation/v2/guides/get-started/initialization/).

```kotlin
mapboxNavigation.registerLocationObserver(locationObserver)
```

Don't forget to unregister the `LocationObserver` interface.

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

### `onNewRawLocation` callback

The [`onNewRawLocation`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavigation-core/com.mapbox.navigation.core.trip.session/-location-observer/on-new-raw-location.html) method delivers a raw `Location` object from the developer-provided or default internal `LocationEngine`.

### `onNewLocationMatcherResult` callback

The [`onNewLocationMatcherResult`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavigation-core/com.mapbox.navigation.core.trip.session/-location-observer/on-new-location-matcher-result.html) method provides the most accurate location update possible. The location is snapped to the route, or if possible, to the road network.

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.

`locationMatcherResult` provides details about the status of the enhanced location. `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 the `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.

## Location puck on the map

If your application includes a map, you can display the user location puck on the map using the [Mapbox Maps SDK's user location component](https://docs.mapbox.com/android/maps/guides/old-versions/migrate-to-v10/#location-component-plugin-with-puck-and-camera-decoupled). The plugin can display both a 2D and 3D puck.

![](https://docs.mapbox.com/android/assets/ideal-img/navigation-overview-device-location-user-location.6a090d3.480.png)

> **Note: Mapbox Maps SDK**
> 
> For more details on how to work with the Maps SDK, [see the `Maps SDK` documentation](https://docs.mapbox.com/android/maps/guides/).

After you've added a [`MapView`](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.maps/-map-view/) to your application, create the [`NavigationLocationProvider`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.location/-navigation-location-provider/) utility class, which helps manage connecting the Navigation SDK and the Maps SDK to display the user location puck:

```kotlin
val navigationLocationProvider = NavigationLocationProvider()
```

Then, activate the Maps SDK's user location component, set the puck drawable (included with the Navigation SDK), and set the location data provider:

```kotlin
mapView.location.apply {
    this.locationPuck = LocationPuck2D(
        bearingImage = ContextCompat.getDrawable(
            this@MainActivity,
            R.drawable.mapbox_navigation_puck_icon
        )
    )
    setLocationProvider(navigationLocationProvider)
    enabled = true
}
```

Once the puck is initialized, you can start passing the enhanced location updates to the puck and render the updated location on the map:

```kotlin
private val locationObserver = object : LocationObserver {

    override fun onNewRawLocation(rawLocation: Location) {
        ...
    }

    override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {
        val transitionOptions: (ValueAnimator.() -> Unit) =
            {
                duration = 1000
            }
        navigationLocationProvider.changePosition(
            location = locationMatcherResult.enhancedLocation,
            keyPoints = locationMatcherResult.keyPoints,
            latLngTransitionOptions = transitionOptions,
            bearingTransitionOptions = transitionOptions
        )
    }
}
```

> **Related content (example): [Render current location on a map](https://docs.mapbox.com/android/navigation/v2/examples/show-current-location/)**
> 
> Use `NavigationLocationProvider` to show a device's current location as a puck on a map.

> **Note: Synchronize with the camera**
> 
> For linear updates once the SDK sets the camera to a following state, keep the animation duration between the puck animation and the camera animation equal so they stay in sync.By default, the [`NavigationCamera`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavui-maps/com.mapbox.navigation.ui.maps.camera/-navigation-camera/) uses a duration of 1 second. To keep the puck in sync, use 1 second for the puck `transitionOptions` as well.

## Custom location engine

By default, the Navigation SDK uses a [`LocationEngine`](https://docs.mapbox.com/android/telemetry/api/libcore/3.1.0/com/mapbox/android/core/location/LocationEngine.html) that comes from `LocationEngineProvider.getBestLocationEngine(context)`, but you can override this default. This allows you to provide locations from automobiles, scooters, simulations, games, or your own version of Android's location provider.

> **Note: Custom location updates have a monotontic-time requirement**
> 
> The [`Location`](https://developer.android.com/reference/android/location/Location)s provided by the `LocationEngine` must override `getElapsedRealtimeNanos()` with [`SystemClock.elapsedRealtimeNanos`](https://developer.android.com/reference/android/os/SystemClock#elapsedRealtimeNanos()). This specific clock improves the location accuracy.

You can pass the `LocationEngine` with the [`NavigationOptions`](https://docs.mapbox.com/android/navigation/v2/api/2.22.2/libnavigation-base/com.mapbox.navigation.base.options/-navigation-options/):

```kotlin
val navigationOptions = NavigationOptions.Builder(context)
    .accessToken("{your_access_token}")
    .locationEngine(customLocationEngine)
    .build()
val mapboxNavigation = MapboxNavigationApp.setup(navigationOptions)
```

### Location engine request

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

First, create a [`LocationEngineRequest`](https://docs.mapbox.com/android/telemetry/api/libcore/3.1.0/com/mapbox/android/core/location/LocationEngineRequest.html) to specify parameters such as the querying frequency or preferred accuracy:

```kotlin
val customLocationEngineRequest = 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()

val navigationOptions = NavigationOptions.Builder(context)
    .accessToken("{your_access_token}")
    .locationEngine(customLocationEngine)
    .locationEngineRequest(customLocationEngineRequest)
    .build()
val mapboxNavigation = MapboxNavigationApp.setup(navigationOptions)
```

## Raw location updates when the trip session is stopped

If you still want to receive location updates when the trip session is stopped, create a custom class that implements the [`LocationEngineCallback`](https://docs.mapbox.com/android/telemetry/api/libcore/3.1.0/?com/mapbox/android/core/location/LocationEngineCallback.html) interface. This interface comes from [Mapbox's Core library for Android](https://docs.mapbox.com/android/core/):

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

    private val activityRef = WeakReference(activity)

    override fun onSuccess(result: LocationEngineResult?) {
        // for example, push a location update to the Map Location Plugin and the NavigationLocationProvider here 
    }

    override fun onFailure(exception: Exception) {

    }
}
```

Create an instance of the custom callback class:

```kotlin
val customLocationEngineCallback = CustomLocationEngineCallback(activity)
```

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

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

> **Note: Obtain a location engine instance**
> 
> To create a location engine instance you can implement the `LocationEngine` interface.`kotlinval locationEngine = LocationEngineProvider.getBestLocationEngine(context)`

Make sure to remove location updating:

```kotlin
override fun onStop() {
    super.onStop()
    locationEngine.removeLocationUpdates(locationListenerCallback)
}
```