Skip to main content

Location component

Shows location puck on the map.
LocationComponentActivity.kt
package com.mapbox.maps.testapp.examples

import android.graphics.Color
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.ImageHolder
import com.mapbox.maps.MapboxExperimental
import com.mapbox.maps.Style
import com.mapbox.maps.extension.style.expressions.dsl.generated.interpolate
import com.mapbox.maps.extension.style.layers.properties.generated.Anchor
import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionName
import com.mapbox.maps.extension.style.light.generated.flatLight
import com.mapbox.maps.extension.style.light.setLight
import com.mapbox.maps.extension.style.projection.generated.getProjection
import com.mapbox.maps.extension.style.projection.generated.projection
import com.mapbox.maps.extension.style.projection.generated.setProjection
import com.mapbox.maps.plugin.LocationPuck2D
import com.mapbox.maps.plugin.LocationPuck3D
import com.mapbox.maps.plugin.PuckBearing
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.maps.plugin.locationcomponent.DefaultLocationProvider
import com.mapbox.maps.plugin.locationcomponent.OnIndicatorPositionChangedListener
import com.mapbox.maps.plugin.locationcomponent.createDefault2DPuck
import com.mapbox.maps.plugin.locationcomponent.location
import com.mapbox.maps.testapp.R
import com.mapbox.maps.testapp.databinding.ActivityLocationComponentBinding
import com.mapbox.maps.testapp.utils.LocationPermissionHelper
import java.lang.ref.WeakReference

@OptIn(MapboxExperimental::class)
class LocationComponentActivity : AppCompatActivity() {

private var lastStyleUri = Style.DARK
private lateinit var locationPermissionHelper: LocationPermissionHelper
private val onIndicatorPositionChangedListener = OnIndicatorPositionChangedListener {
// Jump to the current indicator position
binding.mapView.mapboxMap.setCamera(CameraOptions.Builder().center(it).build())
// Set the gestures plugin's focal point to the current indicator location.
binding.mapView.gestures.focalPoint = binding.mapView.mapboxMap.pixelForCoordinate(it)
}
private lateinit var binding: ActivityLocationComponentBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLocationComponentBinding.inflate(layoutInflater)
setContentView(binding.root)
locationPermissionHelper = LocationPermissionHelper(WeakReference(this))
locationPermissionHelper.checkPermissions {
binding.mapView.apply {
mapboxMap.loadStyle(Style.STANDARD) {
it.setLight(
flatLight {
anchor(Anchor.MAP)
color(Color.YELLOW)
position(
radialCoordinate = 10.0,
azimuthalAngle = 40.0,
polarAngle = 50.0
)
}
)
// Disable scroll gesture, since we are updating the camera position based on the indicator location.
gestures.scrollEnabled = false
gestures.addOnMapClickListener { point ->
location
.isLocatedAt(point) { isPuckLocatedAtPoint ->
if (isPuckLocatedAtPoint) {
Toast.makeText(context, "Clicked on location puck", Toast.LENGTH_SHORT).show()
}
}
true
}
gestures.addOnMapLongClickListener { point ->
location.isLocatedAt(point) { isPuckLocatedAtPoint ->
if (isPuckLocatedAtPoint) {
Toast.makeText(context, "Long-clicked on location puck", Toast.LENGTH_SHORT)
.show()
}
}
true
}
val locationProvider = location.getLocationProvider() as DefaultLocationProvider
locationProvider.addOnCompassCalibrationListener {
Toast.makeText(context, "Compass needs to be calibrated", Toast.LENGTH_LONG).show()
}
}
}
}
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_location_component, menu)
return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_customise_location_puck_change -> {
toggleCustomisedPuck()
return true
}
R.id.action_map_style_change -> {
toggleMapStyle()
return true
}
R.id.action_map_projection_change -> {
toggleMapProjection()
return true
}
R.id.action_component_disable -> {
binding.mapView.location.enabled = false
return true
}
R.id.action_component_enabled -> {
binding.mapView.location.enabled = true
return true
}
R.id.action_show_bearing -> {
binding.mapView.location.puckBearingEnabled = true
if (binding.mapView.location.locationPuck is LocationPuck2D) {
binding.mapView.location.locationPuck = createDefault2DPuck(withBearing = true)
}
return true
}
R.id.action_hide_bearing -> {
binding.mapView.location.puckBearingEnabled = false
if (binding.mapView.location.locationPuck is LocationPuck2D) {
binding.mapView.location.locationPuck = createDefault2DPuck(withBearing = false)
}
return true
}
R.id.heading -> {
binding.mapView.location.puckBearing = PuckBearing.HEADING
item.isChecked = true
return true
}
R.id.course -> {
binding.mapView.location.puckBearing = PuckBearing.COURSE
item.isChecked = true
return true
}
R.id.location_no_animation -> {
(binding.mapView.location.getLocationProvider() as DefaultLocationProvider).locationAnimatorOptions {
duration = 0
}
item.isChecked = true
return true
}
R.id.location_1s_animation -> {
(binding.mapView.location.getLocationProvider() as DefaultLocationProvider).locationAnimatorOptions {
duration = 1000
}
item.isChecked = true
return true
}
R.id.location_300ms_animation -> {
(binding.mapView.location.getLocationProvider() as DefaultLocationProvider).locationAnimatorOptions {
duration = 300
}
item.isChecked = true
return true
}
R.id.action_accuracy_enabled -> {
binding.mapView.location.showAccuracyRing = true
item.isChecked = true
return true
}
R.id.action_accuracy_disable -> {
binding.mapView.location.showAccuracyRing = false
item.isChecked = true
return true
}
R.id.toggle_opacity -> {
val location = binding.mapView.location
location.locationPuck = location.locationPuck.run {
when (this) {
is LocationPuck3D -> copy(modelOpacity = if (modelOpacity == 1.0F) 0.5F else 1.0F)
is LocationPuck2D -> copy(opacity = if (opacity == 1.0F) 0.5F else 1.0F)
}
}
return true
}
R.id.move_to_bottom_slot -> {
val location = binding.mapView.location
location.slot = "bottom"
return true
}

