# Device location

> **Note (legacy): A newer version of the Navigation SDK is available**
> 
> This page uses v1.6.2 of the Mapbox Navigation SDK. A newer version of the SDK is available. Learn about the latest version, v2.22.2, in the [Navigation SDK documentation](https://docs.mapbox.com/android/navigation/v2/guides/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`.

> **Note: More on LocationEngine**
> 
> For more details on how `LocationEngine` works, [see the `LocationEngine` documentation](https://docs.mapbox.com/android/core/guides/#locationengine).

## 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.

```kotlin
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](https://docs.mapbox.com/android/legacy/navigation/guides/install/#create-a-mapboxnavigation-object).

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

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

```kotlin
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`](https://docs.mapbox.com/android/legacy/maps/guides/location-component/) and [customizing its look with its styling options](https://docs.mapbox.com/android/legacy/maps/guides/location-component/#active-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](https://docs.mapbox.com/android/maps/guides/) `LocationComponent`. Read more about the [Maps SDK's `LocationComponent`](https://docs.mapbox.com/android/legacy/maps/guides/location-component/) and [customizing its look with its styling options](https://docs.mapbox.com/android/legacy/maps/guides/location-component/#active-styling-options).

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

When using the `LocationComponent` in combination with the Navigation SDK's `LocationObserver` interface ([described above](#observe-location-changes)), 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`:

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

```kotlin
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)
	    }
	}
}
```

> **Related content (example): [Basic Navigation + Maps SDK integration](https://docs.mapbox.com/android/legacy/navigation/examples/basic-nav-sdk-only/)**
> 
> See how to combine the Navigation SDK with the Maps SDK's `LocationComponent`

## `LocationEngine` customization

The default `LocationEngine` is provided by `LocationEngineProvider.getBestLocationEngine(context)`. Yet, `LocationEngine` is an interface that can be overridden. This allows you to provide locations from automobiles, scooters, simulations, games, or your own version of Android's location provider.

> **Note: Custom Locations 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.

**Custom `LocationEngine` with the [Navigation UI SDK](https://docs.mapbox.com/android/legacy/navigation/guides/install#display-a-navigation-ui)**

You can pass the `LocationEngine` with the `NavigationViewOptions`:

```kotlin
navigationView.startNavigation(NavigationViewOptions.builder(context)
    .locationEngine(customLocationEngine)
    .build())
```

**Custom `LocationEngine` with the [Navigation Core SDK](https://docs.mapbox.com/android/legacy/navigation/guides/install/#create-a-mapboxnavigation-object)**

You can pass the `LocationEngine` with the `NavigationOptions`:

```kotlin
val mapboxNavigation = MapboxNavigationProvider.create(MapboxNavigation
    .defaultNavigationOptionsBuilder(context, accessToken)
    .locationEngine(customLocationEngine)
    .build())
```

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

```kotlin
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](https://docs.mapbox.com/android/core/guides/#requesting-location-updates):

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

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

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

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

```kotlin
override fun onStop() {
    super.onStop()

    mapboxNavigation?.locationEngine?.removeLocationUpdates(locationListenerCallback)
}
```