From 7625f95003f74dbf2eba40793e7f217961628b55 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Tue, 17 May 2022 22:13:24 +0000 Subject: [PATCH] Allow system to disable behavior of pausing animators for bg apps This change adds a static method which can be called to disable the default behavior of pausing infinite animators when an app's windows are all in the background. This could potentially be used for global behavior of a system property to disable this behavior system wide. Bug: 232937493 Test: Added new cts test to AnimatorLeakTest to verify behavior Change-Id: Idf4957e3968253228096671fde89f820311883e3 --- core/api/test-current.txt | 1 + .../android/animation/AnimationHandler.java | 33 ++++++++++++++++--- core/java/android/animation/Animator.java | 14 ++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 5c532a0aaaf54..484dbfbb4855a 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -98,6 +98,7 @@ package android.animation { public abstract class Animator implements java.lang.Cloneable { method public static long getBackgroundPauseDelay(); + method public static void setAnimatorPausingEnabled(boolean); method public static void setBackgroundPauseDelay(long); } diff --git a/core/java/android/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java index b3be42ab83466..1cb2574ae8b75 100644 --- a/core/java/android/animation/AnimationHandler.java +++ b/core/java/android/animation/AnimationHandler.java @@ -53,6 +53,9 @@ public class AnimationHandler { new ArrayList<>(); private AnimationFrameCallbackProvider mProvider; + // Static flag which allows the pausing behavior to be globally disabled/enabled. + private static boolean sAnimatorPausingEnabled = true; + /** * This paused list is used to store animators forcibly paused when the activity * went into the background (to avoid unnecessary background processing work). @@ -93,6 +96,15 @@ public class AnimationHandler { return sAnimatorHandler.get(); } + /** + * Disable the default behavior of pausing infinite animators when + * apps go into the background. + * + * @param enable Enable (default behavior) or disable background pausing behavior. + */ + public static void setAnimatorPausingEnabled(boolean enable) { + sAnimatorPausingEnabled = enable; + } /** * This is called when a window goes away. We should remove @@ -136,16 +148,19 @@ public class AnimationHandler { } else { mAnimatorRequestors.remove(requestor); } + if (!sAnimatorPausingEnabled) { + // Resume any animators that have been paused in the meantime, otherwise noop + // Leave logic above so that if pausing gets re-enabled, the state of the requestors + // list is valid + resumeAnimators(); + return; + } boolean isEmpty = mAnimatorRequestors.isEmpty(); if (wasEmpty != isEmpty) { // only paused/resume animators if there was a visibility change if (!isEmpty) { // If any requestors are enabled, resume currently paused animators - Choreographer.getInstance().removeFrameCallback(mPauser); - for (int i = mPausedAnimators.size() - 1; i >= 0; --i) { - mPausedAnimators.get(i).resume(); - } - mPausedAnimators.clear(); + resumeAnimators(); } else { // Wait before pausing to avoid thrashing animator state for temporary backgrounding Choreographer.getInstance().postFrameCallbackDelayed(mPauser, @@ -160,6 +175,14 @@ public class AnimationHandler { } } + private void resumeAnimators() { + Choreographer.getInstance().removeFrameCallback(mPauser); + for (int i = mPausedAnimators.size() - 1; i >= 0; --i) { + mPausedAnimators.get(i).resume(); + } + mPausedAnimators.clear(); + } + private Choreographer.FrameCallback mPauser = frameTimeNanos -> { if (mAnimatorRequestors.size() > 0) { // something enabled animators since this callback was scheduled - bail diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index 9e55d359b416f..f69decb087f31 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -92,6 +92,20 @@ public abstract class Animator implements Cloneable { return sBackgroundPauseDelay; } + /** + * Sets the behavior of animator pausing when apps go into the background. + * This is exposed as a test API for verification, but is intended for use by internal/ + * platform code, potentially for use by a system property that could disable it + * system wide. + * + * @param enable Enable (default behavior) or disable background pausing behavior. + * @hide + */ + @TestApi + public static void setAnimatorPausingEnabled(boolean enable) { + AnimationHandler.setAnimatorPausingEnabled(enable); + } + /** * Starts this animation. If the animation has a nonzero startDelay, the animation will start * running after that delay elapses. A non-delayed animation will have its initial