R.id.reset_slot -> {
val location = binding.mapView.location
location.slot = null
return true
}

else -> return super.onOptionsItemSelected(item)
}
}

private fun toggleCustomisedPuck() {
binding.mapView.location.let {
when (it.locationPuck) {
is LocationPuck3D -> it.locationPuck = LocationPuck2D(
topImage = ImageHolder.from(com.mapbox.maps.plugin.locationcomponent.R.drawable.mapbox_user_icon),
bearingImage = ImageHolder.from(com.mapbox.maps.plugin.locationcomponent.R.drawable.mapbox_user_bearing_icon),
shadowImage = ImageHolder.from(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()
)
is LocationPuck2D -> it.locationPuck = LocationPuck3D(
modelUri = "asset://sportcar.glb",
modelScale = listOf(10f, 10f, 10f),
modelTranslation = listOf(0.1f, 0.1f, 0.1f),
modelRotation = listOf(0.0f, 0.0f, 180.0f),
modelCastShadows = false,
modelReceiveShadows = false,
modelEmissiveStrength = 1.1f
)
}
}
}

private fun toggleMapStyle() {
val styleUrl = if (lastStyleUri == Style.DARK) Style.LIGHT else Style.DARK
binding.mapView.mapboxMap.loadStyle(styleUrl) {
lastStyleUri = styleUrl
}
}

private fun toggleMapProjection() {
binding.mapView.mapboxMap.getStyle { style ->
style.setProjection(
projection(
when (style.getProjection()?.name) {
ProjectionName.MERCATOR -> ProjectionName.GLOBE
ProjectionName.GLOBE -> ProjectionName.MERCATOR
else -> ProjectionName.GLOBE
}
)
)
}
}

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
locationPermissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

override fun onStart() {
super.onStart()
binding.mapView.location
.addOnIndicatorPositionChangedListener(onIndicatorPositionChangedListener)
}

override fun onStop() {
super.onStop()
binding.mapView.location
.removeOnIndicatorPositionChangedListener(onIndicatorPositionChangedListener)
}
}
Was this example helpful?