Location Tracking Modes
This example shows how to Switch Location Tracking Modes
-
Location Permissions Handling
-
Switch Location component RenderMode
-
Switch Location Tracking Camera Mode
-
Enable/Disable Location Component
-
Tracking Current Location Automatically when MapReady
- locationComponent.setLocationComponentEnabled(true);
- locationComponent.setRenderMode(RenderMode.COMPASS);
- locationComponent.setCameraMode(CameraMode.TRACKING);
For all code examples, refer to Android Maps SDK Code Examples
activity_location_modes.xml view source
1<?xml version="1.0" encoding="utf-8"?>2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"3xmlns:app="http://schemas.android.com/apk/res-auto"4xmlns:tools="http://schemas.android.com/tools"5android:layout_width="match_parent"6android:layout_height="match_parent">78<ai.nextbillion.maps.core.MapView9android:id="@+id/mapView"10android:layout_width="match_parent"11android:layout_height="match_parent"12android:layout_marginBottom="0dp"13app:layout_constraintBottom_toTopOf="parent"14app:layout_constraintLeft_toLeftOf="parent"15app:layout_constraintRight_toRightOf="parent"16app:layout_constraintTop_toTopOf="parent"17app:nbmap_uiAttribution="false" />1819<View20android:id="@+id/view_protected_gesture_area"21android:layout_width="0dp"22android:layout_height="0dp"23android:alpha="0.5"24android:background="@android:color/holo_red_light"25app:layout_constraintStart_toStartOf="@id/mapView"26app:layout_constraintTop_toTopOf="@id/mapView" />2728<LinearLayout29android:id="@+id/linearLayout"30style="?android:attr/buttonBarStyle"31android:layout_width="0dp"32android:layout_height="wrap_content"33android:background="@color/palette_mint_100"34android:orientation="horizontal"35android:weightSum="4"36app:layout_constraintBottom_toBottomOf="parent"37app:layout_constraintLeft_toLeftOf="parent"38app:layout_constraintRight_toRightOf="parent"39tools:layout_constraintBottom_creator="1"40tools:layout_constraintLeft_creator="1"41tools:layout_constraintRight_creator="1">4243<TextView44android:id="@+id/tv_mode"45android:layout_width="0dp"46android:layout_height="match_parent"47android:layout_weight=".75"48android:gravity="center"49android:text="Mode:"50android:textColor="@color/white"51android:textSize="18sp"52android:textStyle="bold" />5354<Button55android:id="@+id/button_location_mode"56style="?android:attr/buttonBarButtonStyle"57android:layout_width="0dp"58android:layout_height="wrap_content"59android:layout_weight="1.25"60android:gravity="center"61android:text="Normal"62android:textColor="@android:color/white" />6364<TextView65android:id="@+id/tv_tracking"66android:layout_width="0dp"67android:layout_height="match_parent"68android:layout_weight=".85"69android:gravity="center"70android:text="Tracking:"71android:textColor="@color/white"72android:textSize="18sp"73android:textStyle="bold" />7475<Button76android:id="@+id/button_location_tracking"77style="?android:attr/buttonBarButtonStyle"78android:layout_width="0dp"79android:layout_height="wrap_content"80android:layout_weight="1.15"81android:gravity="center"82android:text="None"83android:textColor="@android:color/white" />8485</LinearLayout>8687</androidx.constraintlayout.widget.ConstraintLayout>
LocationModesActivity view source
1package ai.nextbillion;23import android.annotation.SuppressLint;4import android.graphics.RectF;5import android.location.Location;6import android.os.Bundle;7import android.view.Menu;8import android.view.MenuItem;9import android.view.View;10import android.widget.ArrayAdapter;11import android.widget.Button;12import android.widget.Toast;1314import java.util.ArrayList;15import java.util.List;1617import ai.nextbillion.maps.camera.CameraUpdateFactory;18import ai.nextbillion.maps.core.MapView;19import ai.nextbillion.maps.core.NextbillionMap;20import ai.nextbillion.maps.core.OnMapReadyCallback;21import ai.nextbillion.maps.location.LocationComponent;22import ai.nextbillion.maps.location.LocationComponentActivationOptions;23import ai.nextbillion.maps.location.LocationComponentOptions;24import ai.nextbillion.maps.location.OnCameraTrackingChangedListener;25import ai.nextbillion.maps.location.OnLocationCameraTransitionListener;26import ai.nextbillion.maps.location.OnLocationClickListener;27import ai.nextbillion.maps.location.engine.LocationEngineRequest;28import ai.nextbillion.maps.location.modes.CameraMode;29import ai.nextbillion.maps.location.modes.RenderMode;30import ai.nextbillion.maps.location.permissions.PermissionsListener;31import ai.nextbillion.maps.location.permissions.PermissionsManager;32import androidx.annotation.NonNull;33import androidx.appcompat.app.AppCompatActivity;34import androidx.appcompat.widget.ListPopupWindow;3536public class LocationModesActivity extends AppCompatActivity implements OnMapReadyCallback,37OnLocationClickListener, OnCameraTrackingChangedListener {3839private MapView mapView;40private Button locationModeBtn;41private Button locationTrackingBtn;42private View protectedGestureArea;4344private PermissionsManager permissionsManager;4546private LocationComponent locationComponent;47private NextbillionMap nextbillionMap;48private boolean defaultStyle = false;4950private static final String SAVED_STATE_CAMERA = "saved_state_camera";51private static final String SAVED_STATE_RENDER = "saved_state_render";52private static final String SAVED_STATE_LOCATION = "saved_state_location";5354@CameraMode.Mode55private int cameraMode = CameraMode.TRACKING;5657@RenderMode.Mode58private int renderMode = RenderMode.NORMAL;5960private Location lastLocation;6162@Override63protected void onCreate(Bundle savedInstanceState) {64super.onCreate(savedInstanceState);65setContentView(R.layout.activity_location_modes);6667mapView = findViewById(R.id.mapView);68protectedGestureArea = findViewById(R.id.view_protected_gesture_area);6970locationModeBtn = findViewById(R.id.button_location_mode);71locationModeBtn.setOnClickListener(v -> {72if (locationComponent == null) {73return;74}75showModeListDialog();76});7778locationTrackingBtn = findViewById(R.id.button_location_tracking);79locationTrackingBtn.setOnClickListener(v -> {80if (locationComponent == null) {81return;82}83showTrackingListDialog();84});858687if (savedInstanceState != null) {88cameraMode = savedInstanceState.getInt(SAVED_STATE_CAMERA);89renderMode = savedInstanceState.getInt(SAVED_STATE_RENDER);90lastLocation = savedInstanceState.getParcelable(SAVED_STATE_LOCATION);91}9293mapView.onCreate(savedInstanceState);9495if (PermissionsManager.areLocationPermissionsGranted(this)) {96mapView.getMapAsync(this);97} else {98permissionsManager = new PermissionsManager(new PermissionsListener() {99@Override100public void onExplanationNeeded(List<String> permissionsToExplain) {101Toast.makeText(LocationModesActivity.this, "You need to accept location permissions.",102Toast.LENGTH_SHORT).show();103}104105@Override106public void onPermissionResult(boolean granted) {107if (granted) {108mapView.getMapAsync(LocationModesActivity.this);109} else {110finish();111}112}113});114permissionsManager.requestLocationPermissions(this);115}116}117118@Override119public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {120super.onRequestPermissionsResult(requestCode, permissions, grantResults);121permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);122}123124@SuppressLint("MissingPermission")125@Override126public void onMapReady(@NonNull NextbillionMap nextbillionMap) {127this.nextbillionMap = nextbillionMap;128nextbillionMap.animateCamera(CameraUpdateFactory.zoomBy(13));129nextbillionMap.setStyle(StyleConstants.NBMAP_STREETS, style -> {130locationComponent = nextbillionMap.getLocationComponent();131locationComponent.activateLocationComponent(132LocationComponentActivationOptions133.builder(this, style)134.useSpecializedLocationLayer(true)135.useDefaultLocationEngine(true)136.locationEngineRequest(new LocationEngineRequest.Builder(750)137.setFastestInterval(750)138.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)139.build())140.build());141142locationComponent.setLocationComponentEnabled(true);143locationComponent.addOnLocationClickListener(this);144locationComponent.addOnCameraTrackingChangedListener(this);145locationComponent.setCameraMode(cameraMode);146setRendererMode(renderMode);147locationComponent.forceLocationUpdate(lastLocation);148});149}150151@Override152public boolean onCreateOptionsMenu(Menu menu) {153getMenuInflater().inflate(R.menu.menu_location_mode, menu);154return true;155}156157@SuppressLint("MissingPermission")158@Override159public boolean onOptionsItemSelected(MenuItem item) {160if (locationComponent == null) {161return super.onOptionsItemSelected(item);162}163164int id = item.getItemId();165if (id == R.id.action_component_disable) {166locationComponent.setLocationComponentEnabled(false);167return true;168} else if (id == R.id.action_component_enabled) {169locationComponent.setLocationComponentEnabled(true);170return true;171} else if (id == R.id.action_gestures_management_disabled) {172disableGesturesManagement();173return true;174} else if (id == R.id.action_gestures_management_enabled) {175enableGesturesManagement();176return true;177} else if (id == R.id.action_component_throttling_enabled) {178locationComponent.setMaxAnimationFps(5);179} else if (id == R.id.action_component_throttling_disabled) {180locationComponent.setMaxAnimationFps(Integer.MAX_VALUE);181} else if (id == R.id.action_component_animate_while_tracking) {182locationComponent.zoomWhileTracking(17, 750, new NextbillionMap.CancelableCallback() {183@Override184public void onCancel() {185// No impl186}187188@Override189public void onFinish() {190locationComponent.tiltWhileTracking(60);191}192});193if (locationComponent.getCameraMode() == CameraMode.NONE) {194195Toast.makeText(this, "Not possible to animate - not tracking", Toast.LENGTH_SHORT).show();196}197}198199return super.onOptionsItemSelected(item);200}201202private void disableGesturesManagement() {203if (locationComponent == null) {204return;205}206207protectedGestureArea.getLayoutParams().height = 0;208protectedGestureArea.getLayoutParams().width = 0;209210LocationComponentOptions options = locationComponent211.getLocationComponentOptions()212.toBuilder()213.trackingGesturesManagement(false)214.build();215locationComponent.applyStyle(options);216}217218private void enableGesturesManagement() {219if (locationComponent == null) {220return;221}222223RectF rectF = new RectF(0f, 0f, mapView.getWidth() / 2f, mapView.getHeight() / 2f);224protectedGestureArea.getLayoutParams().height = (int) rectF.bottom;225protectedGestureArea.getLayoutParams().width = (int) rectF.right;226227LocationComponentOptions options = locationComponent228.getLocationComponentOptions()229.toBuilder()230.trackingGesturesManagement(true)231.trackingMultiFingerProtectedMoveArea(rectF)232.trackingMultiFingerMoveThreshold(500)233.build();234locationComponent.applyStyle(options);235}236237@Override238protected void onStart() {239super.onStart();240mapView.onStart();241}242243@Override244protected void onResume() {245super.onResume();246mapView.onResume();247}248249@Override250protected void onPause() {251super.onPause();252mapView.onPause();253}254255@Override256protected void onStop() {257super.onStop();258mapView.onStop();259}260261@SuppressLint("MissingPermission")262@Override263protected void onSaveInstanceState(Bundle outState) {264super.onSaveInstanceState(outState);265mapView.onSaveInstanceState(outState);266outState.putInt(SAVED_STATE_CAMERA, cameraMode);267outState.putInt(SAVED_STATE_RENDER, renderMode);268if (locationComponent != null) {269outState.putParcelable(SAVED_STATE_LOCATION, locationComponent.getLastKnownLocation());270}271}272273@Override274protected void onDestroy() {275super.onDestroy();276mapView.onDestroy();277}278279@Override280public void onLowMemory() {281super.onLowMemory();282mapView.onLowMemory();283}284285@Override286public void onLocationComponentClick() {287Toast.makeText(this, "OnLocationComponentClick", Toast.LENGTH_LONG).show();288}289290private void showModeListDialog() {291List<String> modes = new ArrayList<>();292modes.add("Normal");293modes.add("Compass");294modes.add("GPS");295ArrayAdapter<String> profileAdapter = new ArrayAdapter<>(this,296android.R.layout.simple_list_item_1, modes);297ListPopupWindow listPopup = new ListPopupWindow(this);298listPopup.setAdapter(profileAdapter);299listPopup.setAnchorView(locationModeBtn);300listPopup.setOnItemClickListener((parent, itemView, position, id) -> {301String selectedMode = modes.get(position);302locationModeBtn.setText(selectedMode);303if (selectedMode.contentEquals("Normal")) {304setRendererMode(RenderMode.NORMAL);305} else if (selectedMode.contentEquals("Compass")) {306setRendererMode(RenderMode.COMPASS);307} else if (selectedMode.contentEquals("GPS")) {308setRendererMode(RenderMode.GPS);309}310listPopup.dismiss();311});312listPopup.show();313}314315private void setRendererMode(@RenderMode.Mode int mode) {316renderMode = mode;317locationComponent.setRenderMode(mode);318if (mode == RenderMode.NORMAL) {319locationModeBtn.setText("Normal");320} else if (mode == RenderMode.COMPASS) {321locationModeBtn.setText("Compass");322} else if (mode == RenderMode.GPS) {323locationModeBtn.setText("Gps");324}325}326327private void showTrackingListDialog() {328List<String> trackingTypes = new ArrayList<>();329trackingTypes.add("None");330trackingTypes.add("None Compass");331trackingTypes.add("None GPS");332trackingTypes.add("Tracking");333trackingTypes.add("Tracking Compass");334trackingTypes.add("Tracking GPS");335trackingTypes.add("Tracking GPS North");336ArrayAdapter<String> profileAdapter = new ArrayAdapter<>(this,337android.R.layout.simple_list_item_1, trackingTypes);338ListPopupWindow listPopup = new ListPopupWindow(this);339listPopup.setAdapter(profileAdapter);340listPopup.setAnchorView(locationTrackingBtn);341listPopup.setOnItemClickListener((parent, itemView, position, id) -> {342String selectedTrackingType = trackingTypes.get(position);343locationTrackingBtn.setText(selectedTrackingType);344if (selectedTrackingType.contentEquals("None")) {345setCameraTrackingMode(CameraMode.NONE);346} else if (selectedTrackingType.contentEquals("None Compass")) {347setCameraTrackingMode(CameraMode.NONE_COMPASS);348} else if (selectedTrackingType.contentEquals("None GPS")) {349setCameraTrackingMode(CameraMode.NONE_GPS);350} else if (selectedTrackingType.contentEquals("Tracking")) {351setCameraTrackingMode(CameraMode.TRACKING);352} else if (selectedTrackingType.contentEquals("Tracking Compass")) {353setCameraTrackingMode(CameraMode.TRACKING_COMPASS);354} else if (selectedTrackingType.contentEquals("Tracking GPS")) {355setCameraTrackingMode(CameraMode.TRACKING_GPS);356} else if (selectedTrackingType.contentEquals("Tracking GPS North")) {357setCameraTrackingMode(CameraMode.TRACKING_GPS_NORTH);358}359listPopup.dismiss();360});361listPopup.show();362}363364private void setCameraTrackingMode(@CameraMode.Mode int mode) {365locationComponent.setCameraMode(mode, 1200, 16.0, null, 45.0,366new OnLocationCameraTransitionListener() {367@Override368public void onLocationCameraTransitionFinished(@CameraMode.Mode int cameraMode) {369Toast.makeText(LocationModesActivity.this, "Transition finished", Toast.LENGTH_SHORT).show();370}371372@Override373public void onLocationCameraTransitionCanceled(@CameraMode.Mode int cameraMode) {374Toast.makeText(LocationModesActivity.this, "Transition canceled", Toast.LENGTH_SHORT).show();375}376});377}378379@Override380public void onCameraTrackingDismissed() {381locationTrackingBtn.setText("None");382}383384@Override385public void onCameraTrackingChanged(int currentMode) {386this.cameraMode = currentMode;387if (currentMode == CameraMode.NONE) {388locationTrackingBtn.setText("None");389} else if (currentMode == CameraMode.NONE_COMPASS) {390locationTrackingBtn.setText("None Compass");391} else if (currentMode == CameraMode.NONE_GPS) {392locationTrackingBtn.setText("None GPS");393} else if (currentMode == CameraMode.TRACKING) {394locationTrackingBtn.setText("Tracking");395} else if (currentMode == CameraMode.TRACKING_COMPASS) {396locationTrackingBtn.setText("Tracking Compass");397} else if (currentMode == CameraMode.TRACKING_GPS) {398locationTrackingBtn.setText("Tracking GPS");399} else if (currentMode == CameraMode.TRACKING_GPS_NORTH) {400locationTrackingBtn.setText("Tracking GPS North");401}402}403}
Summary: The given code is an Android activity that demonstrates various location modes and features using the NextbillionMap library. It initializes a map view, handles location permissions, tracks the current location, switches between location component render modes and tracking camera modes and enables or disables the location component.
initMapView:
- The map view is initialized in the onCreate method by finding the view with the ID R.id.mapView. This method sets up the map view and initializes other UI elements and variables.
Location Permissions Handling:
- The code checks if location permissions are granted using PermissionsManager.areLocationPermissionsGranted(this). If permissions are granted, the map is asynchronously loaded using mapView.getMapAsync(this). If permissions are not granted, a PermissionsManager is created and used to request location permissions. The result of the permission request is handled in the onPermissionResult method.
Tracking Current Location Automatically when MapReady:
- When the map is ready (onMapReady), the NextbillionMap instance is obtained. The map's style is set, and the location component is activated with various options, including a specialized location layer, default location engine, and location update interval. The location component is enabled and configured with listeners for location clicks and camera tracking changes. The last known location is also updated.
Switch Location component RenderMode:
- The render mode can be switched using the showModeListDialog method, which displays a dialog with options for Normal, Compass, and GPS render modes. The selected mode is applied to the location component using setRendererMode().
Switch Location Tracking CameraMode:
- The camera tracking mode can be switched using the showTrackingListDialog method, which displays a dialog with options for different camera tracking modes. The selected mode is applied to the location component using setCameraTrackingMode().
Enable/Disable Location Component:
- The location component can be enabled or disabled by clicking on the corresponding menu items in the options menu. The status of the location component is updated accordingly using setLocationComponentEnabled.
The code also includes various lifecycle methods for managing the map view, saving and restoring the state of the activity, and handling user interactions with the location component, such as clicking and dismissing camera tracking.
Overall, the code demonstrates how to use the NextbillionMap library to implement location-based features in an Android application, including handling permissions, tracking the user's location, and customizing the render and camera tracking modes of the location component.