summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java1618
1 files changed, 0 insertions, 1618 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
deleted file mode 100644
index 8b014b0e9c..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
+++ /dev/null
@@ -1,1618 +0,0 @@
-package com.mapbox.mapboxsdk.location;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.hardware.SensorManager;
-import android.location.Location;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresPermission;
-import android.support.annotation.StyleRes;
-import android.support.annotation.VisibleForTesting;
-import android.view.WindowManager;
-
-import com.mapbox.android.core.location.LocationEngine;
-import com.mapbox.android.core.location.LocationEngineCallback;
-import com.mapbox.android.core.location.LocationEngineProvider;
-import com.mapbox.android.core.location.LocationEngineRequest;
-import com.mapbox.android.core.location.LocationEngineResult;
-import com.mapbox.android.core.permissions.PermissionsManager;
-import com.mapbox.mapboxsdk.R;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdate;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.location.modes.CameraMode;
-import com.mapbox.mapboxsdk.location.modes.RenderMode;
-import com.mapbox.mapboxsdk.log.Logger;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
-import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
-import com.mapbox.mapboxsdk.maps.MapboxMap.OnMapClickListener;
-import com.mapbox.mapboxsdk.maps.Style;
-import com.mapbox.mapboxsdk.maps.Transform;
-
-import java.lang.ref.WeakReference;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
-import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_FASTEST_INTERVAL_MILLIS;
-import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_INTERVAL_MILLIS;
-import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION;
-import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION;
-import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS;
-
-/**
- * The Location Component provides location awareness to your mobile application. Enabling this
- * component provides a contextual experience to your users by showing an icon representing the users
- * current location. A few different modes are offered to provide the right context to your users at
- * the correct time. {@link RenderMode#NORMAL} simply shows the users location on the map
- * represented as a dot. {@link RenderMode#COMPASS} mode allows you to display an arrow icon
- * (by default) that points in the direction the device is pointing in.
- * {@link RenderMode#GPS} can be used in conjunction with our Navigation SDK to
- * display a larger icon (customized with {@link LocationComponentOptions#gpsDrawable()}) we call the user puck.
- * <p>
- * This component also offers the ability to set a map camera behavior for tracking the user
- * location. These different {@link CameraMode}s will track, stop tracking the location based on the
- * mode set with {@link LocationComponent#setCameraMode(int)}.
- * <p>
- * <strong>
- * To get the component object use {@link MapboxMap#getLocationComponent()} and activate it with
- * {@link #activateLocationComponent(Context, Style)} or one of the overloads.
- * Then, manage its visibility with {@link #setLocationComponentEnabled(boolean)}.
- * The component will not process location updates right after activation, but only after being enabled.
- * </strong>
- * <p>
- * Using this component requires you to request permission beforehand manually or using
- * {@link PermissionsManager}. Either
- * {@code ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permissions can be requested for
- * this component to work as expected.
- * <p>
- * This component offers a default, built-in {@link LocationEngine} with some of the activation methods.
- * This engine will be obtained by {@link LocationEngineProvider#getBestLocationEngine(Context, boolean)} which defaults
- * to the {@link com.mapbox.android.core.location.MapboxFusedLocationEngineImpl}. If you'd like to utilize Google
- * Play Services
- * for more precise location updates, simply add the Google Play Location Services dependency in your build script.
- * This will make the default engine the {@link com.mapbox.android.core.location.GoogleLocationEngineImpl} instead.
- * After a custom engine is passed to the component, or the built-in is initialized,
- * the location updates are going to be requested with the {@link LocationEngineRequest}, either a default one,
- * or the one passed during the activation.
- * When using any engine, requesting/removing the location updates is going to be managed internally.
- * <p>
- * You can also push location updates to the component without any internal engine management.
- * To achieve that, use {@link #activateLocationComponent(Context, Style, boolean)} with false.
- * No engine is going to be initialized and you can push location updates with {@link #forceLocationUpdate(Location)}.
- * <p>
- * For location puck animation purposes, like navigation,
- * we recommend limiting the maximum zoom level of the map for the best user experience.
- * <p>
- * Location Component doesn't support state saving out-of-the-box.
- */
-public final class LocationComponent {
- private static final String TAG = "Mbgl-LocationComponent";
-
- @NonNull
- private final MapboxMap mapboxMap;
- @NonNull
- private final Transform transform;
- private Style style;
- private LocationComponentOptions options;
- @NonNull
- private InternalLocationEngineProvider internalLocationEngineProvider = new InternalLocationEngineProvider();
- @Nullable
- private LocationEngine locationEngine;
- @NonNull
- private LocationEngineRequest locationEngineRequest =
- new LocationEngineRequest.Builder(DEFAULT_INTERVAL_MILLIS)
- .setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS)
- .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
- .build();
- private LocationEngineCallback<LocationEngineResult> currentLocationEngineListener
- = new CurrentLocationEngineCallback(this);
- private LocationEngineCallback<LocationEngineResult> lastLocationEngineListener
- = new LastLocationEngineCallback(this);
-
- @Nullable
- private CompassEngine compassEngine;
-
- private LocationLayerController locationLayerController;
- private LocationCameraController locationCameraController;
-
- private LocationAnimatorCoordinator locationAnimatorCoordinator;
-
- /**
- * Holds last location which is being returned in the {@link #getLastKnownLocation()}
- * when there is no {@link #locationEngine} set or when the last location returned by the engine is null.
- */
- @Nullable
- private Location lastLocation;
- private CameraPosition lastCameraPosition;
-
- /**
- * Indicates whether the component has been initialized.
- */
- private boolean isComponentInitialized;
-
- /**
- * Indicates that the component is enabled and should be displaying location if Mapbox components are available and
- * the lifecycle is in a started state.
- */
- private boolean isEnabled;
-
- /**
- * Indicated that component's lifecycle {@link #onStart()} method has been called.
- * This allows Mapbox components enter started state and display data, and adds state safety for methods like
- * {@link #setLocationComponentEnabled(boolean)}
- */
- private boolean isComponentStarted;
-
- /**
- * Indicates if Mapbox components are ready to be interacted with. This can differ from {@link #isComponentStarted}
- * if the Mapbox style is being reloaded.
- */
- private boolean isLayerReady;
-
- /**
- * Indicates whether we are listening for compass updates.
- */
- private boolean isListeningToCompass;
-
- private StaleStateManager staleStateManager;
- private final CopyOnWriteArrayList<OnLocationStaleListener> onLocationStaleListeners
- = new CopyOnWriteArrayList<>();
- private final CopyOnWriteArrayList<OnLocationClickListener> onLocationClickListeners
- = new CopyOnWriteArrayList<>();
- private final CopyOnWriteArrayList<OnLocationLongClickListener> onLocationLongClickListeners
- = new CopyOnWriteArrayList<>();
- private final CopyOnWriteArrayList<OnCameraTrackingChangedListener> onCameraTrackingChangedListeners
- = new CopyOnWriteArrayList<>();
- private final CopyOnWriteArrayList<OnRenderModeChangedListener> onRenderModeChangedListeners
- = new CopyOnWriteArrayList<>();
-
- // Workaround for too frequent updates, see https://github.com/mapbox/mapbox-gl-native/issues/13587
- private long fastestInterval;
- private long lastUpdateTime;
-
- /**
- * Internal use.
- * <p>
- * To get the component object use {@link MapboxMap#getLocationComponent()}.
- */
- public LocationComponent(@NonNull MapboxMap mapboxMap,
- @NonNull Transform transform,
- @NonNull List<MapboxMap.OnDeveloperAnimationListener> developerAnimationListeners) {
- this.mapboxMap = mapboxMap;
- this.transform = transform;
- developerAnimationListeners.add(developerAnimationListener);
- }
-
- // used for creating a spy
- LocationComponent() {
- //noinspection ConstantConditions
- mapboxMap = null;
- transform = null;
- }
-
- @VisibleForTesting
- LocationComponent(@NonNull MapboxMap mapboxMap,
- @NonNull Transform transform,
- @NonNull List<MapboxMap.OnDeveloperAnimationListener> developerAnimationListeners,
- @NonNull LocationEngineCallback<LocationEngineResult> currentListener,
- @NonNull LocationEngineCallback<LocationEngineResult> lastListener,
- @NonNull LocationLayerController locationLayerController,
- @NonNull LocationCameraController locationCameraController,
- @NonNull LocationAnimatorCoordinator locationAnimatorCoordinator,
- @NonNull StaleStateManager staleStateManager,
- @NonNull CompassEngine compassEngine,
- @NonNull InternalLocationEngineProvider internalLocationEngineProvider) {
- this.mapboxMap = mapboxMap;
- this.transform = transform;
- developerAnimationListeners.add(developerAnimationListener);
- this.currentLocationEngineListener = currentListener;
- this.lastLocationEngineListener = lastListener;
- this.locationLayerController = locationLayerController;
- this.locationCameraController = locationCameraController;
- this.locationAnimatorCoordinator = locationAnimatorCoordinator;
- this.staleStateManager = staleStateManager;
- this.compassEngine = compassEngine;
- this.internalLocationEngineProvider = internalLocationEngineProvider;
- isComponentInitialized = true;
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- * <p>
- * <strong>Note</strong>: This method will initialize and use an internal {@link LocationEngine} when enabled.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style) {
- activateLocationComponent(context, style,
- LocationComponentOptions.createFromAttributes(context, R.style.mapbox_LocationComponent));
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param useDefaultLocationEngine true if you want to initialize and use the built-in location engine or false if
- * there should be no location engine initialized
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- boolean useDefaultLocationEngine) {
- if (useDefaultLocationEngine) {
- activateLocationComponent(context, style, R.style.mapbox_LocationComponent);
- } else {
- activateLocationComponent(context, style, null, R.style.mapbox_LocationComponent);
- }
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param useDefaultLocationEngine true if you want to initialize and use the built-in location engine or false if
- * there should be no location engine initialized
- * @param locationEngineRequest the location request
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- boolean useDefaultLocationEngine,
- @NonNull LocationEngineRequest locationEngineRequest) {
- setLocationEngineRequest(locationEngineRequest);
- if (useDefaultLocationEngine) {
- activateLocationComponent(context, style, R.style.mapbox_LocationComponent);
- } else {
- activateLocationComponent(context, style, null, R.style.mapbox_LocationComponent);
- }
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param useDefaultLocationEngine true if you want to initialize and use the built-in location engine or false if
- * there should be no location engine initialized
- * @param locationEngineRequest the location request
- * @param options the options
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- boolean useDefaultLocationEngine,
- @NonNull LocationEngineRequest locationEngineRequest,
- @NonNull LocationComponentOptions options) {
- setLocationEngineRequest(locationEngineRequest);
- if (useDefaultLocationEngine) {
- activateLocationComponent(context, style, options);
- } else {
- activateLocationComponent(context, style, null, options);
- }
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- * <p>
- * <strong>Note</strong>: This method will initialize and use an internal {@link LocationEngine} when enabled.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param styleRes the LocationComponent style res
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @StyleRes int styleRes) {
- activateLocationComponent(context, style, LocationComponentOptions.createFromAttributes(context, styleRes));
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- * <p>
- * <strong>Note</strong>: This method will initialize and use an internal {@link LocationEngine} when enabled.
- * </p>
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param options the options
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- @NonNull LocationComponentOptions options) {
- initialize(context, style, options);
- initializeLocationEngine(context);
- applyStyle(options);
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param locationEngine the engine, or null if you'd like to only force location updates
- * @param styleRes the LocationComponent style res
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- @Nullable LocationEngine locationEngine, @StyleRes int styleRes) {
- activateLocationComponent(context, style, locationEngine,
- LocationComponentOptions.createFromAttributes(context, styleRes));
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param locationEngine the engine, or null if you'd like to only force location updates
- * @param locationEngineRequest the location request
- * @param styleRes the LocationComponent style res
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- @Nullable LocationEngine locationEngine,
- @NonNull LocationEngineRequest locationEngineRequest, @StyleRes int styleRes) {
- activateLocationComponent(context, style, locationEngine, locationEngineRequest,
- LocationComponentOptions.createFromAttributes(context, styleRes));
- }
-
- /**
- * This method will show the location icon and enable the camera tracking the location.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param locationEngine the engine
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- @Nullable LocationEngine locationEngine) {
- activateLocationComponent(context, style, locationEngine, R.style.mapbox_LocationComponent);
- }
-
- /**
- * This method will show the location icon and enable the camera tracking the location.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param locationEngine the engine
- * @param locationEngineRequest the location request
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- @Nullable LocationEngine locationEngine,
- @NonNull LocationEngineRequest locationEngineRequest) {
- activateLocationComponent(context, style, locationEngine, locationEngineRequest, R.style.mapbox_LocationComponent);
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- *
- * @param locationEngine the engine, or null if you'd like to only force location updates
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param options the options
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- @Nullable LocationEngine locationEngine,
- @NonNull LocationComponentOptions options) {
- initialize(context, style, options);
- setLocationEngine(locationEngine);
- applyStyle(options);
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- *
- * @param context the context
- * @param style the proxy object for current map style. More info at {@link Style}
- * @param locationEngine the engine, or null if you'd like to only force location updates
- * @param locationEngineRequest the location request
- * @param options the options
- * @deprecated use {@link LocationComponentActivationOptions.Builder} instead
- */
- @Deprecated
- public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
- @Nullable LocationEngine locationEngine,
- @NonNull LocationEngineRequest locationEngineRequest,
- @NonNull LocationComponentOptions options) {
- initialize(context, style, options);
- setLocationEngineRequest(locationEngineRequest);
- setLocationEngine(locationEngine);
- applyStyle(options);
- }
-
- /**
- * This method initializes the component and needs to be called before any other operations are performed.
- * Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
- *
- * @param activationOptions a fully built {@link LocationComponentActivationOptions} object
- */
- public void activateLocationComponent(@NonNull LocationComponentActivationOptions activationOptions) {
- LocationComponentOptions options = activationOptions.locationComponentOptions();
- if (options == null) {
- int styleRes = activationOptions.styleRes();
- if (styleRes == 0) {
- styleRes = R.style.mapbox_LocationComponent;
- }
- options = LocationComponentOptions.createFromAttributes(activationOptions.context(), styleRes);
- }
-
- // Initialize the LocationComponent with Context, the map's `Style`, and either custom LocationComponentOptions
- // or backup options created from default/custom attributes
- initialize(activationOptions.context(), activationOptions.style(), options);
-
- // Apply the LocationComponent styling
- // TODO avoid doubling style initialization
- applyStyle(options);
-
- // Set the LocationEngine request if one was given to LocationComponentActivationOptions
- LocationEngineRequest locationEngineRequest = activationOptions.locationEngineRequest();
- if (locationEngineRequest != null) {
- setLocationEngineRequest(locationEngineRequest);
- }
-
- // Set the LocationEngine if one was given to LocationComponentActivationOptions
- LocationEngine locationEngine = activationOptions.locationEngine();
- if (locationEngine != null) {
- setLocationEngine(locationEngine);
- } else {
- if (activationOptions.useDefaultLocationEngine()) {
- initializeLocationEngine(activationOptions.context());
- } else {
- setLocationEngine(null);
- }
- }
- }
-
- /**
- * Manage component's visibility after activation.
- *
- * @param isEnabled true if the plugin should be visible and listen for location updates, false otherwise.
- */
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
- public void setLocationComponentEnabled(boolean isEnabled) {
- checkActivationState();
- if (isEnabled) {
- enableLocationComponent();
- } else {
- disableLocationComponent();
- }
- }
-
- /**
- * Returns whether the plugin is enabled, meaning that location can be displayed and camera modes can be used.
- *
- * @return true if the plugin is enabled, false otherwise
- */
- public boolean isLocationComponentEnabled() {
- checkActivationState();
- return isEnabled;
- }
-
- /**
- * Sets the camera mode, which determines how the map camera will track the rendered location.
- * <p>
- * When camera is transitioning to a new mode, it will reject inputs like {@link #zoomWhileTracking(double)} or
- * {@link #tiltWhileTracking(double)}.
- * Use {@link OnLocationCameraTransitionListener} to listen for the transition state.
- * <p>
- * <ul>
- * <li>{@link CameraMode#NONE}: No camera tracking</li>
- * <li>{@link CameraMode#NONE_COMPASS}: Camera does not track location, but does track compass bearing</li>
- * <li>{@link CameraMode#NONE_GPS}: Camera does not track location, but does track GPS bearing</li>
- * <li>{@link CameraMode#TRACKING}: Camera tracks the user location</li>
- * <li>{@link CameraMode#TRACKING_COMPASS}: Camera tracks the user location, with bearing provided by a compass</li>
- * <li>{@link CameraMode#TRACKING_GPS}: Camera tracks the user location, with normalized bearing</li>
- * <li>{@link CameraMode#TRACKING_GPS_NORTH}: Camera tracks the user location, with bearing always set to north</li>
- * </ul>
- *
- * @param cameraMode one of the modes found in {@link CameraMode}
- */
- public void setCameraMode(@CameraMode.Mode int cameraMode) {
- setCameraMode(cameraMode, null);
- }
-
- /**
- * Sets the camera mode, which determines how the map camera will track the rendered location.
- * <p>
- * When camera is transitioning to a new mode, it will reject inputs like {@link #zoomWhileTracking(double)} or
- * {@link #tiltWhileTracking(double)}.
- * Use {@link OnLocationCameraTransitionListener} to listen for the transition state.
- * <p>
- * <ul>
- * <li>{@link CameraMode#NONE}: No camera tracking</li>
- * <li>{@link CameraMode#NONE_COMPASS}: Camera does not track location, but does track compass bearing</li>
- * <li>{@link CameraMode#NONE_GPS}: Camera does not track location, but does track GPS bearing</li>
- * <li>{@link CameraMode#TRACKING}: Camera tracks the user location</li>
- * <li>{@link CameraMode#TRACKING_COMPASS}: Camera tracks the user location, with bearing provided by a compass</li>
- * <li>{@link CameraMode#TRACKING_GPS}: Camera tracks the user location, with normalized bearing</li>
- * <li>{@link CameraMode#TRACKING_GPS_NORTH}: Camera tracks the user location, with bearing always set to north</li>
- * </ul>
- *
- * @param cameraMode one of the modes found in {@link CameraMode}
- * @param transitionListener callback that's going to be invoked when the transition animation finishes
- */
- public void setCameraMode(@CameraMode.Mode int cameraMode,
- @Nullable OnLocationCameraTransitionListener transitionListener) {
- setCameraMode(cameraMode, TRANSITION_ANIMATION_DURATION_MS, null, null, null, transitionListener);
- }
-
- /**
- * Sets the camera mode, which determines how the map camera will track the rendered location.
- * <p>
- * When camera is transitioning to a new mode, it will reject inputs like {@link #zoomWhileTracking(double)} or
- * {@link #tiltWhileTracking(double)}.
- * Use {@link OnLocationCameraTransitionListener} to listen for the transition state.
- * <p>
- * Set values of zoom, bearing and tilt that the camera will transition to. If null is passed to any of those,
- * current value will be used for that parameter instead.
- * If the camera is already tracking, provided values are ignored.
- * <p>
- * <ul>
- * <li>{@link CameraMode#NONE}: No camera tracking</li>
- * <li>{@link CameraMode#NONE_COMPASS}: Camera does not track location, but does track compass bearing</li>
- * <li>{@link CameraMode#NONE_GPS}: Camera does not track location, but does track GPS bearing</li>
- * <li>{@link CameraMode#TRACKING}: Camera tracks the user location</li>
- * <li>{@link CameraMode#TRACKING_COMPASS}: Camera tracks the user location, with bearing provided by a compass</li>
- * <li>{@link CameraMode#TRACKING_GPS}: Camera tracks the user location, with normalized bearing</li>
- * <li>{@link CameraMode#TRACKING_GPS_NORTH}: Camera tracks the user location, with bearing always set to north</li>
- * </ul>
- *
- * @param cameraMode one of the modes found in {@link CameraMode}
- * @param transitionDuration duration of the transition in milliseconds
- * @param zoom target zoom, set to null to use current camera position
- * @param bearing target bearing, set to null to use current camera position
- * @param tilt target tilt, set to null to use current camera position
- * @param transitionListener callback that's going to be invoked when the transition animation finishes
- */
- public void setCameraMode(@CameraMode.Mode int cameraMode,
- long transitionDuration,
- @Nullable Double zoom, @Nullable Double bearing, @Nullable Double tilt,
- @Nullable OnLocationCameraTransitionListener transitionListener) {
- checkActivationState();
- locationCameraController.setCameraMode(
- cameraMode, lastLocation, transitionDuration, zoom, bearing, tilt,
- new CameraTransitionListener(transitionListener));
- updateCompassListenerState(true);
- }
-
- /**
- * Used to reset camera animators and notify listeners when the transition finishes.
- */
- private class CameraTransitionListener implements OnLocationCameraTransitionListener {
-
- private final OnLocationCameraTransitionListener externalListener;
-
- private CameraTransitionListener(OnLocationCameraTransitionListener externalListener) {
- this.externalListener = externalListener;
- }
-
- @Override
- public void onLocationCameraTransitionFinished(int cameraMode) {
- if (externalListener != null) {
- externalListener.onLocationCameraTransitionFinished(cameraMode);
- }
- reset(cameraMode);
- }
-
- @Override
- public void onLocationCameraTransitionCanceled(int cameraMode) {
- if (externalListener != null) {
- externalListener.onLocationCameraTransitionCanceled(cameraMode);
- }
- reset(cameraMode);
- }
-
- private void reset(@CameraMode.Mode int cameraMode) {
- locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(),
- cameraMode == CameraMode.TRACKING_GPS_NORTH);
- }
- }
-
- /**
- * Provides the current camera mode being used to track the location or compass updates.
- *
- * @return the current camera mode
- */
- @CameraMode.Mode
- public int getCameraMode() {
- checkActivationState();
- return locationCameraController.getCameraMode();
- }
-
- /**
- * Sets the render mode, which determines how the location updates will be rendered on the map.
- * <p>
- * <ul>
- * <li>{@link RenderMode#NORMAL}: Shows user location, bearing ignored</li>
- * <li>{@link RenderMode#COMPASS}: Shows user location with bearing considered from compass</li>
- * <li>{@link RenderMode#GPS}: Shows user location with bearing considered from location</li>
- * </ul>
- *
- * @param renderMode one of the modes found in {@link RenderMode}
- */
- public void setRenderMode(@RenderMode.Mode int renderMode) {
- checkActivationState();
- locationLayerController.setRenderMode(renderMode);
- updateLayerOffsets(true);
- updateCompassListenerState(true);
- }
-
- /**
- * Provides the current render mode being used to show
- * the location and/or compass updates on the map.
- *
- * @return the current render mode
- */
- @RenderMode.Mode
- public int getRenderMode() {
- checkActivationState();
- return locationLayerController.getRenderMode();
- }
-
- /**
- * Returns the current location options being used.
- *
- * @return the current {@link LocationComponentOptions}
- */
- public LocationComponentOptions getLocationComponentOptions() {
- checkActivationState();
- return options;
- }
-
- /**
- * Apply a new component style with a style resource.
- *
- * @param styleRes a XML style overriding some or all the options
- */
- public void applyStyle(@NonNull Context context, @StyleRes int styleRes) {
- checkActivationState();
- applyStyle(LocationComponentOptions.createFromAttributes(context, styleRes));
- }
-
- /**
- * Apply a new component style with location component options.
- *
- * @param options to update the current style
- */
- public void applyStyle(@NonNull final LocationComponentOptions options) {
- checkActivationState();
- LocationComponent.this.options = options;
- if (mapboxMap.getStyle() != null) {
- locationLayerController.applyStyle(options);
- locationCameraController.initializeOptions(options);
- staleStateManager.setEnabled(options.enableStaleState());
- staleStateManager.setDelayTime(options.staleStateTimeout());
- locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options.trackingAnimationDurationMultiplier());
- locationAnimatorCoordinator.setCompassAnimationEnabled(options.compassAnimationEnabled());
- locationAnimatorCoordinator.setAccuracyAnimationEnabled(options.accuracyAnimationEnabled());
- updateMapWithOptions(options);
- }
- }
-
- /**
- * Zooms to the desired zoom level.
- * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}.
- * If you are not using any of {@link CameraMode} modes,
- * use one of {@link MapboxMap#moveCamera(CameraUpdate)},
- * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead.
- * <p>
- * If the camera is transitioning when the zoom change is requested, the call is going to be ignored.
- * Use {@link CameraTransitionListener} to chain the animations, or provide the zoom as a camera change argument.
- * </p>
- *
- * @param zoomLevel The desired zoom level.
- * @param animationDuration The zoom animation duration.
- * @param callback The callback with finish/cancel information
- */
- public void zoomWhileTracking(double zoomLevel, long animationDuration,
- @Nullable MapboxMap.CancelableCallback callback) {
- checkActivationState();
- if (!isLayerReady) {
- return;
- } else if (getCameraMode() == CameraMode.NONE) {
- Logger.e(TAG, String.format("%s%s",
- "LocationComponent#zoomWhileTracking method can only be used",
- " when a camera mode other than CameraMode#NONE is engaged."));
- return;
- } else if (locationCameraController.isTransitioning()) {
- Logger.e(TAG,
- "LocationComponent#zoomWhileTracking method call is ignored because the camera mode is transitioning");
- return;
- }
- locationAnimatorCoordinator.feedNewZoomLevel(zoomLevel, mapboxMap.getCameraPosition(), animationDuration, callback);
- }
-
- /**
- * Zooms to the desired zoom level.
- * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}.
- * If you are not using any of {@link CameraMode} modes,
- * use one of {@link MapboxMap#moveCamera(CameraUpdate)},
- * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead.
- * <p>
- * If the camera is transitioning when the zoom change is requested, the call is going to be ignored.
- * Use {@link CameraTransitionListener} to chain the animations, or provide the zoom as a camera change argument.
- * </p>
- *
- * @param zoomLevel The desired zoom level.
- * @param animationDuration The zoom animation duration.
- */
- public void zoomWhileTracking(double zoomLevel, long animationDuration) {
- checkActivationState();
- zoomWhileTracking(zoomLevel, animationDuration, null);
- }
-
- /**
- * Zooms to the desired zoom level.
- * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}.
- * If you are not using any of {@link CameraMode} modes,
- * use one of {@link MapboxMap#moveCamera(CameraUpdate)},
- * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead.
- * <p>
- * If the camera is transitioning when the zoom change is requested, the call is going to be ignored.
- * Use {@link CameraTransitionListener} to chain the animations, or provide the zoom as a camera change argument.
- * </p>
- *
- * @param zoomLevel The desired zoom level.
- */
- public void zoomWhileTracking(double zoomLevel) {
- checkActivationState();
- zoomWhileTracking(zoomLevel, DEFAULT_TRACKING_ZOOM_ANIM_DURATION, null);
- }
-
- /**
- * Cancels animation started by {@link #zoomWhileTracking(double, long, MapboxMap.CancelableCallback)}.
- */
- public void cancelZoomWhileTrackingAnimation() {
- checkActivationState();
- locationAnimatorCoordinator.cancelZoomAnimation();
- }
-
- /**
- * Tilts the camera.
- * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}.
- * If you are not using any of {@link CameraMode} modes,
- * use one of {@link MapboxMap#moveCamera(CameraUpdate)},
- * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead.
- * <p>
- * If the camera is transitioning when the tilt change is requested, the call is going to be ignored.
- * Use {@link CameraTransitionListener} to chain the animations, or provide the tilt as a camera change argument.
- * </p>
- *
- * @param tilt The desired camera tilt.
- * @param animationDuration The tilt animation duration.
- * @param callback The callback with finish/cancel information
- */
- public void tiltWhileTracking(double tilt, long animationDuration,
- @Nullable MapboxMap.CancelableCallback callback) {
- checkActivationState();
- if (!isLayerReady) {
- return;
- } else if (getCameraMode() == CameraMode.NONE) {
- Logger.e(TAG, String.format("%s%s",
- "LocationComponent#tiltWhileTracking method can only be used",
- " when a camera mode other than CameraMode#NONE is engaged."));
- return;
- } else if (locationCameraController.isTransitioning()) {
- Logger.e(TAG,
- "LocationComponent#tiltWhileTracking method call is ignored because the camera mode is transitioning");
- return;
- }
- locationAnimatorCoordinator.feedNewTilt(tilt, mapboxMap.getCameraPosition(), animationDuration, callback);
- }
-
- /**
- * Tilts the camera.
- * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}.
- * If you are not using any of {@link CameraMode} modes,
- * use one of {@link MapboxMap#moveCamera(CameraUpdate)},
- * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead.
- * <p>
- * If the camera is transitioning when the tilt change is requested, the call is going to be ignored.
- * Use {@link CameraTransitionListener} to chain the animations, or provide the tilt as a camera change argument.
- * </p>
- *
- * @param tilt The desired camera tilt.
- * @param animationDuration The tilt animation duration.
- */
- public void tiltWhileTracking(double tilt, long animationDuration) {
- checkActivationState();
- tiltWhileTracking(tilt, animationDuration, null);
- }
-
- /**
- * Tilts the camera.
- * This API can only be used in pair with camera modes other than {@link CameraMode#NONE}.
- * If you are not using any of {@link CameraMode} modes,
- * use one of {@link MapboxMap#moveCamera(CameraUpdate)},
- * {@link MapboxMap#easeCamera(CameraUpdate)} or {@link MapboxMap#animateCamera(CameraUpdate)} instead.
- * <p>
- * If the camera is transitioning when the tilt change is requested, the call is going to be ignored.
- * Use {@link CameraTransitionListener} to chain the animations, or provide the tilt as a camera change argument.
- * </p>
- *
- * @param tilt The desired camera tilt.
- */
- public void tiltWhileTracking(double tilt) {
- checkActivationState();
- tiltWhileTracking(tilt, DEFAULT_TRACKING_TILT_ANIM_DURATION, null);
- }
-
- /**
- * Cancels animation started by {@link #tiltWhileTracking(double, long, MapboxMap.CancelableCallback)}.
- */
- public void cancelTiltWhileTrackingAnimation() {
- checkActivationState();
- locationAnimatorCoordinator.cancelTiltAnimation();
- }
-
- /**
- * Use to either force a location update or to manually control when the user location gets
- * updated.
- *
- * @param location where the location icon is placed on the map
- */
- public void forceLocationUpdate(@Nullable Location location) {
- checkActivationState();
- updateLocation(location, false);
- }
-
- /**
- * Set max FPS at which location animators can output updates. The throttling will only impact the location puck
- * and camera tracking smooth animations.
- * <p>
- * Setting this <b>will not impact</b> any other animations schedule with {@link MapboxMap}, gesture animations or
- * {@link #zoomWhileTracking(double)}/{@link #tiltWhileTracking(double)}.
- * <p>
- * Use this setting to limit animation rate of the location puck on higher zoom levels to decrease the stress on
- * the device's CPU which can directly improve battery life, without sacrificing UX.
- * <p>
- * Example usage:
- * <pre>
- * {@code
- * mapboxMap.addOnCameraIdleListener(new MapboxMap.OnCameraIdleListener() {
- * {@literal @}Override
- * public void onCameraIdle() {
- * double zoom = mapboxMap.getCameraPosition().zoom;
- * int maxAnimationFps;
- * if (zoom < 5) {
- * maxAnimationFps = 3;
- * } else if (zoom < 10) {
- * maxAnimationFps = 5;
- * } else if (zoom < 15) {
- * maxAnimationFps = 7;
- * } else if (zoom < 18) {
- * maxAnimationFps = 15;
- * } else {
- * maxAnimationFps = Integer.MAX_VALUE;
- * }
- * locationComponent.setMaxAnimationFps(maxAnimationFps);
- * }
- * });
- * }
- * </pre>
- * <p>
- * If you're looking for a way to throttle the FPS of the whole map, including other animations and gestures, see
- * {@link MapView#setMaximumFps(int)}.
- *
- * @param maxAnimationFps max location animation FPS
- */
- public void setMaxAnimationFps(int maxAnimationFps) {
- checkActivationState();
- locationAnimatorCoordinator.setMaxAnimationFps(maxAnimationFps);
- }
-
- /**
- * Set the location engine to update the current user location.
- * <p>
- * If {@code null} is passed in, all updates will have to occur through the
- * {@link LocationComponent#forceLocationUpdate(Location)} method.
- *
- * @param locationEngine a {@link LocationEngine} this component should use to handle updates
- */
- @SuppressLint("MissingPermission")
- public void setLocationEngine(@Nullable LocationEngine locationEngine) {
- checkActivationState();
- if (this.locationEngine != null) {
- // If internal location engines being used, extra steps need to be taken to deconstruct the instance.
- this.locationEngine.removeLocationUpdates(currentLocationEngineListener);
- this.locationEngine = null;
- }
-
- if (locationEngine != null) {
- fastestInterval = locationEngineRequest.getFastestInterval();
- this.locationEngine = locationEngine;
- if (isLayerReady && isEnabled) {
- setLastLocation();
- locationEngine.requestLocationUpdates(
- locationEngineRequest, currentLocationEngineListener, Looper.getMainLooper());
- }
- } else {
- fastestInterval = 0;
- }
- }
-
- /**
- * Set the location request that's going to be used when requesting location updates.
- *
- * @param locationEngineRequest the location request
- */
- public void setLocationEngineRequest(@NonNull LocationEngineRequest locationEngineRequest) {
- checkActivationState();
- this.locationEngineRequest = locationEngineRequest;
-
- // reset internal LocationEngine ref to re-request location updates if needed
- setLocationEngine(locationEngine);
- }
-
- /**
- * Get the location request that's going to be used when requesting location updates.
- */
- @NonNull
- public LocationEngineRequest getLocationEngineRequest() {
- checkActivationState();
- return locationEngineRequest;
- }
-
- /**
- * Returns the current {@link LocationEngine} being used for updating the user location.
- *
- * @return the {@link LocationEngine} being used to update the user location
- */
- @Nullable
- public LocationEngine getLocationEngine() {
- checkActivationState();
- return locationEngine;
- }
-
- /**
- * Sets the compass engine used to provide compass heading values.
- *
- * @param compassEngine to be used
- */
- public void setCompassEngine(@Nullable CompassEngine compassEngine) {
- checkActivationState();
- if (this.compassEngine != null) {
- updateCompassListenerState(false);
- }
- this.compassEngine = compassEngine;
- updateCompassListenerState(true);
- }
-
- /**
- * Returns the compass engine used to provide compass heading values.
- *
- * @return compass engine currently being used
- */
- @Nullable
- public CompassEngine getCompassEngine() {
- checkActivationState();
- return compassEngine;
- }
-
- /**
- * Get the last know location of the location component.
- *
- * @return the last known location
- */
- @Nullable
- public Location getLastKnownLocation() {
- checkActivationState();
- return lastLocation;
- }
-
- /**
- * Adds a listener that gets invoked when the user clicks the displayed location.
- * <p>
- * If there are registered location click listeners and the location is clicked,
- * only {@link OnLocationClickListener#onLocationComponentClick()} is going to be delivered,
- * {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnMapClickListener#onMapClick(LatLng)} is going to be consumed
- * and not pushed to the listeners registered after the component's activation.
- *
- * @param listener The location click listener that is invoked when the
- * location is clicked
- */
- public void addOnLocationClickListener(@NonNull OnLocationClickListener listener) {
- onLocationClickListeners.add(listener);
- }
-
- /**
- * Removes the passed listener from the current list of location click listeners.
- *
- * @param listener to be removed
- */
- public void removeOnLocationClickListener(@NonNull OnLocationClickListener listener) {
- onLocationClickListeners.remove(listener);
- }
-
- /**
- * Adds a listener that gets invoked when the user long clicks the displayed location.
- * <p>
- * If there are registered location long click listeners and the location is long clicked,
- * only {@link OnLocationLongClickListener#onLocationComponentLongClick()} is going to be delivered,
- * {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnMapLongClickListener#onMapLongClick(LatLng)} is going to be consumed
- * and not pushed to the listeners registered after the component's activation.
- *
- * @param listener The location click listener that is invoked when the
- * location is clicked
- */
- public void addOnLocationLongClickListener(@NonNull OnLocationLongClickListener listener) {
- onLocationLongClickListeners.add(listener);
- }
-
- /**
- * Removes the passed listener from the current list of location long click listeners.
- *
- * @param listener to be removed
- */
- public void removeOnLocationLongClickListener(@NonNull OnLocationLongClickListener listener) {
- onLocationLongClickListeners.remove(listener);
- }
-
- /**
- * Adds a listener that gets invoked when camera tracking state changes.
- *
- * @param listener Listener that gets invoked when camera tracking state changes.
- */
- public void addOnCameraTrackingChangedListener(@NonNull OnCameraTrackingChangedListener listener) {
- onCameraTrackingChangedListeners.add(listener);
- }
-
- /**
- * Removes a listener that gets invoked when camera tracking state changes.
- *
- * @param listener Listener that gets invoked when camera tracking state changes.
- */
- public void removeOnCameraTrackingChangedListener(@NonNull OnCameraTrackingChangedListener listener) {
- onCameraTrackingChangedListeners.remove(listener);
- }
-
- /**
- * Adds a listener that gets invoked when render mode changes.
- *
- * @param listener Listener that gets invoked when render mode changes.
- */
- public void addOnRenderModeChangedListener(@NonNull OnRenderModeChangedListener listener) {
- onRenderModeChangedListeners.add(listener);
- }
-
- /**
- * Removes a listener that gets invoked when render mode changes.
- *
- * @param listener Listener that gets invoked when render mode changes.
- */
- public void removeRenderModeChangedListener(@NonNull OnRenderModeChangedListener listener) {
- onRenderModeChangedListeners.remove(listener);
- }
-
- /**
- * Adds the passed listener that gets invoked when user updates have stopped long enough for the last update
- * to be considered stale.
- * <p>
- * This timeout is set by {@link LocationComponentOptions#staleStateTimeout()}.
- *
- * @param listener invoked when last update is considered stale
- */
- public void addOnLocationStaleListener(@NonNull OnLocationStaleListener listener) {
- onLocationStaleListeners.add(listener);
- }
-
- /**
- * Removes the passed listener from the current list of stale listeners.
- *
- * @param listener to be removed from the list
- */
- public void removeOnLocationStaleListener(@NonNull OnLocationStaleListener listener) {
- onLocationStaleListeners.remove(listener);
- }
-
- /**
- * Internal use.
- */
- public void onStart() {
- isComponentStarted = true;
- onLocationLayerStart();
- }
-
- /**
- * Internal use.
- */
- public void onStop() {
- onLocationLayerStop();
- isComponentStarted = false;
- }
-
- /**
- * Internal use.
- */
- public void onDestroy() {
- }
-
- /**
- * Internal use.
- */
- public void onStartLoadingMap() {
- onLocationLayerStop();
- }
-
- /**
- * Internal use.
- */
- public void onFinishLoadingStyle() {
- if (isComponentInitialized) {
- style = mapboxMap.getStyle();
- locationLayerController.initializeComponents(style, options);
- locationCameraController.initializeOptions(options);
- onLocationLayerStart();
- }
- }
-
- @SuppressLint("MissingPermission")
- private void onLocationLayerStart() {
- if (!isComponentInitialized || !isComponentStarted || mapboxMap.getStyle() == null) {
- return;
- }
-
- if (!isLayerReady) {
- isLayerReady = true;
- mapboxMap.addOnCameraMoveListener(onCameraMoveListener);
- mapboxMap.addOnCameraIdleListener(onCameraIdleListener);
- if (options.enableStaleState()) {
- staleStateManager.onStart();
- }
- }
-
- if (isEnabled) {
- if (locationEngine != null) {
- try {
- locationEngine.requestLocationUpdates(
- locationEngineRequest, currentLocationEngineListener, Looper.getMainLooper());
- } catch (SecurityException se) {
- Logger.e(TAG, "Unable to request location updates", se);
- }
- }
- setCameraMode(locationCameraController.getCameraMode());
- setLastLocation();
- updateCompassListenerState(true);
- setLastCompassHeading();
- }
- }
-
- private void onLocationLayerStop() {
- if (!isComponentInitialized || !isLayerReady || !isComponentStarted) {
- return;
- }
-
- isLayerReady = false;
- staleStateManager.onStop();
- if (compassEngine != null) {
- updateCompassListenerState(false);
- }
- locationAnimatorCoordinator.cancelAllAnimations();
- if (locationEngine != null) {
- locationEngine.removeLocationUpdates(currentLocationEngineListener);
- }
- mapboxMap.removeOnCameraMoveListener(onCameraMoveListener);
- mapboxMap.removeOnCameraIdleListener(onCameraIdleListener);
- }
-
- private void initialize(@NonNull final Context context, @NonNull Style style,
- @NonNull final LocationComponentOptions options) {
- if (isComponentInitialized) {
- return;
- }
- isComponentInitialized = true;
-
- if (!style.isFullyLoaded()) {
- throw new IllegalStateException("Style is invalid, provide the most recently loaded one.");
- }
-
- this.style = style;
- this.options = options;
-
- mapboxMap.addOnMapClickListener(onMapClickListener);
- mapboxMap.addOnMapLongClickListener(onMapLongClickListener);
-
- LayerSourceProvider sourceProvider = new LayerSourceProvider();
- LayerFeatureProvider featureProvider = new LayerFeatureProvider();
- LayerBitmapProvider bitmapProvider = new LayerBitmapProvider(context);
- locationLayerController = new LocationLayerController(mapboxMap, style, sourceProvider, featureProvider,
- bitmapProvider, options, renderModeChangedListener);
- locationCameraController = new LocationCameraController(
- context, mapboxMap, transform, cameraTrackingChangedListener, options, onCameraMoveInvalidateListener);
-
- locationAnimatorCoordinator = new LocationAnimatorCoordinator(
- mapboxMap.getProjection(),
- MapboxAnimatorSetProvider.getInstance(),
- MapboxAnimatorProvider.getInstance()
- );
- locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options
- .trackingAnimationDurationMultiplier());
-
- WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
- if (windowManager != null && sensorManager != null) {
- compassEngine = new LocationComponentCompassEngine(windowManager, sensorManager);
- }
- staleStateManager = new StaleStateManager(onLocationStaleListener, options);
-
- updateMapWithOptions(options);
-
- setRenderMode(RenderMode.NORMAL);
- setCameraMode(CameraMode.NONE);
-
- onLocationLayerStart();
- }
-
- private void initializeLocationEngine(@NonNull Context context) {
- if (this.locationEngine != null) {
- this.locationEngine.removeLocationUpdates(currentLocationEngineListener);
- }
- setLocationEngine(internalLocationEngineProvider.getBestLocationEngine(context, false));
- }
-
- private void updateCompassListenerState(boolean canListen) {
- if (compassEngine != null) {
- if (!canListen) {
- // We shouldn't listen, simply unregistering
- removeCompassListener(compassEngine);
- return;
- }
-
- if (!isComponentInitialized || !isComponentStarted || !isEnabled) {
- return;
- }
-
- if (locationCameraController.isConsumingCompass() || locationLayerController.isConsumingCompass()) {
- // If we have a consumer, and not yet listening, then start listening
- if (!isListeningToCompass) {
- isListeningToCompass = true;
- compassEngine.addCompassListener(compassListener);
- }
- } else {
- // If we have no consumers, stop listening
- removeCompassListener(compassEngine);
- }
- }
- }
-
- private void removeCompassListener(@NonNull CompassEngine engine) {
- if (isListeningToCompass) {
- isListeningToCompass = false;
- engine.removeCompassListener(compassListener);
- }
- }
-
- private void enableLocationComponent() {
- isEnabled = true;
- onLocationLayerStart();
- }
-
- private void disableLocationComponent() {
- isEnabled = false;
- locationLayerController.hide();
- onLocationLayerStop();
- }
-
- private void updateMapWithOptions(@NonNull LocationComponentOptions options) {
- int[] padding = options.padding();
- if (padding != null) {
- mapboxMap.setPadding(
- padding[0], padding[1], padding[2], padding[3]
- );
- }
- }
-
- /**
- * Updates the user location icon.
- *
- * @param location the latest user location
- */
- private void updateLocation(@Nullable final Location location, boolean fromLastLocation) {
- if (location == null) {
- return;
- } else if (!isLayerReady) {
- lastLocation = location;
- return;
- } else {
- long currentTime = SystemClock.elapsedRealtime();
- if (currentTime - lastUpdateTime < fastestInterval) {
- return;
- } else {
- lastUpdateTime = currentTime;
- }
- }
-
- showLocationLayerIfHidden();
-
- if (!fromLastLocation) {
- staleStateManager.updateLatestLocationTime();
- }
- CameraPosition currentCameraPosition = mapboxMap.getCameraPosition();
- boolean isGpsNorth = getCameraMode() == CameraMode.TRACKING_GPS_NORTH;
- locationAnimatorCoordinator.feedNewLocation(location, currentCameraPosition, isGpsNorth);
- updateAccuracyRadius(location, false);
- lastLocation = location;
- }
-
- private void showLocationLayerIfHidden() {
- boolean isLocationLayerHidden = locationLayerController.isHidden();
- if (isEnabled && isComponentStarted && isLocationLayerHidden) {
- locationLayerController.show();
- }
- }
-
- private void updateCompassHeading(float heading) {
- locationAnimatorCoordinator.feedNewCompassBearing(heading, mapboxMap.getCameraPosition());
- }
-
- /**
- * If the locationEngine contains a last location value, we use it for the initial location layer
- * position.
- */
- @SuppressLint("MissingPermission")
- private void setLastLocation() {
- if (locationEngine != null) {
- locationEngine.getLastLocation(lastLocationEngineListener);
- } else {
- updateLocation(getLastKnownLocation(), true);
- }
- }
-
- private void setLastCompassHeading() {
- updateCompassHeading(compassEngine != null ? compassEngine.getLastHeading() : 0);
- }
-
- @SuppressLint("MissingPermission")
- private void updateLayerOffsets(boolean forceUpdate) {
- CameraPosition position = mapboxMap.getCameraPosition();
- if (lastCameraPosition == null || forceUpdate) {
- lastCameraPosition = position;
- locationLayerController.updateForegroundBearing((float) position.bearing);
- locationLayerController.updateForegroundOffset(position.tilt);
- updateAccuracyRadius(getLastKnownLocation(), true);
- return;
- }
-
- if (position.bearing != lastCameraPosition.bearing) {
- locationLayerController.updateForegroundBearing((float) position.bearing);
- }
- if (position.tilt != lastCameraPosition.tilt) {
- locationLayerController.updateForegroundOffset(position.tilt);
- }
- if (position.zoom != lastCameraPosition.zoom) {
- updateAccuracyRadius(getLastKnownLocation(), true);
- }
- lastCameraPosition = position;
- }
-
- private void updateAccuracyRadius(Location location, boolean noAnimation) {
- locationAnimatorCoordinator.feedNewAccuracyRadius(Utils.calculateZoomLevelRadius(mapboxMap, location), noAnimation);
- }
-
- private void updateAnimatorListenerHolders() {
- Set<AnimatorListenerHolder> animationsValueChangeListeners = new HashSet<>();
- animationsValueChangeListeners.addAll(locationLayerController.getAnimationListeners());
- animationsValueChangeListeners.addAll(locationCameraController.getAnimationListeners());
- locationAnimatorCoordinator.updateAnimatorListenerHolders(animationsValueChangeListeners);
- locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(),
- locationCameraController.getCameraMode() == CameraMode.TRACKING_GPS_NORTH);
- locationAnimatorCoordinator.resetAllLayerAnimations();
- }
-
- @NonNull
- private OnCameraMoveListener onCameraMoveListener = new OnCameraMoveListener() {
- @Override
- public void onCameraMove() {
- updateLayerOffsets(false);
- }
- };
-
- @NonNull
- private OnCameraIdleListener onCameraIdleListener = new OnCameraIdleListener() {
- @Override
- public void onCameraIdle() {
- updateLayerOffsets(false);
- }
- };
-
- @NonNull
- private OnMapClickListener onMapClickListener = new OnMapClickListener() {
- @Override
- public boolean onMapClick(@NonNull LatLng point) {
- if (!onLocationClickListeners.isEmpty() && locationLayerController.onMapClick(point)) {
- for (OnLocationClickListener listener : onLocationClickListeners) {
- listener.onLocationComponentClick();
- }
- return true;
- }
- return false;
- }
- };
-
- @NonNull
- private MapboxMap.OnMapLongClickListener onMapLongClickListener = new MapboxMap.OnMapLongClickListener() {
- @Override
- public boolean onMapLongClick(@NonNull LatLng point) {
- if (!onLocationLongClickListeners.isEmpty() && locationLayerController.onMapClick(point)) {
- for (OnLocationLongClickListener listener : onLocationLongClickListeners) {
- listener.onLocationComponentLongClick();
- }
- return true;
- }
- return false;
- }
- };
-
- @NonNull
- private OnLocationStaleListener onLocationStaleListener = new OnLocationStaleListener() {
- @Override
- public void onStaleStateChange(boolean isStale) {
- locationLayerController.setLocationsStale(isStale);
-
- for (OnLocationStaleListener listener : onLocationStaleListeners) {
- listener.onStaleStateChange(isStale);
- }
- }
- };
-
- @NonNull
- private OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = new OnCameraMoveInvalidateListener() {
- @Override
- public void onInvalidateCameraMove() {
- onCameraMoveListener.onCameraMove();
- }
- };
-
- @NonNull
- private CompassListener compassListener = new CompassListener() {
- @Override
- public void onCompassChanged(float userHeading) {
- updateCompassHeading(userHeading);
- }
-
- @Override
- public void onCompassAccuracyChange(int compassStatus) {
- // Currently don't handle this inside SDK
- }
- };
-
- @VisibleForTesting
- static final class CurrentLocationEngineCallback implements LocationEngineCallback<LocationEngineResult> {
- private final WeakReference<LocationComponent> componentWeakReference;
-
- CurrentLocationEngineCallback(LocationComponent component) {
- this.componentWeakReference = new WeakReference<>(component);
- }
-
- @Override
- public void onSuccess(LocationEngineResult result) {
- LocationComponent component = componentWeakReference.get();
- if (component != null) {
- component.updateLocation(result.getLastLocation(), false);
- }
- }
-
- @Override
- public void onFailure(@NonNull Exception exception) {
- Logger.e(TAG, "Failed to obtain location update", exception);
- }
- }
-
- @VisibleForTesting
- static final class LastLocationEngineCallback implements LocationEngineCallback<LocationEngineResult> {
- private final WeakReference<LocationComponent> componentWeakReference;
-
- LastLocationEngineCallback(LocationComponent component) {
- this.componentWeakReference = new WeakReference<>(component);
- }
-
- @Override
- public void onSuccess(LocationEngineResult result) {
- LocationComponent component = componentWeakReference.get();
- if (component != null) {
- component.updateLocation(result.getLastLocation(), true);
- }
- }
-
- @Override
- public void onFailure(@NonNull Exception exception) {
- Logger.e(TAG, "Failed to obtain last location update", exception);
- }
- }
-
- @NonNull
- @VisibleForTesting
- OnCameraTrackingChangedListener cameraTrackingChangedListener = new OnCameraTrackingChangedListener() {
- @Override
- public void onCameraTrackingDismissed() {
- for (OnCameraTrackingChangedListener listener : onCameraTrackingChangedListeners) {
- listener.onCameraTrackingDismissed();
- }
- }
-
- @Override
- public void onCameraTrackingChanged(int currentMode) {
- locationAnimatorCoordinator.cancelZoomAnimation();
- locationAnimatorCoordinator.cancelTiltAnimation();
- updateAnimatorListenerHolders();
- for (OnCameraTrackingChangedListener listener : onCameraTrackingChangedListeners) {
- listener.onCameraTrackingChanged(currentMode);
- }
- }
- };
-
- @NonNull
- @VisibleForTesting
- OnRenderModeChangedListener renderModeChangedListener = new OnRenderModeChangedListener() {
- @Override
- public void onRenderModeChanged(int currentMode) {
- updateAnimatorListenerHolders();
- for (OnRenderModeChangedListener listener : onRenderModeChangedListeners) {
- listener.onRenderModeChanged(currentMode);
- }
- }
- };
-
- @NonNull
- private final MapboxMap.OnDeveloperAnimationListener developerAnimationListener =
- new MapboxMap.OnDeveloperAnimationListener() {
- @Override
- public void onDeveloperAnimationStarted() {
- if (isComponentInitialized && isEnabled) {
- setCameraMode(CameraMode.NONE);
- }
- }
- };
-
- static class InternalLocationEngineProvider {
- LocationEngine getBestLocationEngine(@NonNull Context context, boolean background) {
- return LocationEngineProvider.getBestLocationEngine(context, background);
- }
- }
-
- private void checkActivationState() {
- if (!isComponentInitialized) {
- throw new LocationComponentNotInitializedException();
- }
- }
-
- /**
- * Returns whether the location component is activated.
- *
- * @return true if the component is activated, false otherwise
- */
- public boolean isLocationComponentActivated() {
- return isComponentInitialized;
- }
-}