diff options
author | kevin <kevin.li@mapbox.com> | 2019-01-16 08:29:58 -0800 |
---|---|---|
committer | kevin <kevin.li@mapbox.com> | 2019-01-16 08:29:58 -0800 |
commit | c09831cda04bf97c1c208cacfaaa660c36003cbd (patch) | |
tree | e1ff23c5feaea81d0e6ec096b17e5f223204c2d4 /platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location | |
parent | 788158cc5608bc428b13ad0ef6215626e1acaffd (diff) | |
parent | b23a6122259cac97f174dddb978437dd3a58a5df (diff) | |
download | qtlocation-mapboxgl-upstream/no-v7.tar.gz |
Merge branch 'release-horchata' into no-v7upstream/no-v7
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location')
11 files changed, 278 insertions, 65 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java index 3691bdc0ea..33efa06226 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java @@ -55,11 +55,17 @@ public interface CompassEngine { /** * Lifecycle method that can be used for adding or releasing resources. + * + * @deprecated Use {@link #addCompassListener(CompassListener)} */ + @Deprecated void onStart(); /** * Lifecycle method that can be used for adding or releasing resources. + * + * @deprecated Use {@link #removeCompassListener(CompassListener)} */ + @Deprecated void onStop(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java index 3e5eb7f258..c44218a1d1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java @@ -7,7 +7,7 @@ public interface CompassListener { /** * Callback's invoked when a new compass update occurs. You can listen into the compass updates - * using {@link LocationComponent#addCompassListener(CompassListener)} and implementing these + * using {@link CompassEngine#addCompassListener(CompassListener)} and implementing these * callbacks. Note that this interface is also used internally to to update the UI chevron/arrow. * * @param userHeading the new compass heading diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java index 0a6c9b5ddc..4ac124ef24 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java @@ -1,7 +1,6 @@ package com.mapbox.mapboxsdk.location; import android.animation.Animator; -import android.animation.AnimatorSet; import android.location.Location; import android.os.SystemClock; import android.support.annotation.NonNull; @@ -13,13 +12,13 @@ import android.view.animation.LinearInterpolator; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; import java.util.ArrayList; import java.util.List; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_RADIUS_ANIMATION_DURATION; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.COMPASS_UPDATE_RATE_MS; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.MAX_ANIMATION_DURATION_MS; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_COMPASS_BEARING; @@ -31,6 +30,7 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BE import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_TILT; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_ZOOM; +import static com.mapbox.mapboxsdk.location.Utils.immediateAnimation; final class LocationAnimatorCoordinator { @@ -39,11 +39,20 @@ final class LocationAnimatorCoordinator { final List<MapboxAnimator.OnLayerAnimationsValuesChangeListener> layerListeners = new ArrayList<>(); final List<MapboxAnimator.OnCameraAnimationsValuesChangeListener> cameraListeners = new ArrayList<>(); + private final Projection projection; private Location previousLocation; private float previousAccuracyRadius = -1; private float previousCompassBearing = -1; private long locationUpdateTimestamp = -1; private float durationMultiplier; + private final MapboxAnimatorSetProvider animatorSetProvider; + private boolean compassAnimationEnabled; + private boolean accuracyAnimationEnabled; + + LocationAnimatorCoordinator(@NonNull Projection projection, @NonNull MapboxAnimatorSetProvider animatorSetProvider) { + this.projection = projection; + this.animatorSetProvider = animatorSetProvider; + } void addLayerListener(MapboxAnimator.OnLayerAnimationsValuesChangeListener listener) { layerListeners.add(listener); @@ -81,8 +90,8 @@ final class LocationAnimatorCoordinator { updateLayerAnimators(previousLayerLatLng, targetLatLng, previousLayerBearing, targetLayerBearing); updateCameraAnimators(previousCameraLatLng, previousCameraBearing, targetLatLng, targetCameraBearing); - boolean snap = immediateAnimation(previousCameraLatLng, targetLatLng, currentCameraPosition.zoom) - || immediateAnimation(previousLayerLatLng, targetLatLng, currentCameraPosition.zoom); + boolean snap = immediateAnimation(projection, previousCameraLatLng, targetLatLng) + || immediateAnimation(projection, previousLayerLatLng, targetLatLng); playLocationAnimators(snap ? 0 : getAnimationDuration()); previousLocation = newLocation; @@ -97,7 +106,7 @@ final class LocationAnimatorCoordinator { float previousCameraBearing = (float) currentCameraPosition.bearing; updateCompassAnimators(targetCompassBearing, previousLayerBearing, previousCameraBearing); - playCompassAnimators(COMPASS_UPDATE_RATE_MS); + playCompassAnimators(compassAnimationEnabled ? COMPASS_UPDATE_RATE_MS : 0); previousCompassBearing = targetCompassBearing; } @@ -109,7 +118,7 @@ final class LocationAnimatorCoordinator { float previousAccuracyRadius = getPreviousAccuracyRadius(); updateAccuracyAnimators(targetAccuracyRadius, previousAccuracyRadius); - playAccuracyAnimator(noAnimation ? 0 : ACCURACY_RADIUS_ANIMATION_DURATION); + playAccuracyAnimator(noAnimation || !accuracyAnimationEnabled ? 0 : ACCURACY_RADIUS_ANIMATION_DURATION); this.previousAccuracyRadius = targetAccuracyRadius; } @@ -249,27 +258,20 @@ final class LocationAnimatorCoordinator { locationAnimators.add(animatorArray.get(ANIMATOR_LAYER_GPS_BEARING)); locationAnimators.add(animatorArray.get(ANIMATOR_CAMERA_LATLNG)); locationAnimators.add(animatorArray.get(ANIMATOR_CAMERA_GPS_BEARING)); - AnimatorSet locationAnimatorSet = new AnimatorSet(); - locationAnimatorSet.playTogether(locationAnimators); - locationAnimatorSet.setInterpolator(new LinearInterpolator()); - locationAnimatorSet.setDuration(duration); - locationAnimatorSet.start(); + animatorSetProvider.startAnimation(locationAnimators, new LinearInterpolator(), duration); } private void playCompassAnimators(long duration) { List<Animator> compassAnimators = new ArrayList<>(); compassAnimators.add(animatorArray.get(ANIMATOR_LAYER_COMPASS_BEARING)); compassAnimators.add(animatorArray.get(ANIMATOR_CAMERA_COMPASS_BEARING)); - AnimatorSet compassAnimatorSet = new AnimatorSet(); - compassAnimatorSet.playTogether(compassAnimators); - compassAnimatorSet.setDuration(duration); - compassAnimatorSet.start(); + animatorSetProvider.startAnimation(compassAnimators, new LinearInterpolator(), duration); } private void playAccuracyAnimator(long duration) { - MapboxAnimator animator = animatorArray.get(ANIMATOR_LAYER_ACCURACY); - animator.setDuration(duration); - animator.start(); + List<Animator> accuracyAnimators = new ArrayList<>(); + accuracyAnimators.add(animatorArray.get(ANIMATOR_LAYER_ACCURACY)); + animatorSetProvider.startAnimation(accuracyAnimators, new LinearInterpolator(), duration); } private void playZoomAnimator(long duration) { @@ -288,11 +290,7 @@ final class LocationAnimatorCoordinator { List<Animator> locationAnimators = new ArrayList<>(); locationAnimators.add(animatorArray.get(ANIMATOR_CAMERA_LATLNG)); locationAnimators.add(animatorArray.get(ANIMATOR_CAMERA_GPS_BEARING)); - AnimatorSet locationAnimatorSet = new AnimatorSet(); - locationAnimatorSet.playTogether(locationAnimators); - locationAnimatorSet.setInterpolator(new FastOutSlowInInterpolator()); - locationAnimatorSet.setDuration(duration); - locationAnimatorSet.start(); + animatorSetProvider.startAnimation(locationAnimators, new FastOutSlowInInterpolator(), duration); } void resetAllCameraAnimations(CameraPosition currentCameraPosition, boolean isGpsNorth) { @@ -317,7 +315,7 @@ final class LocationAnimatorCoordinator { createNewAnimator(ANIMATOR_CAMERA_LATLNG, new CameraLatLngAnimator(previousCameraTarget, currentTarget, cameraListeners)); - return immediateAnimation(previousCameraTarget, currentTarget, currentCameraPosition.zoom); + return immediateAnimation(projection, previousCameraTarget, currentTarget); } private void resetCameraGpsBearingAnimation(CameraPosition currentCameraPosition, boolean isGpsNorth) { @@ -382,12 +380,11 @@ final class LocationAnimatorCoordinator { this.durationMultiplier = trackingAnimationDurationMultiplier; } - private boolean immediateAnimation(LatLng current, LatLng target, double zoom) { - // TODO: calculate the value based on the projection - double distance = current.distanceTo(target); - if (zoom > 10) { - distance *= zoom; - } - return distance > INSTANT_LOCATION_TRANSITION_THRESHOLD; + void setCompassAnimationEnabled(boolean compassAnimationEnabled) { + this.compassAnimationEnabled = compassAnimationEnabled; + } + + void setAccuracyAnimationEnabled(boolean accuracyAnimationEnabled) { + this.accuracyAnimationEnabled = accuracyAnimationEnabled; } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java index e3194df009..340ee3d0f2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java @@ -164,6 +164,11 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation } } + boolean isConsumingCompass() { + return cameraMode == CameraMode.TRACKING_COMPASS + || cameraMode == CameraMode.NONE_COMPASS; + } + private boolean isLocationTracking() { return cameraMode == CameraMode.TRACKING || cameraMode == CameraMode.TRACKING_COMPASS 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 index 9118f926f3..e624378487 100644 --- 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 @@ -26,6 +26,8 @@ import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener; import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener; import com.mapbox.mapboxsdk.maps.MapboxMap.OnMapClickListener; +import org.jetbrains.annotations.NotNull; + import java.util.concurrent.CopyOnWriteArrayList; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; @@ -116,6 +118,11 @@ public final class LocationComponent { */ private boolean isLayerReady; + /** + * Indicates whether we are listening for compass updates. + */ + private boolean isListeningToCompass; + private StaleStateManager staleStateManager; private final CopyOnWriteArrayList<OnLocationStaleListener> onLocationStaleListeners = new CopyOnWriteArrayList<>(); @@ -135,6 +142,21 @@ public final class LocationComponent { this.mapboxMap = mapboxMap; } + public LocationComponent(@NotNull MapboxMap mapboxMap, @NotNull LocationEngine locationEngine, + @NotNull LocationLayerController locationLayerController, + @NotNull LocationCameraController locationCameraController, + @NotNull LocationAnimatorCoordinator locationAnimatorCoordinator, + @NotNull StaleStateManager staleStateManager, @NotNull CompassEngine compassEngine) { + this.mapboxMap = mapboxMap; + this.locationEngine = locationEngine; + this.locationLayerController = locationLayerController; + this.locationCameraController = locationCameraController; + this.locationAnimatorCoordinator = locationAnimatorCoordinator; + this.staleStateManager = staleStateManager; + this.compassEngine = compassEngine; + isInitialized = 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)}. @@ -276,6 +298,7 @@ public final class LocationComponent { locationCameraController.setCameraMode(cameraMode); boolean isGpsNorth = cameraMode == CameraMode.TRACKING_GPS_NORTH; locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(), isGpsNorth); + updateCompassListenerState(true); } /** @@ -302,6 +325,7 @@ public final class LocationComponent { public void setRenderMode(@RenderMode.Mode int renderMode) { locationLayerController.setRenderMode(renderMode); updateLayerOffsets(true); + updateCompassListenerState(true); } /** @@ -345,6 +369,8 @@ public final class LocationComponent { staleStateManager.setEnabled(options.enableStaleState()); staleStateManager.setDelayTime(options.staleStateTimeout()); locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options.trackingAnimationDurationMultiplier()); + locationAnimatorCoordinator.setCompassAnimationEnabled(options.compassAnimationEnabled()); + locationAnimatorCoordinator.setAccuracyAnimationEnabled(options.accuracyAnimationEnabled()); updateMapWithOptions(options); } @@ -518,10 +544,12 @@ public final class LocationComponent { * * @param compassEngine to be used */ - public void setCompassEngine(@NonNull CompassEngine compassEngine) { - this.compassEngine.removeCompassListener(compassListener); + public void setCompassEngine(@Nullable CompassEngine compassEngine) { + if (this.compassEngine != null) { + updateCompassListenerState(false); + } this.compassEngine = compassEngine; - compassEngine.addCompassListener(compassListener); + updateCompassListenerState(true); } /** @@ -529,7 +557,7 @@ public final class LocationComponent { * * @return compass engine currently being used */ - @NonNull + @Nullable public CompassEngine getCompassEngine() { return compassEngine; } @@ -555,9 +583,11 @@ public final class LocationComponent { * The last known accuracy of the compass sensor, one of SensorManager.SENSOR_STATUS_* * * @return the last know compass accuracy bearing + * @deprecated Use {@link #getCompassEngine()} */ + @Deprecated public float getLastKnownCompassAccuracyStatus() { - return compassEngine.getLastAccuracySensorStatus(); + return compassEngine != null ? compassEngine.getLastAccuracySensorStatus() : 0; } /** @@ -566,9 +596,13 @@ public final class LocationComponent { * * @param compassListener a {@link CompassListener} for listening into compass heading and * accuracy changes + * @deprecated Use {@link #getCompassEngine()} */ + @Deprecated public void addCompassListener(@NonNull CompassListener compassListener) { - compassEngine.addCompassListener(compassListener); + if (compassEngine != null) { + compassEngine.addCompassListener(compassListener); + } } /** @@ -576,9 +610,13 @@ public final class LocationComponent { * * @param compassListener the {@link CompassListener} which you'd like to remove from the listener * list. + * @deprecated Use {@link #getCompassEngine()} */ + @Deprecated public void removeCompassListener(@NonNull CompassListener compassListener) { - compassEngine.removeCompassListener(compassListener); + if (compassEngine != null) { + compassEngine.removeCompassListener(compassListener); + } } /** @@ -714,7 +752,6 @@ public final class LocationComponent { if (options.enableStaleState()) { staleStateManager.onStart(); } - compassEngine.onStart(); } if (isEnabled) { @@ -726,6 +763,7 @@ public final class LocationComponent { } setCameraMode(locationCameraController.getCameraMode()); setLastLocation(); + updateCompassListenerState(true); setLastCompassHeading(); } } @@ -738,7 +776,9 @@ public final class LocationComponent { isLayerReady = false; locationLayerController.hide(); staleStateManager.onStop(); - compassEngine.onStop(); + if (compassEngine != null) { + updateCompassListenerState(false); + } locationAnimatorCoordinator.cancelAllAnimations(); if (locationEngine != null) { if (usingInternalLocationEngine) { @@ -768,15 +808,19 @@ public final class LocationComponent { locationCameraController = new LocationCameraController( context, mapboxMap, cameraTrackingChangedListener, options, onCameraMoveInvalidateListener); - locationAnimatorCoordinator = new LocationAnimatorCoordinator(); + locationAnimatorCoordinator = new LocationAnimatorCoordinator( + mapboxMap.getProjection(), + MapboxAnimatorSetProvider.getInstance() + ); locationAnimatorCoordinator.addLayerListener(locationLayerController); locationAnimatorCoordinator.addCameraListener(locationCameraController); locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options.trackingAnimationDurationMultiplier()); WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - compassEngine = new LocationComponentCompassEngine(windowManager, sensorManager); - compassEngine.addCompassListener(compassListener); + if (windowManager != null && sensorManager != null) { + compassEngine = new LocationComponentCompassEngine(windowManager, sensorManager); + } staleStateManager = new StaleStateManager(onLocationStaleListener, options); updateMapWithOptions(options); @@ -804,6 +848,38 @@ public final class LocationComponent { locationEngine.activate(); } + private void updateCompassListenerState(boolean canListen) { + if (compassEngine != null) { + if (!canListen) { + // We shouldn't listen, simply unregistering + removeCompassListener(compassEngine); + return; + } + + if (!isInitialized || !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(); @@ -815,9 +891,12 @@ public final class LocationComponent { } private void updateMapWithOptions(final LocationComponentOptions options) { - mapboxMap.setPadding( - options.padding()[0], options.padding()[1], options.padding()[2], options.padding()[3] - ); + int[] padding = options.padding(); + if (padding != null) { + mapboxMap.setPadding( + padding[0], padding[1], padding[2], padding[3] + ); + } mapboxMap.setMaxZoomPreference(options.maxZoom()); mapboxMap.setMinZoomPreference(options.minZoom()); @@ -869,7 +948,7 @@ public final class LocationComponent { } private void setLastCompassHeading() { - updateCompassHeading(compassEngine.getLastHeading()); + updateCompassHeading(compassEngine != null ? compassEngine.getLastHeading() : 0); } @SuppressLint("MissingPermission") diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index b53d909de3..6db307369a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -10,6 +10,8 @@ import android.support.annotation.Nullable; import android.view.Surface; import android.view.WindowManager; +import com.mapbox.mapboxsdk.log.Logger; + import java.util.ArrayList; import java.util.List; @@ -21,15 +23,18 @@ import timber.log.Timber; */ class LocationComponentCompassEngine implements CompassEngine, SensorEventListener { + private static final String TAG = "Mbgl-LocationComponentCompassEngine"; + // The rate sensor events will be delivered at. As the Android documentation states, this is only // a hint to the system and the events might actually be received faster or slower then this // specified rate. Since the minimum Android API levels about 9, we are able to set this value // ourselves rather than using one of the provided constants which deliver updates too quickly for // our use case. The default is set to 100ms - private static final int SENSOR_DELAY_MICROS = 100 * 1000; + static final int SENSOR_DELAY_MICROS = 100 * 1000; // Filtering coefficient 0 < ALPHA < 1 private static final float ALPHA = 0.45f; + @NonNull private final WindowManager windowManager; private final SensorManager sensorManager; private final List<CompassListener> compassListeners = new ArrayList<>(); @@ -56,7 +61,7 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen * Construct a new instance of the this class. A internal compass listeners needed to separate it * from the cleared list of public listeners. */ - LocationComponentCompassEngine(WindowManager windowManager, SensorManager sensorManager) { + LocationComponentCompassEngine(@NonNull WindowManager windowManager, @NonNull SensorManager sensorManager) { this.windowManager = windowManager; this.sensorManager = sensorManager; compassSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); @@ -75,7 +80,7 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen @Override public void addCompassListener(@NonNull CompassListener compassListener) { if (compassListeners.isEmpty()) { - onStart(); + registerSensorListeners(); } compassListeners.add(compassListener); } @@ -84,7 +89,7 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen public void removeCompassListener(@NonNull CompassListener compassListener) { compassListeners.remove(compassListener); if (compassListeners.isEmpty()) { - onStop(); + unregisterSensorListeners(); } } @@ -100,12 +105,16 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen @Override public void onStart() { - registerSensorListeners(); + if (!compassListeners.isEmpty()) { + registerSensorListeners(); + } } @Override public void onStop() { - unregisterSensorListeners(); + if (!compassListeners.isEmpty()) { + unregisterSensorListeners(); + } } @Override @@ -116,15 +125,12 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen return; } if (lastAccuracySensorStatus == SensorManager.SENSOR_STATUS_UNRELIABLE) { - Timber.d("Compass sensor is unreliable, device calibration is needed."); + Logger.d(TAG, "Compass sensor is unreliable, device calibration is needed."); return; } if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { rotationVectorValue = getRotationVectorFromSensorEvent(event); updateOrientation(); - - // Update the compassUpdateNextTimestamp - compassUpdateNextTimestamp = currentTime + LocationComponentConstants.COMPASS_UPDATE_RATE_MS; } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { notifyCompassChangeListeners((event.values[0] + 360) % 360); } else if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { @@ -134,6 +140,9 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen magneticValues = lowPassFilter(getRotationVectorFromSensorEvent(event), magneticValues); updateOrientation(); } + + // Update the compassUpdateNextTimestamp + compassUpdateNextTimestamp = currentTime + LocationComponentConstants.COMPASS_UPDATE_RATE_MS; } @Override @@ -233,7 +242,8 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen * @param smoothedValues array of float, that contains previous state * @return float filtered array of float */ - private float[] lowPassFilter(float[] newValues, float[] smoothedValues) { + @NonNull + private float[] lowPassFilter(@NonNull float[] newValues, @Nullable float[] smoothedValues) { if (smoothedValues == null) { return newValues; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java index 4376ef4e60..135534460a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java @@ -6,7 +6,7 @@ package com.mapbox.mapboxsdk.location; final class LocationComponentConstants { // Controls the compass update rate in milliseconds - static final int COMPASS_UPDATE_RATE_MS = 500; + static final long COMPASS_UPDATE_RATE_MS = 500; // Sets the transition animation duration when switching camera modes. static final long TRANSITION_ANIMATION_DURATION_MS = 750; @@ -24,7 +24,7 @@ final class LocationComponentConstants { static final long DEFAULT_TRACKING_TILT_ANIM_DURATION = 1250; // Threshold value to perform immediate camera/layer position update. - static final double INSTANT_LOCATION_TRANSITION_THRESHOLD = 500_000; + static final double INSTANT_LOCATION_TRANSITION_THRESHOLD = 50_000; // Sources static final String LOCATION_SOURCE = "mapbox-location-source"; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java index 10dfff8694..58b86c7b3a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java @@ -111,6 +111,8 @@ public class LocationComponentOptions implements Parcelable { private float trackingMultiFingerMoveThreshold; private String layerBelow; private float trackingAnimationDurationMultiplier; + private boolean compassAnimationEnabled; + private boolean accuracyAnimationEnabled; public LocationComponentOptions( float accuracyAlpha, @@ -144,7 +146,9 @@ public class LocationComponentOptions implements Parcelable { float trackingInitialMoveThreshold, float trackingMultiFingerMoveThreshold, String layerBelow, - float trackingAnimationDurationMultiplier) { + float trackingAnimationDurationMultiplier, + boolean compassAnimationEnabled, + boolean accuracyAnimationEnabled) { this.accuracyAlpha = accuracyAlpha; this.accuracyColor = accuracyColor; this.backgroundDrawableStale = backgroundDrawableStale; @@ -180,6 +184,8 @@ public class LocationComponentOptions implements Parcelable { this.trackingMultiFingerMoveThreshold = trackingMultiFingerMoveThreshold; this.layerBelow = layerBelow; this.trackingAnimationDurationMultiplier = trackingAnimationDurationMultiplier; + this.compassAnimationEnabled = compassAnimationEnabled; + this.accuracyAnimationEnabled = accuracyAnimationEnabled; } /** @@ -304,6 +310,14 @@ public class LocationComponentOptions implements Parcelable { ); builder.trackingAnimationDurationMultiplier(trackingAnimationDurationMultiplier); + builder.compassAnimationEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_compassAnimationEnabled, true + ); + + builder.accuracyAnimationEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_accuracyAnimationEnabled, true + ); + typedArray.recycle(); return builder.build(); @@ -723,6 +737,26 @@ public class LocationComponentOptions implements Parcelable { return trackingAnimationDurationMultiplier; } + /** + * Enable or disable smooth animation of compass values for {@link com.mapbox.mapboxsdk.location.modes.CameraMode} + * and {@link com.mapbox.mapboxsdk.location.modes.RenderMode}. + * + * @return whether smooth compass animation is enabled + */ + public boolean compassAnimationEnabled() { + return compassAnimationEnabled; + } + + /** + * Enable or disable smooth animation of the accuracy circle around the user's position. + * + * @return whether smooth animation of the accuracy circle is enabled + */ + public boolean accuracyAnimationEnabled() { + return accuracyAnimationEnabled; + } + + @NonNull @Override public String toString() { return "LocationComponentOptions{" @@ -882,6 +916,10 @@ public class LocationComponentOptions implements Parcelable { h$ ^= Float.floatToIntBits(trackingMultiFingerMoveThreshold); h$ *= 1000003; h$ ^= Float.floatToIntBits(trackingAnimationDurationMultiplier); + h$ *= 1000003; + h$ ^= compassAnimationEnabled ? 1231 : 1237; + h$ *= 1000003; + h$ ^= accuracyAnimationEnabled ? 1231 : 1237; return h$; } @@ -921,7 +959,9 @@ public class LocationComponentOptions implements Parcelable { in.readFloat(), in.readFloat(), in.readString(), - in.readFloat() + in.readFloat(), + in.readInt() == 1, + in.readInt() == 1 ); } @@ -1020,6 +1060,8 @@ public class LocationComponentOptions implements Parcelable { dest.writeFloat(trackingMultiFingerMoveThreshold()); dest.writeString(layerBelow()); dest.writeFloat(trackingAnimationDurationMultiplier); + dest.writeInt(compassAnimationEnabled() ? 1 : 0); + dest.writeInt(accuracyAnimationEnabled() ? 1 : 0); } @Override @@ -1084,6 +1126,8 @@ public class LocationComponentOptions implements Parcelable { private Float trackingMultiFingerMoveThreshold; private String layerBelow; private Float trackingAnimationDurationMultiplier; + private Boolean compassAnimationEnabled; + private Boolean accuracyAnimationEnabled; Builder() { } @@ -1121,6 +1165,8 @@ public class LocationComponentOptions implements Parcelable { this.trackingMultiFingerMoveThreshold = source.trackingMultiFingerMoveThreshold(); this.layerBelow = source.layerBelow(); this.trackingAnimationDurationMultiplier = source.trackingAnimationDurationMultiplier(); + this.compassAnimationEnabled = source.compassAnimationEnabled(); + this.accuracyAnimationEnabled = source.accuracyAnimationEnabled(); } /** @@ -1556,6 +1602,28 @@ public class LocationComponentOptions implements Parcelable { return this; } + /** + * Enable or disable smooth animation of compass values for {@link com.mapbox.mapboxsdk.location.modes.CameraMode} + * and {@link com.mapbox.mapboxsdk.location.modes.RenderMode}. + * + * @return whether smooth compass animation is enabled + */ + public LocationComponentOptions.Builder compassAnimationEnabled(Boolean compassAnimationEnabled) { + this.compassAnimationEnabled = compassAnimationEnabled; + return this; + } + + /** + * Enable or disable smooth animation of the accuracy circle around the user's position. + * + * @return whether smooth animation of the accuracy circle is enabled + */ + public Builder accuracyAnimationEnabled(Boolean accuracyAnimationEnabled) { + this.accuracyAnimationEnabled = accuracyAnimationEnabled; + return this; + } + + @Nullable LocationComponentOptions autoBuild() { String missing = ""; if (this.accuracyAlpha == null) { @@ -1653,7 +1721,9 @@ public class LocationComponentOptions implements Parcelable { this.trackingInitialMoveThreshold, this.trackingMultiFingerMoveThreshold, this.layerBelow, - this.trackingAnimationDurationMultiplier); + this.trackingAnimationDurationMultiplier, + this.compassAnimationEnabled, + this.accuracyAnimationEnabled); } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index da3144eea1..fc4dd1d872 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -11,8 +11,8 @@ import com.google.gson.JsonObject; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; @@ -192,6 +192,10 @@ final class LocationLayerController implements MapboxAnimator.OnLayerAnimationsV return isHidden; } + boolean isConsumingCompass() { + return renderMode == RenderMode.COMPASS; + } + private void setLayerVisibility(String layerId, boolean visible) { Layer layer = mapboxMap.getLayer(layerId); if (layer != null) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java new file mode 100644 index 0000000000..1d09f8ae71 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java @@ -0,0 +1,32 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.support.annotation.NonNull; +import android.view.animation.Interpolator; + +import java.util.List; + +class MapboxAnimatorSetProvider { + private static MapboxAnimatorSetProvider instance; + + private MapboxAnimatorSetProvider() { + // private constructor + } + + static MapboxAnimatorSetProvider getInstance() { + if (instance == null) { + instance = new MapboxAnimatorSetProvider(); + } + return instance; + } + + void startAnimation(@NonNull List<Animator> animators, @NonNull Interpolator interpolator, + long duration) { + AnimatorSet locationAnimatorSet = new AnimatorSet(); + locationAnimatorSet.playTogether(animators); + locationAnimatorSet.setInterpolator(interpolator); + locationAnimatorSet.setDuration(duration); + locationAnimatorSet.start(); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java index 553678709e..45911a99b3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java @@ -14,7 +14,11 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD; public final class Utils { @@ -88,6 +92,12 @@ public final class Utils { return (float) (location.getAccuracy() * (1 / metersPerPixel)); } + static boolean immediateAnimation(@NonNull Projection projection, @NonNull LatLng current, @NonNull LatLng target) { + double metersPerPixel = projection.getMetersPerPixelAtLatitude((current.getLatitude() + target.getLatitude()) / 2); + double distance = current.distanceTo(target); + return distance / metersPerPixel > INSTANT_LOCATION_TRANSITION_THRESHOLD; + } + /** * Casts the value to an even integer. */ |