diff options
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main')
14 files changed, 667 insertions, 9 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java index cac513c2f9..1ff3583b5c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LayerSourceProvider.java @@ -27,6 +27,7 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PULSING_CIRCLE_LAYER; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; import static com.mapbox.mapboxsdk.style.expressions.Expression.get; @@ -108,4 +109,18 @@ class LayerSourceProvider { circlePitchAlignment(Property.CIRCLE_PITCH_ALIGNMENT_MAP) ); } + + /** + * Adds a {@link CircleLayer} to the map to support the {@link LocationComponent} pulsing UI functionality. + * + * @return a {@link CircleLayer} with the correct data-driven styling. Tilting the map will keep the pulsing + * layer aligned with the map plane. + */ + @NonNull + Layer generatePulsingCircleLayer() { + return new CircleLayer(PULSING_CIRCLE_LAYER, LOCATION_SOURCE) + .withProperties( + circlePitchAlignment(Property.CIRCLE_PITCH_ALIGNMENT_MAP) + ); + } } 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 5aad038a28..a522fbaaa1 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 @@ -30,6 +30,7 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_ACCURA import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_COMPASS_BEARING; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BEARING; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG; +import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_PULSING_CIRCLE; 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; @@ -51,6 +52,7 @@ final class LocationAnimatorCoordinator { private final MapboxAnimatorSetProvider animatorSetProvider; private boolean compassAnimationEnabled; private boolean accuracyAnimationEnabled; + private LocationComponentOptions locationComponentOptions; @VisibleForTesting int maxAnimationFps = Integer.MAX_VALUE; @@ -59,10 +61,12 @@ final class LocationAnimatorCoordinator { final SparseArray<MapboxAnimator.AnimationsValueChangeListener> listeners = new SparseArray<>(); LocationAnimatorCoordinator(@NonNull Projection projection, @NonNull MapboxAnimatorSetProvider animatorSetProvider, - @NonNull MapboxAnimatorProvider animatorProvider) { + @NonNull MapboxAnimatorProvider animatorProvider, + @NonNull LocationComponentOptions locationComponentOptions) { this.projection = projection; this.animatorProvider = animatorProvider; this.animatorSetProvider = animatorSetProvider; + this.locationComponentOptions = locationComponentOptions; } void updateAnimatorListenerHolders(@NonNull Set<AnimatorListenerHolder> listenerHolders) { @@ -150,6 +154,29 @@ final class LocationAnimatorCoordinator { this.previousAccuracyRadius = targetAccuracyRadius; } + /** + * Initializes the {@link PulsingLocationCircleAnimator}, which is a type of {@link MapboxAnimator}. + * This method also adds the animator to this class' animator array. + * + * @param options the {@link LocationComponentOptions} passed to this class upstream from the + * {@link LocationComponent}. + */ + void startLocationComponentCirclePulsing(LocationComponentOptions options) { + cancelAnimator(ANIMATOR_PULSING_CIRCLE); + MapboxAnimator.AnimationsValueChangeListener listener = listeners.get(ANIMATOR_PULSING_CIRCLE); + locationComponentOptions = options; + PulsingLocationCircleAnimator pulsingLocationCircleAnimator = animatorProvider.pulsingCircleAnimator( + listener, + maxAnimationFps, + locationComponentOptions.pulseSingleDuration(), + locationComponentOptions.pulseMaxRadius(), + locationComponentOptions.pulseInterpolator()); + if (listener != null) { + animatorArray.put(ANIMATOR_PULSING_CIRCLE, pulsingLocationCircleAnimator); + } + playPulsingAnimator(); + } + void feedNewZoomLevel(double targetZoomLevel, @NonNull CameraPosition currentCameraPosition, long animationDuration, @Nullable MapboxMap.CancelableCallback callback) { updateZoomAnimator((float) targetZoomLevel, (float) currentCameraPosition.zoom, callback); @@ -292,6 +319,18 @@ final class LocationAnimatorCoordinator { animatorSetProvider.startAnimation(animators, new LinearInterpolator(), duration); } + /** + * Starts the {@link PulsingLocationCircleAnimator} in the animator array. This method is separate + * from {@link #playAnimators(long, int...)} because the MapboxAnimatorSetProvider has many more + * customizable animation parameters than the other {@link MapboxAnimator}s. + */ + private void playPulsingAnimator() { + Animator animator = animatorArray.get(ANIMATOR_PULSING_CIRCLE); + if (animator != null) { + animatorSetProvider.startSingleAnimation(animator); + } + } + void resetAllCameraAnimations(@NonNull CameraPosition currentCameraPosition, boolean isGpsNorth) { resetCameraCompassAnimation(currentCameraPosition); boolean snap = resetCameraLocationAnimations(currentCameraPosition, isGpsNorth); @@ -383,6 +422,13 @@ final class LocationAnimatorCoordinator { cancelAnimator(ANIMATOR_TILT); } + /** + * Cancel's the pulsing circle location animator. + */ + void cancelPulsingCircleAnimation() { + cancelAnimator(ANIMATOR_PULSING_CIRCLE); + } + void cancelAllAnimations() { for (int i = 0; i < animatorArray.size(); i++) { @MapboxAnimator.Type int animatorType = animatorArray.keyAt(i); 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 8b014b0e9c..5bd2268e43 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 @@ -710,17 +710,26 @@ public final class LocationComponent { 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()); + if (options.pulseEnabled()) { + startPulsingLocationCircle(); + } updateMapWithOptions(options); } } /** + * Starts the LocationComponent's pulsing circle UI. + */ + public void startPulsingLocationCircle() { + locationAnimatorCoordinator.startLocationComponentCirclePulsing(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, @@ -1177,6 +1186,14 @@ public final class LocationComponent { } } + /** + * Available to cancel the specific pulsing circle animation. + */ + public void cancelPulsingLocationCircle() { + locationAnimatorCoordinator.cancelPulsingCircleAnimation(); + locationLayerController.adjustPulsingCircleLayerVisibility(false); + } + @SuppressLint("MissingPermission") private void onLocationLayerStart() { if (!isComponentInitialized || !isComponentStarted || mapboxMap.getStyle() == null) { @@ -1202,6 +1219,9 @@ public final class LocationComponent { } } setCameraMode(locationCameraController.getCameraMode()); + if (options.pulseEnabled()) { + startPulsingLocationCircle(); + } setLastLocation(); updateCompassListenerState(true); setLastCompassHeading(); @@ -1254,7 +1274,7 @@ public final class LocationComponent { locationAnimatorCoordinator = new LocationAnimatorCoordinator( mapboxMap.getProjection(), MapboxAnimatorSetProvider.getInstance(), - MapboxAnimatorProvider.getInstance() + MapboxAnimatorProvider.getInstance(), options ); locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options .trackingAnimationDurationMultiplier()); @@ -1369,6 +1389,9 @@ public final class LocationComponent { boolean isLocationLayerHidden = locationLayerController.isHidden(); if (isEnabled && isComponentStarted && isLocationLayerHidden) { locationLayerController.show(); + if (options.pulseEnabled()) { + locationLayerController.adjustPulsingCircleLayerVisibility(true); + } } } 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 f2158584c7..baba5eaca4 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 @@ -52,6 +52,8 @@ public final class LocationComponentConstants { static final String PROPERTY_FOREGROUND_STALE_ICON = "mapbox-property-foreground-stale-icon"; static final String PROPERTY_BACKGROUND_STALE_ICON = "mapbox-property-background-stale-icon"; static final String PROPERTY_BEARING_ICON = "mapbox-property-shadow-icon"; + static final String PROPERTY_PULSING_RADIUS = "mapbox-property-pulsing-circle-radius"; + static final String PROPERTY_PULSING_OPACITY = "mapbox-property-pulsing-circle-opacity"; // Layers @@ -80,6 +82,11 @@ public final class LocationComponentConstants { */ public static final String BEARING_LAYER = "mapbox-location-bearing-layer"; + /** + * Layer ID of the location pulsing circle. + */ + public static final String PULSING_CIRCLE_LAYER = "mapbox-location-pulsing-circle-layer"; + // Icons static final String FOREGROUND_ICON = "mapbox-location-icon"; static final String BACKGROUND_ICON = "mapbox-location-stroke-icon"; 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 48c89622cd..dfadd9f0ae 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 @@ -14,6 +14,7 @@ import android.support.annotation.StyleRes; import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.location.modes.PulseMode; import com.mapbox.mapboxsdk.style.layers.Layer; import java.util.Arrays; @@ -69,6 +70,21 @@ public class LocationComponentOptions implements Parcelable { */ private static final float TRACKING_ANIMATION_DURATION_MULTIPLIER_DEFAULT = 1.1f; + /** + * Default duration of a single LocationComponent circle pulse. + */ + private static final long CIRCLE_PULSING_DURATION_DEFAULT_MS = 2300; + + /** + * Default opacity of the LocationComponent circle when it ends a single pulse. + */ + private static final float CIRCLE_PULSING_ALPHA_DEFAULT = 1f; + + /** + * Default maximum radius of the LocationComponent circle when it's pulsing. + */ + public static final float CIRCLE_PULSING_MAX_RADIUS_DEFAULT = 35f; + private float accuracyAlpha; private int accuracyColor; private int backgroundDrawableStale; @@ -114,6 +130,13 @@ public class LocationComponentOptions implements Parcelable { private float trackingAnimationDurationMultiplier; private boolean compassAnimationEnabled; private boolean accuracyAnimationEnabled; + private Boolean pulsingCircleEnabled; + private Boolean pulsingCircleFadeEnabled; + private Integer pulseColor; + private float pulseSingleDuration; + private float pulsingCircleMaxRadius; + private float pulseAlpha; + private String pulseInterpolator; public LocationComponentOptions( float accuracyAlpha, @@ -148,7 +171,14 @@ public class LocationComponentOptions implements Parcelable { String layerBelow, float trackingAnimationDurationMultiplier, boolean compassAnimationEnabled, - boolean accuracyAnimationEnabled) { + boolean accuracyAnimationEnabled, + Boolean pulsingCircleEnabled, + Boolean pulsingCircleFadeEnabled, + Integer pulsingCircleColor, + float pulsingCircleDuration, + float pulsingCircleMaxRadius, + float pulsingCircleAlpha, + String pulsingCircleInterpolator) { this.accuracyAlpha = accuracyAlpha; this.accuracyColor = accuracyColor; this.backgroundDrawableStale = backgroundDrawableStale; @@ -185,6 +215,13 @@ public class LocationComponentOptions implements Parcelable { this.trackingAnimationDurationMultiplier = trackingAnimationDurationMultiplier; this.compassAnimationEnabled = compassAnimationEnabled; this.accuracyAnimationEnabled = accuracyAnimationEnabled; + this.pulsingCircleEnabled = pulsingCircleEnabled; + this.pulsingCircleFadeEnabled = pulsingCircleFadeEnabled; + this.pulseColor = pulsingCircleColor; + this.pulseSingleDuration = pulsingCircleDuration; + this.pulsingCircleMaxRadius = pulsingCircleMaxRadius; + this.pulseAlpha = pulsingCircleAlpha; + this.pulseInterpolator = pulsingCircleInterpolator; } /** @@ -302,6 +339,35 @@ public class LocationComponentOptions implements Parcelable { R.styleable.mapbox_LocationComponent_mapbox_accuracyAnimationEnabled, true ); + builder.pulsingCircleEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleEnabled, false + ); + + builder.pulsingCircleFadeEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleFadeEnabled, true + ); + + if (typedArray.hasValue(R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleColor)) { + builder.pulsingCircleColor(typedArray.getColor( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleColor, + -1)); + } + + builder.pulsingCircleDuration = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleDuration, CIRCLE_PULSING_DURATION_DEFAULT_MS + ); + + builder.pulsingCircleMaxRadius = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleRadius, CIRCLE_PULSING_MAX_RADIUS_DEFAULT + ); + + builder.pulsingCircleAlpha = typedArray.getFloat( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleAlpha, CIRCLE_PULSING_ALPHA_DEFAULT + ); + + builder.pulsingCircleInterpolator = typedArray.getString( + R.styleable.mapbox_LocationComponent_mapbox_pulsingLocationCircleInterpolator); + typedArray.recycle(); return builder.build(); @@ -740,6 +806,70 @@ public class LocationComponentOptions implements Parcelable { return accuracyAnimationEnabled; } + /** + * Enable or disable the LocationComponent's pulsing circle. + * + * @return whether the LocationComponent's pulsing circle is enabled + */ + public Boolean pulseEnabled() { + return pulsingCircleEnabled; + } + + /** + * Enable or disable fading of the LocationComponent's pulsing circle. If it fades, the circle's + * opacity decreases as its radius increases. + * + * @return whether fading of the LocationComponent's pulsing circle is enabled + */ + public Boolean pulsingCircleFadeEnabled() { + return pulsingCircleFadeEnabled; + } + + /** + * Color of the LocationComponent's pulsing circle as it pulses. + * + * @return the current set color of the circle + */ + public Integer pulseColor() { + return pulseColor; + } + + /** + * The number of milliseconds it takes for a single pulse of the LocationComponent's pulsing circle. + * + * @return the current set length of time for a single pulse + */ + public float pulseSingleDuration() { + return pulseSingleDuration; + } + + /** + * The maximum radius that a single pulse should expand the LocationComponent's pulsing circle to. + * + * @return the maximum radius that the pulsing circle will expand to. + */ + public float pulseMaxRadius() { + return pulsingCircleMaxRadius; + } + + /** + * The opacity of the LocationComponent's circle as it pulses. + * + * @return the current set opacity of the LocationComponent's circle + */ + public float pulseAlpha() { + return pulseAlpha; + } + + /** + * The interpolator type of animation for the movement of the LocationComponent's circle + * + * @return the current set type of animation interpolator for the pulsing circle + */ + public String pulseInterpolator() { + return pulseInterpolator; + } + @NonNull @Override public String toString() { @@ -775,6 +905,13 @@ public class LocationComponentOptions implements Parcelable { + "layerAbove=" + layerAbove + "layerBelow=" + layerBelow + "trackingAnimationDurationMultiplier=" + trackingAnimationDurationMultiplier + + "pulsingCircleEnabled=" + pulsingCircleEnabled + + "pulsingCircleFadeEnabled=" + pulsingCircleFadeEnabled + + "pulseColor=" + pulseColor + + "pulseSingleDuration=" + pulseSingleDuration + + "pulsingCircleMaxRadius=" + pulsingCircleMaxRadius + + "pulseAlpha=" + pulseAlpha + + "pulseInterpolator=" + pulseInterpolator + "}"; } @@ -892,6 +1029,36 @@ public class LocationComponentOptions implements Parcelable { if (layerAbove != null ? !layerAbove.equals(options.layerAbove) : options.layerAbove != null) { return false; } + + if (pulsingCircleEnabled != options.pulsingCircleEnabled) { + return false; + } + + if (pulsingCircleFadeEnabled != options.pulsingCircleFadeEnabled) { + return false; + } + + if (pulseColor != null ? !pulseColor.equals(options.pulseColor) : + options.pulseColor() != null) { + return false; + } + if (Float.compare(options.pulseSingleDuration, pulseSingleDuration) != 0) { + return false; + } + + if (Float.compare(options.pulsingCircleMaxRadius, pulsingCircleMaxRadius) != 0) { + return false; + } + + if (Float.compare(options.pulseAlpha, pulseAlpha) != 0) { + return false; + } + + if (pulseInterpolator != null ? !pulseInterpolator.equals(options.pulseInterpolator) + : options.pulseInterpolator != null) { + return false; + } + return layerBelow != null ? layerBelow.equals(options.layerBelow) : options.layerBelow == null; } @@ -933,6 +1100,13 @@ public class LocationComponentOptions implements Parcelable { ? Float.floatToIntBits(trackingAnimationDurationMultiplier) : 0); result = 31 * result + (compassAnimationEnabled ? 1 : 0); result = 31 * result + (accuracyAnimationEnabled ? 1 : 0); + result = 31 * result + (pulsingCircleEnabled ? 1 : 0); + result = 31 * result + (pulsingCircleFadeEnabled ? 1 : 0); + result = 31 * result + (pulseColor != null ? pulseColor.hashCode() : 0); + result = 31 * result + (pulseSingleDuration != +0.0f ? Float.floatToIntBits(pulseSingleDuration) : 0); + result = 31 * result + (pulsingCircleMaxRadius != +0.0f ? Float.floatToIntBits(pulsingCircleMaxRadius) : 0); + result = 31 * result + (pulseAlpha != +0.0f ? Float.floatToIntBits(pulseAlpha) : 0); + result = 31 * result + (pulseInterpolator != null ? pulseInterpolator.hashCode() : 0); return result; } @@ -973,7 +1147,14 @@ public class LocationComponentOptions implements Parcelable { in.readString(), in.readFloat(), in.readInt() == 1, - in.readInt() == 1 + in.readInt() == 1, + in.readInt() == 1, + in.readInt() == 1, + in.readInt() == 0 ? in.readInt() : null, + in.readFloat(), + in.readFloat(), + in.readFloat(), + in.readString() ); } @@ -1073,6 +1254,18 @@ public class LocationComponentOptions implements Parcelable { dest.writeFloat(trackingAnimationDurationMultiplier); dest.writeInt(compassAnimationEnabled() ? 1 : 0); dest.writeInt(accuracyAnimationEnabled() ? 1 : 0); + dest.writeInt(pulseEnabled() ? 1 : 0); + dest.writeInt(pulsingCircleFadeEnabled() ? 1 : 0); + if (pulseColor() == null) { + dest.writeInt(1); + } else { + dest.writeInt(0); + dest.writeInt(pulseColor()); + } + dest.writeFloat(pulseSingleDuration()); + dest.writeFloat(pulseMaxRadius()); + dest.writeFloat(pulseAlpha()); + dest.writeString(pulseInterpolator()); } @Override @@ -1108,6 +1301,32 @@ public class LocationComponentOptions implements Parcelable { + "Choose one or the other."); } + if (locationComponentOptions.pulseEnabled() == null) { + String pulsingSetupError = ""; + if (locationComponentOptions.pulsingCircleFadeEnabled() != null) { + pulsingSetupError += " pulsingCircleFadeEnabled"; + } + if (locationComponentOptions.pulseColor() != null) { + pulsingSetupError += " pulsingCircleColor"; + } + if (locationComponentOptions.pulseSingleDuration() > 0) { + pulsingSetupError += " pulsingCircleDuration"; + } + if (locationComponentOptions.pulseMaxRadius() > 0) { + pulsingSetupError += " pulsingCircleMaxRadius"; + } + if (locationComponentOptions.pulseAlpha() >= 0 && locationComponentOptions.pulseAlpha() <= 1) { + pulsingSetupError += " pulsingCircleAlpha"; + } + if (locationComponentOptions.pulseInterpolator() != null) { + pulsingSetupError += " pulsingCircleInterpolator"; + } + if (!pulsingSetupError.isEmpty()) { + throw new IllegalStateException("You've set up the following pulsing circle options but have not enabled" + + " the pulsing circle via the LocationComponentOptions builder:" + pulsingSetupError + + ". Enable the pulsing circle if you're going to set pulsing options."); + } + } return locationComponentOptions; } @@ -1156,6 +1375,13 @@ public class LocationComponentOptions implements Parcelable { private Float trackingAnimationDurationMultiplier; private Boolean compassAnimationEnabled; private Boolean accuracyAnimationEnabled; + private Boolean pulsingCircleEnabled; + private Boolean pulsingCircleFadeEnabled; + private int pulsingCircleColor; + private float pulsingCircleDuration; + private float pulsingCircleMaxRadius; + private float pulsingCircleAlpha; + private String pulsingCircleInterpolator; Builder() { } @@ -1194,6 +1420,13 @@ public class LocationComponentOptions implements Parcelable { this.trackingAnimationDurationMultiplier = source.trackingAnimationDurationMultiplier(); this.compassAnimationEnabled = source.compassAnimationEnabled(); this.accuracyAnimationEnabled = source.accuracyAnimationEnabled(); + this.pulsingCircleEnabled = source.pulsingCircleEnabled; + this.pulsingCircleFadeEnabled = source.pulsingCircleFadeEnabled; + this.pulsingCircleColor = source.pulseColor; + this.pulsingCircleDuration = source.pulseSingleDuration; + this.pulsingCircleMaxRadius = source.pulsingCircleMaxRadius; + this.pulsingCircleAlpha = source.pulseAlpha; + this.pulsingCircleInterpolator = source.pulseInterpolator; } /** @@ -1674,11 +1907,83 @@ public class LocationComponentOptions implements Parcelable { * * @return whether smooth animation of the accuracy circle is enabled */ - public Builder accuracyAnimationEnabled(Boolean accuracyAnimationEnabled) { + public LocationComponentOptions.Builder accuracyAnimationEnabled(Boolean accuracyAnimationEnabled) { this.accuracyAnimationEnabled = accuracyAnimationEnabled; return this; } + /** + * Enable or disable the LocationComponent's pulsing circle. + * + * @return whether the LocationComponent's pulsing circle is enabled + */ + public LocationComponentOptions.Builder pulsingCircleEnabled(Boolean pulsingCircleEnabled) { + this.pulsingCircleEnabled = pulsingCircleEnabled; + return this; + } + + /** + * Enable or disable fading of the LocationComponent's pulsing circle. If it fades, the circle's + * opacity decreases as its radius increases. + * + * @return whether fading of the LocationComponent's pulsing circle is enabled + */ + public LocationComponentOptions.Builder pulsingCircleFadeEnabled(Boolean pulsingCircleFadeEnabled) { + this.pulsingCircleFadeEnabled = pulsingCircleFadeEnabled; + return this; + } + + /** + * Sets the color of the LocationComponent's pulsing circle. + * + * @return the current set color of the circle + */ + public LocationComponentOptions.Builder pulsingCircleColor(int pulsingCircleColor) { + this.pulsingCircleColor = pulsingCircleColor; + return this; + } + + /** + * Sets the number of milliseconds it takes for a single pulse of the LocationComponent's pulsing circle. + * + * @return the current set length of time for a single pulse + */ + public LocationComponentOptions.Builder pulsingCircleDuration(float pulsingCircleDuration) { + this.pulsingCircleDuration = pulsingCircleDuration; + return this; + } + + /** + * The maximum radius that a single pulse should expand the LocationComponent's pulsing circle to. + * + * @return the maximum radius that the pulsing circle will expand to. + */ + public LocationComponentOptions.Builder pulsingCircleMaxRadius(float pulsingCircleMaxRadius) { + this.pulsingCircleMaxRadius = pulsingCircleMaxRadius; + return this; + } + + /** + * Sets the opacity of the LocationComponent's pulsing circle. + * + * @return the current set opacity of the LocationComponent's circle + */ + public LocationComponentOptions.Builder pulsingCircleAlpha(float pulsingCircleAlpha) { + this.pulsingCircleAlpha = pulsingCircleAlpha; + return this; + } + + /** + * Sets the pulsing circle's interpolator animation. Pass through a mode constant via the + * {@link PulseMode} class. + * + * @return a String which represents the interpolator animation that the pulsing circle will use. + */ + public LocationComponentOptions.Builder pulsingCircleInterpolator(String pulsingCircleInterpolator) { + this.pulsingCircleInterpolator = pulsingCircleInterpolator; + return this; + } + @Nullable LocationComponentOptions autoBuild() { String missing = ""; @@ -1772,7 +2077,14 @@ public class LocationComponentOptions implements Parcelable { this.layerBelow, this.trackingAnimationDurationMultiplier, this.compassAnimationEnabled, - this.accuracyAnimationEnabled); + this.accuracyAnimationEnabled, + this.pulsingCircleEnabled, + this.pulsingCircleFadeEnabled, + this.pulsingCircleColor, + this.pulsingCircleDuration, + this.pulsingCircleMaxRadius, + this.pulsingCircleAlpha, + this.pulsingCircleInterpolator); } } } 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 54f8ee6d1a..53a6b74e4f 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 @@ -45,15 +45,23 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_FOREGROUND_STALE_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_GPS_BEARING; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_LOCATION_STALE; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PULSING_CIRCLE_LAYER; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_PULSING_OPACITY; +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_PULSING_RADIUS; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.PROPERTY_SHADOW_ICON_OFFSET; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_ICON; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.SHADOW_LAYER; +import static com.mapbox.mapboxsdk.style.expressions.Expression.get; import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; import static com.mapbox.mapboxsdk.style.expressions.Expression.linear; import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; import static com.mapbox.mapboxsdk.style.layers.Property.NONE; import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleOpacity; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeColor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; import static com.mapbox.mapboxsdk.utils.ColorUtils.colorToRgbaString; @@ -127,6 +135,7 @@ final class LocationLayerController { styleBearing(options); styleAccuracy(options.accuracyAlpha(), options.accuracyColor()); styleScaling(options); + stylePulsingCircle(options); determineIconsSource(options); if (!isHidden) { @@ -186,6 +195,13 @@ final class LocationLayerController { } } + /** + * Adjust the visibility of the pulsing LocationComponent circle. + */ + void adjustPulsingCircleLayerVisibility(boolean visible) { + setLayerVisibility(PULSING_CIRCLE_LAYER, visible); + } + void hide() { isHidden = true; for (String layerId : layerSet) { @@ -242,6 +258,7 @@ final class LocationLayerController { addSymbolLayer(BACKGROUND_LAYER, FOREGROUND_LAYER); addSymbolLayer(SHADOW_LAYER, BACKGROUND_LAYER); addAccuracyLayer(); + addPulsingCircleLayerToMap(); } private void addSymbolLayer(@NonNull String layerId, @NonNull String beforeLayerId) { @@ -259,6 +276,14 @@ final class LocationLayerController { layerSet.add(layer.getId()); } + /** + * Add the pulsing LocationComponent circle to the map for future use, if need be.updatePulsingLocationCircleRadius + */ + private void addPulsingCircleLayerToMap() { + Layer pulsingCircleLayer = layerSourceProvider.generatePulsingCircleLayer(); + addLayerToMap(pulsingCircleLayer, ACCURACY_LAYER); + } + private void removeLayers() { for (String layerId : layerSet) { style.removeLayer(layerId); @@ -276,6 +301,30 @@ final class LocationLayerController { refreshSource(); } + /** + * Updates the {@link LocationComponentConstants#PROPERTY_PULSING_RADIUS} property value and refreshes + * the LocationComponent source. This leads to a smooth update to the visuals of the pulsing + * LocationComponent circle. + * + * @param radius The new radius in the animation. + */ + private void updatePulsingLocationCircleRadius(float radius) { + locationFeature.addNumberProperty(PROPERTY_PULSING_RADIUS, radius); + refreshSource(); + } + + /** + * Updates the {@link LocationComponentConstants#PROPERTY_PULSING_OPACITY} property value and refreshes + * the LocationComponent source. This leads to a smooth update to the visuals of the pulsing + * LocationComponent circle. This is used if the fade option is set to true while setting pulsing options. + * + * @param opacity The new opacity in the animation. + */ + private void updatePulsingLocationCircleOpacity(float opacity) { + locationFeature.addNumberProperty(PROPERTY_PULSING_OPACITY, opacity); + refreshSource(); + } + // // Source actions // @@ -365,6 +414,24 @@ final class LocationLayerController { } } + /** + * Use the Maps SDK's data-driven styling properties to set the pulsing circle location UI. + * + * @param options The {@link LocationComponentOptions} set upstream during LocationComponent + * initialization. + */ + private void stylePulsingCircle(LocationComponentOptions options) { + if (style.getLayer(PULSING_CIRCLE_LAYER) != null) { + setLayerVisibility(PULSING_CIRCLE_LAYER, true); + style.getLayer(PULSING_CIRCLE_LAYER).setProperties( + circleRadius(get(PROPERTY_PULSING_RADIUS)), + circleColor(options.pulseColor()), + circleStrokeColor(options.pulseColor()), + circleOpacity(get(PROPERTY_PULSING_OPACITY)) + ); + } + } + private void determineIconsSource(LocationComponentOptions options) { String foregroundIconString = buildIconString( renderMode == RenderMode.GPS ? options.gpsName() : options.foregroundName(), FOREGROUND_ICON); @@ -444,6 +511,21 @@ final class LocationLayerController { } }; + /** + * The listener that handles the updating of the pulsing circle's radius and opacity. + */ + private final MapboxAnimator.AnimationsValueChangeListener<Float> pulsingCircleRadiusListener = + new MapboxAnimator.AnimationsValueChangeListener<Float>() { + @Override + public void onNewAnimationValue(Float newPulsingRadiusValue) { + updatePulsingLocationCircleRadius(newPulsingRadiusValue); + if (options.pulsingCircleFadeEnabled()) { + double newPulsingOpacityValue = 1 - ((newPulsingRadiusValue / 100) * 3); + updatePulsingLocationCircleOpacity((float) newPulsingOpacityValue); + } + } + }; + Set<AnimatorListenerHolder> getAnimationListeners() { Set<AnimatorListenerHolder> holders = new HashSet<>(); holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_LAYER_LATLNG, latLngValueListener)); @@ -459,6 +541,10 @@ final class LocationLayerController { holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_LAYER_ACCURACY, accuracyValueListener)); } + if (options.pulseEnabled()) { + holders.add(new AnimatorListenerHolder(MapboxAnimator.ANIMATOR_PULSING_CIRCLE, + pulsingCircleRadiusListener)); + } return holders; } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java index dff7369cd5..2ffaceb507 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java @@ -26,7 +26,8 @@ abstract class MapboxAnimator<K> extends ValueAnimator implements ValueAnimator. ANIMATOR_CAMERA_COMPASS_BEARING, ANIMATOR_LAYER_ACCURACY, ANIMATOR_ZOOM, - ANIMATOR_TILT + ANIMATOR_TILT, + ANIMATOR_PULSING_CIRCLE }) @interface Type { } @@ -40,6 +41,7 @@ abstract class MapboxAnimator<K> extends ValueAnimator implements ValueAnimator. static final int ANIMATOR_LAYER_ACCURACY = 6; static final int ANIMATOR_ZOOM = 7; static final int ANIMATOR_TILT = 8; + static final int ANIMATOR_PULSING_CIRCLE = 9; private final AnimationsValueChangeListener<K> updateListener; private final K target; @@ -59,6 +61,15 @@ abstract class MapboxAnimator<K> extends ValueAnimator implements ValueAnimator. addListener(new AnimatorListener()); } + public MapboxAnimator(AnimationsValueChangeListener<K> updateListener, K target, K animatedValue, + double minUpdateInterval, long timeElapsed) { + this.updateListener = updateListener; + this.target = target; + this.animatedValue = animatedValue; + this.minUpdateInterval = minUpdateInterval; + this.timeElapsed = timeElapsed; + } + @Override public void onAnimationUpdate(ValueAnimator animation) { animatedValue = (K) animation.getAnimatedValue(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java index 938f4ec74a..36cce25d2b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorProvider.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.location; +import android.animation.ValueAnimator; import android.support.annotation.Nullable; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -37,4 +38,33 @@ final class MapboxAnimatorProvider { @Nullable MapboxMap.CancelableCallback cancelableCallback) { return new MapboxCameraAnimatorAdapter(previous, target, updateListener, cancelableCallback); } + + /** + * This animator is for the LocationComponent pulsing circle. + * + * @param updateListener the listener that is found in the {@link LocationAnimatorCoordinator}'s + * listener array. + * @param maxAnimationFps the max frames per second of the pulsing animation + * @param pulseSingleDuration the number of milliseconds it takes for the animator to create + * a single pulse. + * @param pulseMaxRadius the max radius when the circle is finished with a single pulse. + * @param desiredInterpolatorFromOptions the type of Android-system interpolator to use for + * the pulsing animation (linear, accelerate, bounce, etc.) + * @return a built {@link PulsingLocationCircleAnimator} object. + */ + PulsingLocationCircleAnimator pulsingCircleAnimator(MapboxAnimator.AnimationsValueChangeListener updateListener, + int maxAnimationFps, + float pulseSingleDuration, + float pulseMaxRadius, + String desiredInterpolatorFromOptions) { + PulsingLocationCircleAnimator pulsingLocationCircleAnimator = + new PulsingLocationCircleAnimator(updateListener, maxAnimationFps, pulseMaxRadius); + pulsingLocationCircleAnimator.setDuration((long) pulseSingleDuration); + pulsingLocationCircleAnimator.setRepeatMode(ValueAnimator.RESTART); + pulsingLocationCircleAnimator.setRepeatCount(ValueAnimator.INFINITE); + pulsingLocationCircleAnimator.retrievePulseInterpolator(desiredInterpolatorFromOptions); + pulsingLocationCircleAnimator.setInterpolator( + pulsingLocationCircleAnimator.retrievePulseInterpolator(desiredInterpolatorFromOptions)); + return pulsingLocationCircleAnimator; + } } 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 index 1d09f8ae71..da7c666ae9 100644 --- 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 @@ -29,4 +29,15 @@ class MapboxAnimatorSetProvider { locationAnimatorSet.setDuration(duration); locationAnimatorSet.start(); } + + /** + * Starts a single animator rather than playing multliple animators all at once. + * + * @param singleAnimation the {@link Animator} to run. + */ + void startSingleAnimation(@NonNull Animator singleAnimation) { + AnimatorSet locationAnimatorSet = new AnimatorSet(); + locationAnimatorSet.play(singleAnimation); + locationAnimatorSet.start(); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/PulsingLocationCircleAnimator.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/PulsingLocationCircleAnimator.java new file mode 100644 index 0000000000..bfae5102ab --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/PulsingLocationCircleAnimator.java @@ -0,0 +1,42 @@ +package com.mapbox.mapboxsdk.location; + +import android.view.animation.AccelerateInterpolator; +import android.view.animation.BounceInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import com.mapbox.mapboxsdk.location.modes.PulseMode; + +/** + * Manages the logic of the interpolated animation which is applied to the LocationComponent's pulsing circle + */ +public class PulsingLocationCircleAnimator extends MapboxFloatAnimator { + + /** + * + * @param updateListener the {@link AnimationsValueChangeListener} associated with this animator. + * @param maxAnimationFps the maximum frames per second that the animator should use. Default + * is the {@link LocationAnimatorCoordinator#maxAnimationFps} variable. + */ + public PulsingLocationCircleAnimator(AnimationsValueChangeListener updateListener, + int maxAnimationFps, + float circleMaxRadius) { + super(0f, circleMaxRadius, updateListener, maxAnimationFps); + } + + public Interpolator retrievePulseInterpolator(String desiredInterpolatorFromOptions) { + switch (desiredInterpolatorFromOptions) { + case PulseMode.LINEAR: + return new LinearInterpolator(); + case PulseMode.ACCELERATE: + return new AccelerateInterpolator(); + case PulseMode.DECELERATE: + return new DecelerateInterpolator(); + case PulseMode.BOUNCE: + return new BounceInterpolator(); + default: + return new DecelerateInterpolator(); + } + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/PulseMode.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/PulseMode.java new file mode 100644 index 0000000000..f8713ffe86 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/modes/PulseMode.java @@ -0,0 +1,50 @@ +package com.mapbox.mapboxsdk.location.modes; + +import android.support.annotation.StringDef; + +import com.mapbox.mapboxsdk.location.LocationComponentOptions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A convenience class for setting the {@link com.mapbox.mapboxsdk.location.LocationComponent}'s + * pulsing circle UI functionality. Use with + */ +public final class PulseMode { + + private PulseMode() { + // Class should not be initialized + } + + /** + * An interpolator defines the rate of change of an animation. + * + * One of these constants should be used with {@link LocationComponentOptions#pulseInterpolator}. + * + */ + @StringDef( {LINEAR, ACCELERATE, DECELERATE, BOUNCE}) + @Retention(RetentionPolicy.SOURCE) + public @interface Mode { + } + + /** + * An interpolator where the rate of change is constant. + */ + public static final String LINEAR = "linear"; + + /** + * An interpolator where the rate of change starts out slowly and and then accelerates. + */ + public static final String ACCELERATE = "accelerate"; + + /** + * An interpolator where the rate of change starts out quickly and and then decelerates. + */ + public static final String DECELERATE = "decelerate"; + + /** + * An interpolator where the change bounces at the end. + */ + public static final String BOUNCE = "bounce"; +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 60a1efc771..731ec8a0e7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -159,4 +159,12 @@ <public name="mapbox_layer_above" format="string" type="attr" /> <public name="mapbox_layer_below" format="string" type="attr" /> -</resources> + <!-- Pulsing circle --> + <public name="mapbox_pulsingLocationCircleEnabled" format="boolean" type="attr" /> + <public name="mapbox_pulsingLocationCircleFadeEnabled" format="boolean" type="attr" /> + <public name="mapbox_pulsingLocationCircleColor" format="color" type="attr" /> + <public name="mapbox_pulsingLocationCircleDuration" format="float" type="attr" /> + <public name="mapbox_pulsingLocationCircleRadius" format="float" type="attr" /> + <public name="mapbox_pulsingLocationCircleAlpha" format="float" type="attr" /> + <public name="mapbox_pulsingLocationCircleInterpolator" format="string" type="attr" /> +</resources>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index ff8a32ac64..a8703e81d1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -182,5 +182,14 @@ <!-- Accuracy animation--> <attr name="mapbox_accuracyAnimationEnabled" format="boolean" /> + <!-- Pulsing circle --> + <attr name="mapbox_pulsingLocationCircleEnabled" format="boolean" /> + <attr name="mapbox_pulsingLocationCircleFadeEnabled" format="boolean" /> + <attr name="mapbox_pulsingLocationCircleColor" format="color" /> + <attr name="mapbox_pulsingLocationCircleDuration" format="float" /> + <attr name="mapbox_pulsingLocationCircleRadius" format="float" /> + <attr name="mapbox_pulsingLocationCircleAlpha" format="float" /> + <attr name="mapbox_pulsingLocationCircleInterpolator" format="string" /> + </declare-styleable> </resources> diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml index c6c2d3fc7b..32429e2b62 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml @@ -33,5 +33,13 @@ <item name="mapbox_trackingInitialMoveThreshold">@dimen/mapbox_locationComponentTrackingInitialMoveThreshold</item> <item name="mapbox_trackingMultiFingerMoveThreshold">@dimen/mapbox_locationComponentTrackingMultiFingerMoveThreshold</item> + <!-- Location pulsing circle --> + <item name="mapbox_pulsingLocationCircleEnabled">false</item> + <item name="mapbox_pulsingLocationCircleFadeEnabled">true</item> + <item name="mapbox_pulsingLocationCircleColor">@color/mapbox_location_layer_blue</item> + <item name="mapbox_pulsingLocationCircleDuration">2300</item> + <item name="mapbox_pulsingLocationCircleRadius">35</item> + <item name="mapbox_pulsingLocationCircleAlpha">0.4</item> + <item name="mapbox_pulsingLocationCircleInterpolator">decelerate</item> </style> </resources>
\ No newline at end of file |