summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sally <sallyyuen@google.com> 2022-03-07 18:39:05 +0000
committer Sally <sallyyuen@google.com> 2022-03-10 21:23:17 +0000
commit60442cb1b8b7cda7719943f2183f6ba40e29bc8f (patch)
tree73b9bf783c27d83da6ae4ba0b2dded1868d24ae2
parent99483fa82bb17c4aaaaf7920affeaab501bdc803 (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.txt7
-rw-r--r--core/api/test-current.txt3
-rw-r--r--core/java/android/animation/ValueAnimator.java101
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);
+ }
}