Lock free animations (2/2)

Second CL that migrates WSA to use SurfaceAnimator

We start our synchronized app transition journey by showing that
the concept works by using WindowState animations as proof of
concept.

The main class in this CL are SurfaceAnimator and
SurfaceAnimatorRunner. When we start an animation on a Window, we
create a new bufferless surface, called "The Leash", in the
hierarchy and attach the surface of WindowState onto it, while
attaching the leash onto the old surface parent which is still
responsible for z-layering.

Then, we pass off the Leash into SurfaceAnimationRunner, which then
changes the surface properties of Leash in every animation frame,
without holding the WM lock. While it's doing that we can still
update the z-layering of the window, or even relayout the window
of needed - the important surfaces for this are still under WM's
control.

In case the animation is finished the window surface gets
reparented to its original parent, and the leash is abandoned.
Note that the reparenting is done in the same transaction as
processing the animation finish, such that we don't end up with
a flicker in case of a disappearing animation, where the window
surface gets destroyed.

In case the animation needs to be cancelled, WM can revoke control
of the leash by reparenting the window surface. Even if the
cancellation signal is heavily delayed, WM immediately regains
control over the surface by reparenting it within a transaction.

We also introduce the concept of animating a WindowContainer. We
clean up isAnimating:
- isLocalAnimating: is the container itself animating
- isAnimating: is the container or one of its parents animating
- isSelfOrChildAnimating: is local animating or any child
animating.

SurfaceAnimationRunner also needs it's own thread so it's not getting
bogged down by any WM lock contention by processing regular
animation frames. We call that thread android.anim.lf (lockfree).

Now, imagine that SurfaceAnimationAnimator would sit behind an IPC in
another process and instead of animating WindowState, we'd animate
AppWindowToken. Then, synchronized app transitions would be done.

Test: go/wm-smoke
Test: SurfaceAnimatorTest
Test: SurfaceAnimationRunnerTest
Test: WindowContainerTests
Bug: 64674361

Change-Id: Idf59daa90361af57fce1128d19a0c0dbf5971d18
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eda8fec..f05cf2a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -146,6 +146,7 @@
 import android.view.MagnificationSpec;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -339,6 +340,7 @@
             new ApplySurfaceChangesTransactionState();
     private final ScreenshotApplicationState mScreenshotApplicationState =
             new ScreenshotApplicationState();
+    private final Transaction mTmpTransaction = new Transaction();
 
     // True if this display is in the process of being removed. Used to determine if the removal of
     // the display's direct children should be allowed.
@@ -381,27 +383,6 @@
 
     private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
         WindowStateAnimator winAnimator = w.mWinAnimator;
-        if (winAnimator.hasSurface()) {
-            final boolean wasAnimating = winAnimator.mWasAnimating;
-            final boolean nowAnimating = winAnimator.stepAnimationLocked(
-                    mTmpWindowAnimator.mCurrentTime);
-            winAnimator.mWasAnimating = nowAnimating;
-            mTmpWindowAnimator.orAnimating(nowAnimating);
-
-            if (DEBUG_WALLPAPER) Slog.v(TAG,
-                    w + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating);
-
-            if (wasAnimating && !winAnimator.mAnimating
-                    && mWallpaperController.isWallpaperTarget(w)) {
-                mTmpWindowAnimator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
-                pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                if (DEBUG_LAYOUT_REPEATS) {
-                    mService.mWindowPlacerLocked.debugLayoutRepeats(
-                            "updateWindowsAndWallpaperLocked 2", pendingLayoutChanges);
-                }
-            }
-        }
-
         final AppWindowToken atoken = w.mAppToken;
         if (winAnimator.mDrawState == READY_TO_SHOW) {
             if (atoken == null || atoken.allDrawn) {
@@ -434,13 +415,13 @@
 
         // If this window is animating, make a note that we have an animating window and take
         // care of a request to run a detached wallpaper animation.
-        if (winAnimator.mAnimating) {
-            if (winAnimator.mAnimation != null) {
-                if ((flags & FLAG_SHOW_WALLPAPER) != 0
-                        && winAnimator.mAnimation.getDetachWallpaper()) {
+        if (winAnimator.isAnimationSet()) {
+            final AnimationAdapter anim = w.getAnimation();
+            if (anim != null) {
+                if ((flags & FLAG_SHOW_WALLPAPER) != 0 && anim.getDetachWallpaper()) {
                     mTmpWindow = w;
                 }
-                final int color = winAnimator.mAnimation.getBackgroundColor();
+                final int color = anim.getBackgroundColor();
                 if (color != 0) {
                     final TaskStack stack = w.getStack();
                     if (stack != null) {
@@ -448,7 +429,6 @@
                     }
                 }
             }
-            mTmpWindowAnimator.setAnimating(true);
         }
 
         // If this window's app token is running a detached wallpaper animation, make a note so
@@ -684,7 +664,10 @@
             mWallpaperController.updateWallpaperVisibility();
         }
 
-        w.handleWindowMovedIfNeeded();
+        // Use mTmpTransaction instead of mPendingTransaction because we don't want to commit
+        // other changes in mPendingTransaction at this point.
+        w.handleWindowMovedIfNeeded(mTmpTransaction);
+        SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
 
         final WindowStateAnimator winAnimator = w.mWinAnimator;
 
@@ -720,7 +703,7 @@
                 }
             }
             final TaskStack stack = w.getStack();
-            if ((!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening())
+            if ((!winAnimator.isWaitingForOpening())
                     || (stack != null && stack.isAnimatingBounds())) {
                 // Updates the shown frame before we set up the surface. This is needed
                 // because the resizing could change the top-left position (in addition to
@@ -736,6 +719,12 @@
                 winAnimator.computeShownFrameLocked();
             }
             winAnimator.setSurfaceBoundariesLocked(mTmpRecoveringMemory /* recoveringMemory */);
+
+            // Since setSurfaceBoundariesLocked applies the clipping, we need to apply the position
+            // to the surface of the window container as well. Use mTmpTransaction instead of
+            // mPendingTransaction to avoid committing any existing changes in there.
+            w.updateSurfacePosition(mTmpTransaction);
+            SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
         }
 
         final AppWindowToken atoken = w.mAppToken;
@@ -2617,8 +2606,7 @@
         forAllWindows(w -> {
             if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)
                     && w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
-                w.mWinAnimator.setAnimation(
-                        policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
+                w.startAnimation(policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
             }
         }, true /* traverseTopToBottom */);
     }
@@ -3775,13 +3763,13 @@
     }
 
     @Override
-    void destroyAfterPendingTransaction(SurfaceControl surface) {
+    public void destroyAfterPendingTransaction(SurfaceControl surface) {
         mPendingDestroyingSurfaces.add(surface);
     }
 
     /**
      * Destroys any surfaces that have been put into the pending list with
-     * {@link #destroyAfterTransaction}.
+     * {@link #destroyAfterPendingTransaction}.
      */
     void onPendingTransactionApplied() {
         for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {