make sure to hard-cancel all ignored location animators

This commit is contained in:
Łukasz Paczos
2020-04-21 14:07:57 +02:00
parent 6f73982d95
commit bb1132a4d3
3 changed files with 65 additions and 5 deletions

View File

@@ -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() {

View File

@@ -50,6 +50,13 @@ abstract class MapboxAnimator<K> 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<K> updateListener,
int maxAnimationFps) {
minUpdateInterval = 1E9 / maxAnimationFps;
@@ -82,7 +89,9 @@ abstract class MapboxAnimator<K> extends ValueAnimator implements ValueAnimator.
}
private void postUpdates() {
updateListener.onNewAnimationValue(animatedValue);
if (!invalid) {
updateListener.onNewAnimationValue(animatedValue);
}
}
K getTarget() {
@@ -94,4 +103,8 @@ abstract class MapboxAnimator<K> extends ValueAnimator implements ValueAnimator.
interface AnimationsValueChangeListener<K> {
void onNewAnimationValue(K value);
}
public void makeInvalid() {
invalid = true;
}
}

View File

@@ -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<AnimatorListenerHolder>().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<AnimatorListenerHolder>().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<Float> = mockk(relaxUnitFun = true)
val holder = AnimatorListenerHolder(ANIMATOR_LAYER_ACCURACY, listener)
val set = HashSet<AnimatorListenerHolder>().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<AnimatorListenerHolder>().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)