From bb1132a4d38023ab7fd640924464b5e90b4bcc20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 21 Apr 2020 14:07:57 +0200 Subject: [PATCH] make sure to hard-cancel all ignored location animators --- .../location/LocationAnimatorCoordinator.java | 16 ++++++++ .../mapboxsdk/location/MapboxAnimator.java | 15 ++++++- .../LocationAnimatorCoordinatorTest.kt | 39 +++++++++++++++++-- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java index 474e524d1..50b2d6384 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java @@ -74,6 +74,16 @@ final class LocationAnimatorCoordinator { for (AnimatorListenerHolder holder : listenerHolders) { listeners.append(holder.getAnimatorType(), holder.getListener()); } + + for (int i = 0; i < animatorArray.size(); i++) { + @MapboxAnimator.Type int animatorType = animatorArray.keyAt(i); + if (listeners.get(animatorType) == null) { + MapboxAnimator animator = animatorArray.get(animatorType); + if (animator != null) { + animator.makeInvalid(); + } + } + } } void feedNewLocation(@NonNull Location newLocation, @NonNull CameraPosition currentCameraPosition, @@ -397,6 +407,8 @@ final class LocationAnimatorCoordinator { MapboxFloatAnimator gpsBearingAnimator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_GPS_BEARING); MapboxFloatAnimator compassBearingAnimator = (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_COMPASS_BEARING); + MapboxFloatAnimator accuracyAnimator = + (MapboxFloatAnimator) animatorArray.get(ANIMATOR_LAYER_ACCURACY); if (latLngAnimator != null && gpsBearingAnimator != null) { LatLng currentLatLng = (LatLng) latLngAnimator.getAnimatedValue(); @@ -420,6 +432,10 @@ final class LocationAnimatorCoordinator { compassAnimationEnabled ? COMPASS_UPDATE_RATE_MS : 0, ANIMATOR_LAYER_COMPASS_BEARING); } + + if (accuracyAnimator != null) { + feedNewAccuracyRadius(previousAccuracyRadius, false); + } } void cancelZoomAnimation() { diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java index f9a213241..694594fa6 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimator.java @@ -50,6 +50,13 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. private final double minUpdateInterval; private long timeElapsed; + /** + * Makes this animator invalid and prevents it from pushing any more updates to the listener. + * + * This can be used to prevent propagating final updates when the animator should be immediately canceled. + */ + private boolean invalid; + MapboxAnimator(@NonNull @Size(min = 2) K[] values, @NonNull AnimationsValueChangeListener updateListener, int maxAnimationFps) { minUpdateInterval = 1E9 / maxAnimationFps; @@ -82,7 +89,9 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. } private void postUpdates() { - updateListener.onNewAnimationValue(animatedValue); + if (!invalid) { + updateListener.onNewAnimationValue(animatedValue); + } } K getTarget() { @@ -94,4 +103,8 @@ abstract class MapboxAnimator extends ValueAnimator implements ValueAnimator. interface AnimationsValueChangeListener { void onNewAnimationValue(K value); } + + public void makeInvalid() { + invalid = true; + } } diff --git a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt index bd741e5b9..7c4feb83b 100644 --- a/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt +++ b/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.location import android.animation.Animator +import android.animation.ValueAnimator import android.location.Location import android.util.SparseArray import android.view.animation.LinearInterpolator @@ -9,7 +10,6 @@ import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION import com.mapbox.mapboxsdk.location.MapboxAnimator.* -import com.mapbox.mapboxsdk.location.modes.CameraMode import com.mapbox.mapboxsdk.location.modes.RenderMode import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.Projection @@ -517,16 +517,16 @@ class LocationAnimatorCoordinatorTest { @Test fun updateListeners() { val listener = Mockito.mock(AnimationsValueChangeListener::class.java) - val holder = AnimatorListenerHolder(RenderMode.NORMAL, listener) + val holder = AnimatorListenerHolder(ANIMATOR_LAYER_LATLNG, listener) val set = HashSet().also { it.add(holder) } locationAnimatorCoordinator.updateAnimatorListenerHolders(set) val listener2 = Mockito.mock(AnimationsValueChangeListener::class.java) - val holder2 = AnimatorListenerHolder(RenderMode.NORMAL, listener2) + val holder2 = AnimatorListenerHolder(ANIMATOR_LAYER_LATLNG, listener2) val listener3 = Mockito.mock(AnimationsValueChangeListener::class.java) - val holder3 = AnimatorListenerHolder(CameraMode.TRACKING_GPS, listener3) + val holder3 = AnimatorListenerHolder(ANIMATOR_LAYER_ACCURACY, listener3) val set2 = HashSet().also { it.add(holder2) it.add(holder3) @@ -538,6 +538,37 @@ class LocationAnimatorCoordinatorTest { assertTrue(locationAnimatorCoordinator.listeners.contains(listener3)) } + @Test + fun updateListeners_listenerRemoved_animtorInvalid() { + // setup accuracy animator + val listener: AnimationsValueChangeListener = mockk(relaxUnitFun = true) + val holder = AnimatorListenerHolder(ANIMATOR_LAYER_ACCURACY, listener) + val set = HashSet().also { + it.add(holder) + } + locationAnimatorCoordinator.updateAnimatorListenerHolders(set) + locationAnimatorCoordinator.feedNewAccuracyRadius(500f, true) + + // reset animator listeners which should make the previously created animator invalid + val listener2: AnimationsValueChangeListener<*> = mockk() + val holder2 = AnimatorListenerHolder(ANIMATOR_LAYER_LATLNG, listener2) + val listener3: AnimationsValueChangeListener<*> = mockk() + val holder3 = AnimatorListenerHolder(ANIMATOR_CAMERA_GPS_BEARING, listener3) + val set2 = HashSet().also { + it.add(holder2) + it.add(holder3) + } + locationAnimatorCoordinator.updateAnimatorListenerHolders(set2) + + // try pushing an update to verify it was ignored + val valueAnimator: ValueAnimator = mockk() + every { valueAnimator.animatedValue } returns 10f + val animator = locationAnimatorCoordinator.animatorArray.get(ANIMATOR_LAYER_ACCURACY) + animator.onAnimationUpdate(valueAnimator) + + verify(exactly = 0) { listener.onNewAnimationValue(any()) } + } + @Test fun feedNewCompassBearing_withAnimation() { locationAnimatorCoordinator.setCompassAnimationEnabled(true)