diff options
| author | 2022-03-07 18:39:05 +0000 | |
|---|---|---|
| committer | 2022-03-10 21:23:17 +0000 | |
| commit | 60442cb1b8b7cda7719943f2183f6ba40e29bc8f (patch) | |
| tree | 73b9bf783c27d83da6ae4ba0b2dded1868d24ae2 | |
| parent | 99483fa82bb17c4aaaaf7920affeaab501bdc803 (diff) | |
Add API to read and listen to duration scale changes for animations
Developers and accessibility services can remove animations by
changing the duration scale to zero. Physics-based animation
libraries like AndroidX's dynamic animations aren't duration-based,
but they need to know the duration scale to remove animations.
Expose the scale through ValueAnimator to avoid requests for
Context which may not be fulfilled by the developer.
Unhide test API getDurationScale and handle callbacks on the main
thread.
Test: atest ValueAnimatorTest
Bug: 221303983
Change-Id: I3134e0bf007df046a9a2aa0f9d866c27c7989e68
| -rw-r--r-- | core/api/current.txt | 7 | ||||
| -rw-r--r-- | core/api/test-current.txt | 3 | ||||
| -rw-r--r-- | core/java/android/animation/ValueAnimator.java | 101 |
3 files changed, 105 insertions, 6 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 3a6fc590648e..c50fec411e57 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -3901,6 +3901,7 @@ package android.animation { method public Object getAnimatedValue(String); method public long getCurrentPlayTime(); method public long getDuration(); + method @FloatRange(from=0, to=1) public static float getDurationScale(); method public static long getFrameDelay(); method public int getRepeatCount(); method public int getRepeatMode(); @@ -3912,6 +3913,7 @@ package android.animation { method public static android.animation.ValueAnimator ofInt(int...); method public static android.animation.ValueAnimator ofObject(android.animation.TypeEvaluator, java.lang.Object...); method public static android.animation.ValueAnimator ofPropertyValuesHolder(android.animation.PropertyValuesHolder...); + method public static boolean registerDurationScaleChangeListener(@NonNull android.animation.ValueAnimator.DurationScaleChangeListener); method public void removeAllUpdateListeners(); method public void removeUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener); method public void reverse(); @@ -3928,6 +3930,7 @@ package android.animation { method public void setRepeatMode(int); method public void setStartDelay(long); method public void setValues(android.animation.PropertyValuesHolder...); + method public static boolean unregisterDurationScaleChangeListener(@NonNull android.animation.ValueAnimator.DurationScaleChangeListener); field public static final int INFINITE = -1; // 0xffffffff field public static final int RESTART = 1; // 0x1 field public static final int REVERSE = 2; // 0x2 @@ -3937,6 +3940,10 @@ package android.animation { method public void onAnimationUpdate(@NonNull android.animation.ValueAnimator); } + public static interface ValueAnimator.DurationScaleChangeListener { + method public void onChanged(float); + } + } package android.annotation { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 9757b2ff318f..3a1bf6406e5c 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -95,8 +95,7 @@ package android.accessibilityservice { package android.animation { public class ValueAnimator extends android.animation.Animator { - method public static float getDurationScale(); - method public static void setDurationScale(float); + method @MainThread public static void setDurationScale(@FloatRange(from=0, to=1) float); } } diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 06b424bcb417..bca6b6a0ddd0 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -17,7 +17,9 @@ package android.animation; import android.annotation.CallSuper; +import android.annotation.FloatRange; import android.annotation.IntDef; +import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; @@ -35,8 +37,10 @@ import android.view.animation.LinearInterpolator; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; /** * This class provides a simple timing engine for running animations @@ -91,6 +95,9 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private static float sDurationScale = 1.0f; + private static final ArrayList<WeakReference<DurationScaleChangeListener>> + sDurationScaleChangeListeners = new ArrayList<>(); + /** * Internal variables * NOTE: This object implements the clone() method, making a deep copy of any referenced @@ -308,20 +315,92 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio */ @UnsupportedAppUsage @TestApi - public static void setDurationScale(float durationScale) { + @MainThread + public static void setDurationScale(@FloatRange(from = 0, to = 1) float durationScale) { sDurationScale = durationScale; + List<WeakReference<DurationScaleChangeListener>> listenerCopy; + + synchronized (sDurationScaleChangeListeners) { + listenerCopy = new ArrayList<>(sDurationScaleChangeListeners); + } + + for (WeakReference<DurationScaleChangeListener> listenerRef : listenerCopy) { + final DurationScaleChangeListener listener = listenerRef.get(); + if (listener != null) { + listener.onChanged(durationScale); + } + } } /** - * @hide + * Returns the system-wide scaling factor for Animator-based animations. + * + * This affects both the start delay and duration of all such animations. Setting to 0 will + * cause animations to end immediately. The default value is 1.0f. + * + * @return the duration scale. */ - @UnsupportedAppUsage - @TestApi + @FloatRange(from = 0, to = 1) public static float getDurationScale() { return sDurationScale; } /** + * Registers a {@link DurationScaleChangeListener} + * + * This listens for changes to the system-wide scaling factor for Animator-based animations. + * Listeners will be called on the main thread. + * + * @param listener the listener to register. + * @return true if the listener was registered. + */ + public static boolean registerDurationScaleChangeListener( + @NonNull DurationScaleChangeListener listener) { + int posToReplace = -1; + synchronized (sDurationScaleChangeListeners) { + for (int i = 0; i < sDurationScaleChangeListeners.size(); i++) { + final WeakReference<DurationScaleChangeListener> ref = + sDurationScaleChangeListeners.get(i); + if (ref.get() == null) { + if (posToReplace == -1) { + posToReplace = i; + } + } else if (ref.get() == listener) { + return false; + } + } + if (posToReplace != -1) { + sDurationScaleChangeListeners.set(posToReplace, new WeakReference<>(listener)); + return true; + } else { + return sDurationScaleChangeListeners.add(new WeakReference<>(listener)); + } + } + } + + /** + * Unregisters a DurationScaleChangeListener. + * + * @see #registerDurationScaleChangeListener(DurationScaleChangeListener) + * @param listener the listener to unregister. + * @return true if the listener was unregistered. + */ + public static boolean unregisterDurationScaleChangeListener( + @NonNull DurationScaleChangeListener listener) { + synchronized (sDurationScaleChangeListeners) { + WeakReference<DurationScaleChangeListener> listenerRefToRemove = null; + for (WeakReference<DurationScaleChangeListener> listenerRef : + sDurationScaleChangeListeners) { + if (listenerRef.get() == listener) { + listenerRefToRemove = listenerRef; + break; + } + } + return sDurationScaleChangeListeners.remove(listenerRefToRemove); + } + } + + /** * Returns whether animators are currently enabled, system-wide. By default, all * animators are enabled. This can change if either the user sets a Developer Option * to set the animator duration scale to 0 or by Battery Savery mode being enabled @@ -1709,4 +1788,18 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio public void setAnimationHandler(@Nullable AnimationHandler animationHandler) { mAnimationHandler = animationHandler; } + + /** + * Listener interface for the system-wide scaling factor for Animator-based animations. + * + * @see #registerDurationScaleChangeListener(DurationScaleChangeListener) + * @see #unregisterDurationScaleChangeListener(DurationScaleChangeListener) + */ + public interface DurationScaleChangeListener { + /** + * Called when the duration scale changes. + * @param scale the duration scalel + */ + void onChanged(float scale); + } } |