User location
The Mapbox Maps SDK for Android's user location component enables your application to observe and respond to the user's location. It helps you request permission to access a user's location, use a location engine to get location information for the device, and display the user's location on the map visually.
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
class. When using the Mapbox Core Library, you can specify the text used in the permission prompt using onExplanationNeeded
.
Location provider
The LocationProvider
is an interface of Mapbox Maps SDK, to provide location updates to the (LocationComponentPlugin
).
By default, the Maps SDK's location component (LocationComponentPlugin
) utilizes the Mapbox Core Library for Android's LocationEngine
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
By default, the Maps SDK uses the Android GPS and Network Providers to obtain raw location updates. In applications using Android 11, the raw location updates might suffer from precision issues.
The Maps SDK also comes pre-compiled with support for the Google's Fused Location Provider. If your target devices support Google Play Services, add the following Google Play Location Services dependency to your project, and the Maps SDK will use the Google's Fused Location Provider in your application automatically:
implementation("com.google.android.gms:play-services-location:18.0.0")
Use a custom location provider
You can also provide your own LocationProvider
to use with LocationComponentPlugin
. Use thesetLocationProvider(locationProvider: LocationProvider)
API to replace the default implementation.
Location puck
The location component makes use of two dedicated layers in the Maps SDK to display either a 2D device location icon (using layer ID LOCATION_INDICATOR_LAYER
) or a 3D model (using layer ID MODEL_LAYER
). These layers are displayed within the map rather than on top of the map as an Android view. Layers in Mapbox map styles give you precise control over how you show a device's location on the map.
By default, the Maps SDK for Android provides a two dimensional location puck with a blue dot and white circle.
Show the user's location on a map using the default location puck.
Set puck style options
There are several options to customize the appearance of the location puck using LocationComponentSettings
. For example, the pulsing effect is disabled by default, but you can enable this effect by passing true
to the pulseEnabled
property.
mapView.getMapboxMap().loadStyleUri(
Style.MAPBOX_STREETS,
// After the style is loaded, initialize the Location component.
object : Style.OnStyleLoaded {
override fun onStyleLoaded(style: Style) {
mapView.location.updateSettings {
enabled = true
pulsingEnabled = true
}
}
}
)
The LocationComponentPlugin
has several similar properties (for example, pulsingColor
and pulsingMaxRadius
) to customize the pulsing UI.
Use a custom image
You can further customize LocationComponentPlugin
by using custom image drawables to display the user's location on a map. Set custom location puck styles in one of two ways: using XML attributes or programmatically using the LocationPuck
class.
Here's an example using style XML attributes to customize the appearance of the location icon:
<style name="CustomLocationComponent" parent="mapbox_LocationComponent">
<item name="mapbox_locationComponentLocationPuck">"location_puck_2_d"</item>
<item name="mapbox_locationComponentLocationPuckLocationPuck2DTopImage">@drawable/custom_user_icon</item>
<item name="mapbox_locationComponentLocationPuckLocationPuck2DBearingImage">@drawable/custom_user_arrow</item>
<item name="mapbox_locationComponentLocationPuckLocationPuck2DShadowImage">@drawable/custom_user_puck_icon</item>
</style>
Here's an example using the LocationPuck
class to programmatically customize the appearance of the location icon. Create a LocationPuck2D
or LocationPuck3D
object and set it through LocationComponentPlugin#locationPuck
method. The following example also specifies the size of the icon based on the map's zoom level using scaleExpression
.
mapView.location.locationPuck = LocationPuck2D(
topImage = AppCompatResources.getDrawable(
this,
com.mapbox.maps.plugin.locationcomponent.R.drawable.mapbox_user_icon
),
bearingImage = AppCompatResources.getDrawable(
this,
com.mapbox.maps.plugin.locationcomponent.R.drawable.mapbox_user_bearing_icon
),
shadowImage = AppCompatResources.getDrawable(
this,
com.mapbox.maps.plugin.locationcomponent.R.drawable.mapbox_user_stroke_icon
),
scaleExpression = interpolate {
linear()
zoom()
stop {
literal(0.0)
literal(0.6)
}
stop {
literal(20.0)
literal(1.0)
}
}.toJson()
)
Set Puck Bearing Source
The user location can track bearing using the device heading or device course. This option can be set in LocationComponentSettings2
. Interface LocationComponentPlugin2
extends the original LocationComponentPlugin
interface, it is introduced inorder to avoid breaking API changes.
Example
mapView.location2.puckBearingSource = PuckBearingSource.HEADING
mapView.location2.puckBearingSource = PuckBearingSource.COURSE
Location Tracking
To make the camera follow the location puck, you can use ViewportPlugin
, which is available at mapView.viewport
.
ViewportPlugin
is primarily used to track objects on a map, but it can be extended with custom states and transitions as well.
Note: ViewportPlugin
is designated as experimental, which means that while it is considered production-ready, Mapbox reserves the right to make breaking API changes in future minor versions.
Viewport States
ViewportState
produces camera updates based on implementation-specific rules (e.g. tracking a dynamic location data source or showing a static overview of a predefined region).
Two ViewportState
implementations are provided by the SDK, both of which can be instantiated from the ViewportPlugin
:
viewport.makeFollowPuckViewportState(options): FollowPuckViewportState
: This state syncs the map camera with the location puck.viewport.makeOverviewViewportState(options): OverviewViewportState
: This state makes the camera show a user-provided geometry.
In addition to using these built-in implementations, you can also create your own and use them with the ViewportPlugin
.
Viewport Transitions
ViewportTransition
defines how to transition to a target ViewportState
.
Two ViewportTransition
implementations are also provided by the SDK, both of which can be instantiated from the ViewportPlugin
:
viewport.makeDefaultViewportTransition(options): DefaultViewportTransition
: The default viewport transition uses sophisticated animations to move the camera to the target state.viewport.makeImmediateViewportTransition(): ImmediateViewportTransition
: The immediate viewport transition moves the camera to the target state immediately without using animations.
In addition to using these built-in implementations, you can also create your own and use them with the ViewportPlugin
.
Example
val viewportPlugin = mapView.viewport
val followPuckViewportState: FollowPuckViewportState = viewportPlugin.makeFollowPuckViewportState(
FollowPuckViewportStateOptions.Builder()
.bearing(FollowPuckViewportStateBearing.Constant(0.0))
.animationDurationMs(500)
.padding(EdgeInsets(200.0 * resources.displayMetrics.density, 0.0, 0.0, 0.0))
.build()
)
val overviewViewportState: OverviewViewportState = viewportPlugin.makeOverviewViewportState(
OverviewViewportStateOptions.Builder()
.geometry(routePoints)
.padding(EdgeInsets(100.0, 100.0, 100.0, 100.0))
.build()
)
}
val immediateTransition = viewportPlugin.makeImmediateViewportTransition()
// transition from idle (the default status) to the created followPuckViewportState with default transition
viewportPlugin.transitionTo(followPuckViewportState) { success ->
// the transition has been completed with a flag indicating whether the transition succeeded
}
...
// transition from followPuckViewportState to overviewViewportState with immediate transition
viewportPlugin.transitionTo(overviewViewportState, immediateTransition) { success ->
// the transition has been completed with a flag indicating whether the transition succeeded
}