Loading core/api/test-current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,12 @@ package android.accessibilityservice { 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); } public class ValueAnimator extends android.animation.Animator { method @MainThread public static void setDurationScale(@FloatRange(from=0) float); } Loading core/java/android/animation/AnimationHandler.java +162 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,10 @@ package android.animation; import android.os.SystemClock; import android.os.SystemProperties; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.view.Choreographer; import java.util.ArrayList; Loading @@ -35,10 +38,13 @@ import java.util.ArrayList; * @hide */ public class AnimationHandler { private static final String TAG = "AnimationHandler"; private static final boolean LOCAL_LOGV = false; /** * Internal per-thread collections used to avoid set collisions as animations start and end * while being processed. * @hide */ private final ArrayMap<AnimationFrameCallback, Long> mDelayedCallbackStartTime = new ArrayMap<>(); Loading @@ -48,6 +54,32 @@ public class AnimationHandler { new ArrayList<>(); private AnimationFrameCallbackProvider mProvider; // Static flag which allows the pausing behavior to be globally disabled/enabled. private static boolean sAnimatorPausingEnabled = isPauseBgAnimationsEnabledInSystemProperties(); // Static flag which prevents the system property from overriding sAnimatorPausingEnabled field. private static boolean sOverrideAnimatorPausingSystemProperty = false; /** * This paused list is used to store animators forcibly paused when the activity * went into the background (to avoid unnecessary background processing work). * These animators should be resume()'d when the activity returns to the foreground. */ private final ArrayList<Animator> mPausedAnimators = new ArrayList<>(); /** * This structure is used to store the currently active objects (ViewRootImpls or * WallpaperService.Engines) in the process. Each of these objects sends a request to * AnimationHandler when it goes into the background (request to pause) or foreground * (request to resume). Because all animators are managed by AnimationHandler on the same * thread, it should only ever pause animators when *all* requestors are in the background. * This list tracks the background/foreground state of all requestors and only ever * pauses animators when all items are in the background (false). To simplify, we only ever * store visible (foreground) requestors; if the set size reaches zero, there are no * objects in the foreground and it is time to pause animators. */ private final ArraySet<Object> mAnimatorRequestors = new ArraySet<>(); private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { Loading @@ -68,6 +100,135 @@ public class AnimationHandler { return sAnimatorHandler.get(); } /** * System property that controls the behavior of pausing infinite animators when an app * is moved to the background. * * @return the value of 'framework.pause_bg_animations.enabled' system property */ private static boolean isPauseBgAnimationsEnabledInSystemProperties() { if (sOverrideAnimatorPausingSystemProperty) return sAnimatorPausingEnabled; return SystemProperties .getBoolean("framework.pause_bg_animations.enabled", true); } /** * 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; } /** * Prevents the setAnimatorPausingEnabled behavior from being overridden * by the 'framework.pause_bg_animations.enabled' system property value. * * This is for testing purposes only. * * @param enable Enable or disable (default behavior) overriding the system * property. */ public static void setOverrideAnimatorPausingSystemProperty(boolean enable) { sOverrideAnimatorPausingSystemProperty = enable; } /** * This is called when a window goes away. We should remove * it from the requestors list to ensure that we are counting requests correctly and not * tracking obsolete+enabled requestors. */ public static void removeRequestor(Object requestor) { getInstance().removeRequestorImpl(requestor); } private void removeRequestorImpl(Object requestor) { // Also request disablement, in case that requestor was the sole object keeping // animators un-paused requestAnimatorsEnabled(false, requestor); mAnimatorRequestors.remove(requestor); if (LOCAL_LOGV) { Log.v(TAG, "removeRequestorImpl for " + requestor); for (int i = 0; i < mAnimatorRequestors.size(); ++i) { Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i)); } } } /** * This method is called from ViewRootImpl or WallpaperService when either a window is no * longer visible (enable == false) or when a window becomes visible (enable == true). * If animators are not properly disabled when activities are backgrounded, it can lead to * unnecessary processing, particularly for infinite animators, as the system will continue * to pulse timing events even though the results are not visible. As a workaround, we * pause all un-paused infinite animators, and resume them when any window in the process * becomes visible. */ public static void requestAnimatorsEnabled(boolean enable, Object requestor) { getInstance().requestAnimatorsEnabledImpl(enable, requestor); } private void requestAnimatorsEnabledImpl(boolean enable, Object requestor) { boolean wasEmpty = mAnimatorRequestors.isEmpty(); setAnimatorPausingEnabled(isPauseBgAnimationsEnabledInSystemProperties()); if (enable) { mAnimatorRequestors.add(requestor); } 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 resumeAnimators(); } else { // Wait before pausing to avoid thrashing animator state for temporary backgrounding Choreographer.getInstance().postFrameCallbackDelayed(mPauser, Animator.getBackgroundPauseDelay()); } } if (LOCAL_LOGV) { Log.v(TAG, enable ? "enable" : "disable" + " animators for " + requestor); for (int i = 0; i < mAnimatorRequestors.size(); ++i) { Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i)); } } } 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 return; } for (int i = 0; i < mAnimationCallbacks.size(); ++i) { Animator animator = ((Animator) mAnimationCallbacks.get(i)); if (animator != null && animator.getTotalDuration() == Animator.DURATION_INFINITE && !animator.isPaused()) { mPausedAnimators.add(animator); animator.pause(); } } }; /** * By default, the Choreographer is used to provide timing for frame callbacks. A custom * provider can be used here to provide different timing pulse. Loading core/java/android/animation/Animator.java +44 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.animation; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ConstantState; Loading Loading @@ -63,6 +64,49 @@ public abstract class Animator implements Cloneable { */ private AnimatorConstantState mConstantState; /** * backing field for backgroundPauseDelay property. This could be simply a hardcoded * value in AnimationHandler, but it is useful to be able to change the value in tests. */ private static long sBackgroundPauseDelay = 10000; /** * Sets the duration for delaying pausing animators when apps go into the background. * Used by AnimationHandler when requested to pause animators. * * @hide */ @TestApi public static void setBackgroundPauseDelay(long value) { sBackgroundPauseDelay = value; } /** * Gets the duration for delaying pausing animators when apps go into the background. * Used by AnimationHandler when requested to pause animators. * * @hide */ @TestApi public static long getBackgroundPauseDelay() { 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); AnimationHandler.setOverrideAnimatorPausingSystemProperty(!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 Loading core/java/android/app/ApplicationExitInfo.java +27 −0 Original line number Diff line number Diff line Loading @@ -524,6 +524,13 @@ public final class ApplicationExitInfo implements Parcelable { */ private boolean mLoggedInStatsd; /** * Whether or not this process hosts one or more foreground services. * * for system internal use only, will not retain across processes. */ private boolean mHasForegroundServices; /** @hide */ @IntDef(prefix = { "REASON_" }, value = { REASON_UNKNOWN, Loading Loading @@ -996,6 +1003,24 @@ public final class ApplicationExitInfo implements Parcelable { mLoggedInStatsd = loggedInStatsd; } /** * @see #mHasForegroundServices * * @hide */ public boolean hasForegroundServices() { return mHasForegroundServices; } /** * @see #mHasForegroundServices * * @hide */ public void setHasForegroundServices(boolean hasForegroundServices) { mHasForegroundServices = hasForegroundServices; } @Override public int describeContents() { return 0; Loading Loading @@ -1060,6 +1085,8 @@ public final class ApplicationExitInfo implements Parcelable { mTraceFile = other.mTraceFile; mAppTraceRetriever = other.mAppTraceRetriever; mNativeTombstoneRetriever = other.mNativeTombstoneRetriever; mLoggedInStatsd = other.mLoggedInStatsd; mHasForegroundServices = other.mHasForegroundServices; } private ApplicationExitInfo(@NonNull Parcel in) { Loading core/java/android/app/ProcessMemoryState.java +6 −1 Original line number Diff line number Diff line Loading @@ -28,12 +28,15 @@ public final class ProcessMemoryState implements Parcelable { public final int pid; public final String processName; public final int oomScore; public final boolean hasForegroundServices; public ProcessMemoryState(int uid, int pid, String processName, int oomScore) { public ProcessMemoryState(int uid, int pid, String processName, int oomScore, boolean hasForegroundServices) { this.uid = uid; this.pid = pid; this.processName = processName; this.oomScore = oomScore; this.hasForegroundServices = hasForegroundServices; } private ProcessMemoryState(Parcel in) { Loading @@ -41,6 +44,7 @@ public final class ProcessMemoryState implements Parcelable { pid = in.readInt(); processName = in.readString(); oomScore = in.readInt(); hasForegroundServices = in.readInt() == 1; } public static final @android.annotation.NonNull Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() { Loading @@ -66,5 +70,6 @@ public final class ProcessMemoryState implements Parcelable { parcel.writeInt(pid); parcel.writeString(processName); parcel.writeInt(oomScore); parcel.writeInt(hasForegroundServices ? 1 : 0); } } Loading
core/api/test-current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,12 @@ package android.accessibilityservice { 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); } public class ValueAnimator extends android.animation.Animator { method @MainThread public static void setDurationScale(@FloatRange(from=0) float); } Loading
core/java/android/animation/AnimationHandler.java +162 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,10 @@ package android.animation; import android.os.SystemClock; import android.os.SystemProperties; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.view.Choreographer; import java.util.ArrayList; Loading @@ -35,10 +38,13 @@ import java.util.ArrayList; * @hide */ public class AnimationHandler { private static final String TAG = "AnimationHandler"; private static final boolean LOCAL_LOGV = false; /** * Internal per-thread collections used to avoid set collisions as animations start and end * while being processed. * @hide */ private final ArrayMap<AnimationFrameCallback, Long> mDelayedCallbackStartTime = new ArrayMap<>(); Loading @@ -48,6 +54,32 @@ public class AnimationHandler { new ArrayList<>(); private AnimationFrameCallbackProvider mProvider; // Static flag which allows the pausing behavior to be globally disabled/enabled. private static boolean sAnimatorPausingEnabled = isPauseBgAnimationsEnabledInSystemProperties(); // Static flag which prevents the system property from overriding sAnimatorPausingEnabled field. private static boolean sOverrideAnimatorPausingSystemProperty = false; /** * This paused list is used to store animators forcibly paused when the activity * went into the background (to avoid unnecessary background processing work). * These animators should be resume()'d when the activity returns to the foreground. */ private final ArrayList<Animator> mPausedAnimators = new ArrayList<>(); /** * This structure is used to store the currently active objects (ViewRootImpls or * WallpaperService.Engines) in the process. Each of these objects sends a request to * AnimationHandler when it goes into the background (request to pause) or foreground * (request to resume). Because all animators are managed by AnimationHandler on the same * thread, it should only ever pause animators when *all* requestors are in the background. * This list tracks the background/foreground state of all requestors and only ever * pauses animators when all items are in the background (false). To simplify, we only ever * store visible (foreground) requestors; if the set size reaches zero, there are no * objects in the foreground and it is time to pause animators. */ private final ArraySet<Object> mAnimatorRequestors = new ArraySet<>(); private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { Loading @@ -68,6 +100,135 @@ public class AnimationHandler { return sAnimatorHandler.get(); } /** * System property that controls the behavior of pausing infinite animators when an app * is moved to the background. * * @return the value of 'framework.pause_bg_animations.enabled' system property */ private static boolean isPauseBgAnimationsEnabledInSystemProperties() { if (sOverrideAnimatorPausingSystemProperty) return sAnimatorPausingEnabled; return SystemProperties .getBoolean("framework.pause_bg_animations.enabled", true); } /** * 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; } /** * Prevents the setAnimatorPausingEnabled behavior from being overridden * by the 'framework.pause_bg_animations.enabled' system property value. * * This is for testing purposes only. * * @param enable Enable or disable (default behavior) overriding the system * property. */ public static void setOverrideAnimatorPausingSystemProperty(boolean enable) { sOverrideAnimatorPausingSystemProperty = enable; } /** * This is called when a window goes away. We should remove * it from the requestors list to ensure that we are counting requests correctly and not * tracking obsolete+enabled requestors. */ public static void removeRequestor(Object requestor) { getInstance().removeRequestorImpl(requestor); } private void removeRequestorImpl(Object requestor) { // Also request disablement, in case that requestor was the sole object keeping // animators un-paused requestAnimatorsEnabled(false, requestor); mAnimatorRequestors.remove(requestor); if (LOCAL_LOGV) { Log.v(TAG, "removeRequestorImpl for " + requestor); for (int i = 0; i < mAnimatorRequestors.size(); ++i) { Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i)); } } } /** * This method is called from ViewRootImpl or WallpaperService when either a window is no * longer visible (enable == false) or when a window becomes visible (enable == true). * If animators are not properly disabled when activities are backgrounded, it can lead to * unnecessary processing, particularly for infinite animators, as the system will continue * to pulse timing events even though the results are not visible. As a workaround, we * pause all un-paused infinite animators, and resume them when any window in the process * becomes visible. */ public static void requestAnimatorsEnabled(boolean enable, Object requestor) { getInstance().requestAnimatorsEnabledImpl(enable, requestor); } private void requestAnimatorsEnabledImpl(boolean enable, Object requestor) { boolean wasEmpty = mAnimatorRequestors.isEmpty(); setAnimatorPausingEnabled(isPauseBgAnimationsEnabledInSystemProperties()); if (enable) { mAnimatorRequestors.add(requestor); } 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 resumeAnimators(); } else { // Wait before pausing to avoid thrashing animator state for temporary backgrounding Choreographer.getInstance().postFrameCallbackDelayed(mPauser, Animator.getBackgroundPauseDelay()); } } if (LOCAL_LOGV) { Log.v(TAG, enable ? "enable" : "disable" + " animators for " + requestor); for (int i = 0; i < mAnimatorRequestors.size(); ++i) { Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i)); } } } 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 return; } for (int i = 0; i < mAnimationCallbacks.size(); ++i) { Animator animator = ((Animator) mAnimationCallbacks.get(i)); if (animator != null && animator.getTotalDuration() == Animator.DURATION_INFINITE && !animator.isPaused()) { mPausedAnimators.add(animator); animator.pause(); } } }; /** * By default, the Choreographer is used to provide timing for frame callbacks. A custom * provider can be used here to provide different timing pulse. Loading
core/java/android/animation/Animator.java +44 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.animation; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ConstantState; Loading Loading @@ -63,6 +64,49 @@ public abstract class Animator implements Cloneable { */ private AnimatorConstantState mConstantState; /** * backing field for backgroundPauseDelay property. This could be simply a hardcoded * value in AnimationHandler, but it is useful to be able to change the value in tests. */ private static long sBackgroundPauseDelay = 10000; /** * Sets the duration for delaying pausing animators when apps go into the background. * Used by AnimationHandler when requested to pause animators. * * @hide */ @TestApi public static void setBackgroundPauseDelay(long value) { sBackgroundPauseDelay = value; } /** * Gets the duration for delaying pausing animators when apps go into the background. * Used by AnimationHandler when requested to pause animators. * * @hide */ @TestApi public static long getBackgroundPauseDelay() { 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); AnimationHandler.setOverrideAnimatorPausingSystemProperty(!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 Loading
core/java/android/app/ApplicationExitInfo.java +27 −0 Original line number Diff line number Diff line Loading @@ -524,6 +524,13 @@ public final class ApplicationExitInfo implements Parcelable { */ private boolean mLoggedInStatsd; /** * Whether or not this process hosts one or more foreground services. * * for system internal use only, will not retain across processes. */ private boolean mHasForegroundServices; /** @hide */ @IntDef(prefix = { "REASON_" }, value = { REASON_UNKNOWN, Loading Loading @@ -996,6 +1003,24 @@ public final class ApplicationExitInfo implements Parcelable { mLoggedInStatsd = loggedInStatsd; } /** * @see #mHasForegroundServices * * @hide */ public boolean hasForegroundServices() { return mHasForegroundServices; } /** * @see #mHasForegroundServices * * @hide */ public void setHasForegroundServices(boolean hasForegroundServices) { mHasForegroundServices = hasForegroundServices; } @Override public int describeContents() { return 0; Loading Loading @@ -1060,6 +1085,8 @@ public final class ApplicationExitInfo implements Parcelable { mTraceFile = other.mTraceFile; mAppTraceRetriever = other.mAppTraceRetriever; mNativeTombstoneRetriever = other.mNativeTombstoneRetriever; mLoggedInStatsd = other.mLoggedInStatsd; mHasForegroundServices = other.mHasForegroundServices; } private ApplicationExitInfo(@NonNull Parcel in) { Loading
core/java/android/app/ProcessMemoryState.java +6 −1 Original line number Diff line number Diff line Loading @@ -28,12 +28,15 @@ public final class ProcessMemoryState implements Parcelable { public final int pid; public final String processName; public final int oomScore; public final boolean hasForegroundServices; public ProcessMemoryState(int uid, int pid, String processName, int oomScore) { public ProcessMemoryState(int uid, int pid, String processName, int oomScore, boolean hasForegroundServices) { this.uid = uid; this.pid = pid; this.processName = processName; this.oomScore = oomScore; this.hasForegroundServices = hasForegroundServices; } private ProcessMemoryState(Parcel in) { Loading @@ -41,6 +44,7 @@ public final class ProcessMemoryState implements Parcelable { pid = in.readInt(); processName = in.readString(); oomScore = in.readInt(); hasForegroundServices = in.readInt() == 1; } public static final @android.annotation.NonNull Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() { Loading @@ -66,5 +70,6 @@ public final class ProcessMemoryState implements Parcelable { parcel.writeInt(pid); parcel.writeString(processName); parcel.writeInt(oomScore); parcel.writeInt(hasForegroundServices ? 1 : 0); } }