diff --git a/app/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerTest.kt b/app/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerTest.kt index f4d521559..3e43ebee1 100644 --- a/app/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerTest.kt +++ b/app/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerTest.kt @@ -271,7 +271,7 @@ class LocationLayerTest { mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0)) uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) plugin.forceLocationUpdate(location) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY + ACCURACY_RADIUS_ANIMATION_DURATION) assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0] diff --git a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayer.java b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayer.java index 7d689b5b8..37a3f6e85 100644 --- a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayer.java +++ b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayer.java @@ -4,7 +4,6 @@ import android.content.Context; import android.graphics.PointF; import android.graphics.drawable.Drawable; -import android.location.Location; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -48,7 +47,6 @@ import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.PROPERTY_SHADOW_ICON_OFFSET; import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.SHADOW_ICON; import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.SHADOW_LAYER; -import static com.mapbox.mapboxsdk.plugins.locationlayer.Utils.calculateZoomLevelRadius; import static com.mapbox.mapboxsdk.plugins.locationlayer.Utils.generateShadow; import static com.mapbox.mapboxsdk.plugins.locationlayer.Utils.getBitmapFromDrawable; import static com.mapbox.mapboxsdk.plugins.locationlayer.Utils.getDrawable; @@ -262,9 +260,9 @@ private void setBearingProperty(String propertyId, float bearing) { refreshSource(); } - void updateAccuracyRadius(Location location) { + void updateAccuracyRadius(float accuracy) { if (renderMode == RenderMode.COMPASS || renderMode == RenderMode.NORMAL) { - locationFeature.addNumberProperty(PROPERTY_ACCURACY_RADIUS, calculateZoomLevelRadius(mapboxMap, location)); + locationFeature.addNumberProperty(PROPERTY_ACCURACY_RADIUS, accuracy); refreshSource(); } } @@ -442,4 +440,9 @@ public void onNewCompassBearingValue(float compassBearing) { setBearingProperty(PROPERTY_COMPASS_BEARING, compassBearing); } } + + @Override + public void onNewAccuracyRadiusValue(float accuracyRadiusValue) { + updateAccuracyRadius(accuracyRadiusValue); + } } \ No newline at end of file diff --git a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerAnimator.java b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerAnimator.java index 416583081..eb345031d 100644 --- a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerAnimator.java +++ b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerAnimator.java @@ -10,12 +10,14 @@ import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.plugins.locationlayer.camera.AccuracyAnimator; import com.mapbox.mapboxsdk.plugins.locationlayer.camera.BearingAnimator; import com.mapbox.mapboxsdk.plugins.locationlayer.camera.LatLngAnimator; import java.util.ArrayList; import java.util.List; +import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.ACCURACY_RADIUS_ANIMATION_DURATION; import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.COMPASS_UPDATE_RATE_MS; import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.MAX_ANIMATION_DURATION_MS; import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.TRANSITION_ANIMATION_DURATION_MS; @@ -28,12 +30,14 @@ final class LocationLayerAnimator { private LatLngAnimator layerLatLngAnimator; private BearingAnimator layerGpsBearingAnimator; private BearingAnimator layerCompassBearingAnimator; + private AccuracyAnimator accuracyRadiusAnimator; private LatLngAnimator cameraLatLngAnimator; private BearingAnimator cameraGpsBearingAnimator; private BearingAnimator cameraCompassBearingAnimator; private Location previousLocation; + private float previousAccuracyRadius = -1; private float previousCompassBearing = -1; private long locationUpdateTimestamp = -1; @@ -92,6 +96,19 @@ void feedNewCompassBearing(float targetCompassBearing, @NonNull CameraPosition c previousCompassBearing = targetCompassBearing; } + void feedNewAccuracyRadius(float targetAccuracyRadius, boolean noAnimation) { + if (previousAccuracyRadius < 0) { + previousAccuracyRadius = targetAccuracyRadius; + } + + float previousAccuracyRadius = getPreviousAccuracyRadius(); + updateAccuracyAnimators(targetAccuracyRadius, previousAccuracyRadius); + accuracyRadiusAnimator.setDuration(noAnimation ? 0 : ACCURACY_RADIUS_ANIMATION_DURATION); + accuracyRadiusAnimator.start(); + + this.previousAccuracyRadius = targetAccuracyRadius; + } + private final ValueAnimator.AnimatorUpdateListener layerLatLngUpdateListener = new ValueAnimator.AnimatorUpdateListener() { @Override @@ -122,6 +139,16 @@ public void onAnimationUpdate(ValueAnimator valueAnimator) { } }; + private final ValueAnimator.AnimatorUpdateListener accuracyRadiusUpdateListener = + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + for (OnLayerAnimationsValuesChangeListener listener : layerListeners) { + listener.onNewAccuracyRadiusValue((Float) valueAnimator.getAnimatedValue()); + } + } + }; + private final ValueAnimator.AnimatorUpdateListener cameraLatLngUpdateListener = new ValueAnimator.AnimatorUpdateListener() { @Override @@ -158,6 +185,8 @@ interface OnLayerAnimationsValuesChangeListener { void onNewGpsBearingValue(float gpsBearing); void onNewCompassBearingValue(float compassBearing); + + void onNewAccuracyRadiusValue(float accuracyRadiusValue); } interface OnCameraAnimationsValuesChangeListener { @@ -177,6 +206,7 @@ void resetAllCameraAnimations(CameraPosition currentCameraPosition, boolean isGp void cancelAllAnimations() { cancelLayerLocationAnimations(); cancelLayerCompassAnimations(); + cancelAccuracyRadiusAnimations(); cancelCameraLocationAnimations(); cancelCameraCompassAnimations(); } @@ -201,6 +231,16 @@ private float getPreviousLayerGpsBearing() { return previousBearing; } + private float getPreviousAccuracyRadius() { + float previousRadius; + if (accuracyRadiusAnimator != null) { + previousRadius = (float) accuracyRadiusAnimator.getAnimatedValue(); + } else { + previousRadius = previousAccuracyRadius; + } + return previousRadius; + } + private float getPreviousLayerCompassBearing() { float previousBearing; if (layerCompassBearingAnimator != null) { @@ -304,6 +344,15 @@ private void playCompassAnimators(long duration) { compassAnimatorSet.start(); } + private void updateAccuracyAnimators(float targetAccuracyRadius, float previousAccuracyRadius) { + cancelAccuracyRadiusAnimations(); + accuracyRadiusAnimator = new AccuracyAnimator(previousAccuracyRadius, targetAccuracyRadius); + accuracyRadiusAnimator.addUpdateListener(accuracyRadiusUpdateListener); + } + + private void playAccuracyRadiusAnimation(long duration) { + } + private void cancelLayerLocationAnimations() { cancelLayerLatLngAnimations(); cancelLayerGpsBearingAnimations(); @@ -323,6 +372,13 @@ private void cancelLayerGpsBearingAnimations() { } } + private void cancelAccuracyRadiusAnimations() { + if (accuracyRadiusAnimator != null) { + accuracyRadiusAnimator.cancel(); + accuracyRadiusAnimator.removeAllUpdateListeners(); + } + } + private void cancelLayerCompassAnimations() { if (layerCompassBearingAnimator != null) { layerCompassBearingAnimator.cancel(); diff --git a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerConstants.java b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerConstants.java index 71a5fc398..5bfe0e217 100644 --- a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerConstants.java +++ b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerConstants.java @@ -16,6 +16,9 @@ final class LocationLayerConstants { // Sets the max allowed time for the location icon animation from one LatLng to another. static final long MAX_ANIMATION_DURATION_MS = 2000; + // Sets the duration of change of accuracy radius when a different value is provided. + static final long ACCURACY_RADIUS_ANIMATION_DURATION = 250; + // Sources static final String LOCATION_SOURCE = "mapbox-location-source"; static final String PROPERTY_GPS_BEARING = "mapbox-property-gps-bearing"; diff --git a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerPlugin.java b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerPlugin.java index 761c676ac..2c39a4a8a 100644 --- a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerPlugin.java +++ b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerPlugin.java @@ -616,7 +616,7 @@ private void updateLocation(final Location location) { CameraPosition currentCameraPosition = mapboxMap.getCameraPosition(); boolean isGpsNorth = getCameraMode() == CameraMode.TRACKING_GPS_NORTH; locationLayerAnimator.feedNewLocation(location, currentCameraPosition, isGpsNorth); - locationLayer.updateAccuracyRadius(location); + updateAccuracyRadius(location, false); lastLocation = location; } @@ -646,7 +646,7 @@ private void updateLayerOffsets(boolean forceUpdate) { lastCameraPosition = position; locationLayer.updateForegroundBearing((float) position.bearing); locationLayer.updateForegroundOffset(position.tilt); - locationLayer.updateAccuracyRadius(getLastKnownLocation()); + updateAccuracyRadius(getLastKnownLocation(), true); return; } @@ -657,11 +657,15 @@ private void updateLayerOffsets(boolean forceUpdate) { locationLayer.updateForegroundOffset(position.tilt); } if (position.zoom != lastCameraPosition.zoom) { - locationLayer.updateAccuracyRadius(getLastKnownLocation()); + updateAccuracyRadius(getLastKnownLocation(), true); } lastCameraPosition = position; } + private void updateAccuracyRadius(Location location, boolean noAnimation) { + locationLayerAnimator.feedNewAccuracyRadius(Utils.calculateZoomLevelRadius(mapboxMap, location), noAnimation); + } + private OnCameraMoveListener onCameraMoveListener = new OnCameraMoveListener() { @Override public void onCameraMove() { diff --git a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/Utils.java b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/Utils.java index 5b341e6e6..776daf5ec 100644 --- a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/Utils.java +++ b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/Utils.java @@ -11,6 +11,7 @@ import android.support.annotation.ColorInt; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -80,7 +81,7 @@ static Drawable getDrawable(@NonNull Context context, @DrawableRes int drawableR return drawable; } - static float calculateZoomLevelRadius(MapboxMap mapboxMap, Location location) { + static float calculateZoomLevelRadius(@NonNull MapboxMap mapboxMap, @Nullable Location location) { if (location == null) { return 0; } diff --git a/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/camera/AccuracyAnimator.java b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/camera/AccuracyAnimator.java new file mode 100644 index 000000000..37982978b --- /dev/null +++ b/plugin-locationlayer/src/main/java/com/mapbox/mapboxsdk/plugins/locationlayer/camera/AccuracyAnimator.java @@ -0,0 +1,12 @@ +package com.mapbox.mapboxsdk.plugins.locationlayer.camera; + +import android.animation.FloatEvaluator; +import android.animation.ValueAnimator; + +public class AccuracyAnimator extends ValueAnimator { + + public AccuracyAnimator(float previous, float target) { + setEvaluator(new FloatEvaluator()); + setFloatValues(previous, target); + } +} \ No newline at end of file