OSDN Git Service

Lock free animations (2/2)
authorJorim Jaggi <jjaggi@google.com>
Wed, 15 Nov 2017 13:36:26 +0000 (14:36 +0100)
committerWinson Chung <winsonc@google.com>
Thu, 14 Dec 2017 02:42:43 +0000 (18:42 -0800)
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

21 files changed:
core/java/android/view/SurfaceControl.java
services/core/java/com/android/server/wm/AppWindowToken.java
services/core/java/com/android/server/wm/DisplayContent.java
services/core/java/com/android/server/wm/DockedStackDividerController.java
services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
services/core/java/com/android/server/wm/SurfaceAnimator.java
services/core/java/com/android/server/wm/Task.java
services/core/java/com/android/server/wm/TaskStack.java
services/core/java/com/android/server/wm/WallpaperWindowToken.java
services/core/java/com/android/server/wm/WindowAnimationSpec.java
services/core/java/com/android/server/wm/WindowContainer.java
services/core/java/com/android/server/wm/WindowManagerService.java
services/core/java/com/android/server/wm/WindowState.java
services/core/java/com/android/server/wm/WindowStateAnimator.java
services/core/java/com/android/server/wm/WindowSurfaceController.java
services/core/java/com/android/server/wm/WindowSurfacePlacer.java
services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java

index 357b8d9..268e460 100644 (file)
@@ -30,6 +30,7 @@ import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.IBinder;
@@ -37,8 +38,12 @@ import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Surface.OutOfResourcesException;
+
+import com.android.internal.annotations.GuardedBy;
+
 import dalvik.system.CloseGuard;
 import libcore.util.NativeAllocationRegistry;
 
@@ -153,6 +158,13 @@ public class SurfaceControl implements Parcelable {
     private final String mName;
     long mNativeObject; // package visibility only for Surface.java access
 
+    // TODO: Move this to native.
+    private final Object mSizeLock = new Object();
+    @GuardedBy("mSizeLock")
+    private int mWidth;
+    @GuardedBy("mSizeLock")
+    private int mHeight;
+
     static Transaction sGlobalTransaction;
     static long sTransactionNestCount = 0;
 
@@ -567,6 +579,8 @@ public class SurfaceControl implements Parcelable {
         }
 
         mName = name;
+        mWidth = w;
+        mHeight = h;
         mNativeObject = nativeCreate(session, name, w, h, format, flags,
             parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
         if (mNativeObject == 0) {
@@ -582,6 +596,8 @@ public class SurfaceControl implements Parcelable {
     // event logging.
     public SurfaceControl(SurfaceControl other) {
         mName = other.mName;
+        mWidth = other.mWidth;
+        mHeight = other.mHeight;
         mNativeObject = other.mNativeObject;
         other.mCloseGuard.close();
         other.mNativeObject = 0;
@@ -590,6 +606,8 @@ public class SurfaceControl implements Parcelable {
 
     private SurfaceControl(Parcel in) {
         mName = in.readString();
+        mWidth = in.readInt();
+        mHeight = in.readInt();
         mNativeObject = nativeReadFromParcel(in);
         if (mNativeObject == 0) {
             throw new IllegalArgumentException("Couldn't read SurfaceControl from parcel=" + in);
@@ -605,6 +623,8 @@ public class SurfaceControl implements Parcelable {
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mName);
+        dest.writeInt(mWidth);
+        dest.writeInt(mHeight);
         nativeWriteToParcel(mNativeObject, dest);
     }
 
@@ -922,6 +942,18 @@ public class SurfaceControl implements Parcelable {
         }
     }
 
+    public int getWidth() {
+        synchronized (mSizeLock) {
+            return mWidth;
+        }
+    }
+
+    public int getHeight() {
+        synchronized (mSizeLock) {
+            return mHeight;
+        }
+    }
+
     @Override
     public String toString() {
         return "Surface(name=" + mName + ")/@0x" +
@@ -1282,6 +1314,7 @@ public class SurfaceControl implements Parcelable {
                 nativeGetNativeTransactionFinalizer(), 512);
         private long mNativeObject;
 
+        private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>();
         Runnable mFreeNativeResources;
 
         public Transaction() {
@@ -1312,9 +1345,22 @@ public class SurfaceControl implements Parcelable {
          * Jankier version of apply. Avoid use (b/28068298).
          */
         public void apply(boolean sync) {
+            applyResizedSurfaces();
             nativeApplyTransaction(mNativeObject, sync);
         }
 
+        private void applyResizedSurfaces() {
+            for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) {
+                final Point size = mResizedSurfaces.valueAt(i);
+                final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i);
+                synchronized (surfaceControl.mSizeLock) {
+                    surfaceControl.mWidth = size.x;
+                    surfaceControl.mHeight = size.y;
+                }
+            }
+            mResizedSurfaces.clear();
+        }
+
         public Transaction show(SurfaceControl sc) {
             sc.checkNotReleased();
             nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
@@ -1335,6 +1381,7 @@ public class SurfaceControl implements Parcelable {
 
         public Transaction setSize(SurfaceControl sc, int w, int h) {
             sc.checkNotReleased();
+            mResizedSurfaces.put(sc, new Point(w, h));
             nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
             return this;
         }
@@ -1567,6 +1614,8 @@ public class SurfaceControl implements Parcelable {
          * other transaction as if it had been applied.
          */
         public Transaction merge(Transaction other) {
+            mResizedSurfaces.putAll(other.mResizedSurfaces);
+            other.mResizedSurfaces.clear();
             nativeMergeTransaction(mNativeObject, other.mNativeObject);
             return this;
         }
index c39ce98..94a0cb7 100644 (file)
@@ -66,6 +66,7 @@ import android.view.IApplicationToken;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
+import android.view.animation.Transformation;
 
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.input.InputApplicationHandle;
@@ -75,6 +76,7 @@ import com.android.server.wm.WindowManagerService.H;
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.LinkedList;
 
 class AppTokenList extends ArrayList<AppWindowToken> {
 }
@@ -231,7 +233,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
             // If this initial window is animating, stop it -- we will do an animation to reveal
             // it from behind the starting window, so there is no need for it to also be doing its
             // own stuff.
-            winAnimator.clearAnimation();
+            win.cancelAnimation();
             if (getController() != null) {
                 getController().removeStartingWindow();
             }
@@ -389,7 +391,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
         }
 
         for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
-            if ((mChildren.get(i)).isWindowAnimationSet()) {
+            if ((mChildren.get(i)).isSelfOrChildAnimating()) {
                 delayed = true;
             }
         }
@@ -610,8 +612,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
      */
     private void destroySurfaces(boolean cleanupOnResume) {
         boolean destroyedSomething = false;
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final WindowState win = mChildren.get(i);
+
+        // Copying to a different list as multiple children can be removed.
+        // TODO: Not sure why this is needed.
+        final LinkedList<WindowState> children = new LinkedList<>(mChildren);
+        for (int i = children.size() - 1; i >= 0; i--) {
+            final WindowState win = children.get(i);
             destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
         }
         if (destroyedSomething) {
@@ -1320,7 +1326,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
                             + " pv=" + w.mPolicyVisibility
                             + " mDrawState=" + winAnimator.drawStateToString()
                             + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
-                            + " a=" + winAnimator.mAnimating);
+                            + " a=" + winAnimator.isAnimationSet());
                 }
             }
 
@@ -1520,6 +1526,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
     }
 
     @Override
+    boolean isSelfAnimating() {
+        return mAppAnimator.isAnimating();
+    }
+
+    @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
         if (appToken != null) {
index eda8fec..f05cf2a 100644 (file)
@@ -146,6 +146,7 @@ import android.view.InputDevice;
 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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
             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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
 
     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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
 
         // 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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                     }
                 }
             }
-            mTmpWindowAnimator.setAnimating(true);
         }
 
         // If this window's app token is running a detached wallpaper animation, make a note so
@@ -684,7 +664,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
             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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                 }
             }
             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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                 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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     }
 
     @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--) {
index a37598e..03c0768 100644 (file)
@@ -751,10 +751,10 @@ public class DockedStackDividerController {
 
                 // There might be an old window delaying the animation start - clear it.
                 if (mDelayedImeWin != null) {
-                    mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+                    mDelayedImeWin.endDelayingAnimationStart();
                 }
                 mDelayedImeWin = imeWin;
-                imeWin.mWinAnimator.startDelayingAnimationStart();
+                imeWin.startDelayingAnimationStart();
             }
 
             // If we are already waiting for something to be drawn, clear out the old one so it
@@ -765,25 +765,27 @@ public class DockedStackDividerController {
                 mService.mWaitingForDrawnCallback.run();
             }
             mService.mWaitingForDrawnCallback = () -> {
-                mAnimationStartDelayed = false;
-                if (mDelayedImeWin != null) {
-                    mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
-                }
-                // If the adjust status changed since this was posted, only notify
-                // the new states and don't animate.
-                long duration = 0;
-                if (mAdjustedForIme == adjustedForIme
-                        && mAdjustedForDivider == adjustedForDivider) {
-                    duration = IME_ADJUST_ANIM_DURATION;
-                } else {
-                    Slog.w(TAG, "IME adjust changed while waiting for drawn:"
-                            + " adjustedForIme=" + adjustedForIme
-                            + " adjustedForDivider=" + adjustedForDivider
-                            + " mAdjustedForIme=" + mAdjustedForIme
-                            + " mAdjustedForDivider=" + mAdjustedForDivider);
+                synchronized (mService.mWindowMap) {
+                    mAnimationStartDelayed = false;
+                    if (mDelayedImeWin != null) {
+                        mDelayedImeWin.endDelayingAnimationStart();
+                    }
+                    // If the adjust status changed since this was posted, only notify
+                    // the new states and don't animate.
+                    long duration = 0;
+                    if (mAdjustedForIme == adjustedForIme
+                            && mAdjustedForDivider == adjustedForDivider) {
+                        duration = IME_ADJUST_ANIM_DURATION;
+                    } else {
+                        Slog.w(TAG, "IME adjust changed while waiting for drawn:"
+                                + " adjustedForIme=" + adjustedForIme
+                                + " adjustedForDivider=" + adjustedForDivider
+                                + " mAdjustedForIme=" + mAdjustedForIme
+                                + " mAdjustedForDivider=" + mAdjustedForDivider);
+                    }
+                    notifyAdjustedForImeChanged(
+                            mAdjustedForIme || mAdjustedForDivider, duration);
                 }
-                notifyAdjustedForImeChanged(
-                        mAdjustedForIme || mAdjustedForDivider, duration);
             };
         } else {
             notifyAdjustedForImeChanged(
index 5bc2722..b64ce1a 100644 (file)
@@ -29,7 +29,6 @@ import android.util.ArrayMap;
 import android.view.Choreographer;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
-import android.view.animation.Transformation;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -94,9 +93,6 @@ class SurfaceAnimationRunner {
         synchronized (mLock) {
             if (mPendingAnimations.containsKey(leash)) {
                 mPendingAnimations.remove(leash);
-                // TODO: Releasing the leash is problematic if reparenting hasn't happened yet.
-                // Fix with transaction
-                //leash.release();
                 return;
             }
             final ValueAnimator anim = mRunningAnimations.get(leash);
@@ -105,7 +101,6 @@ class SurfaceAnimationRunner {
                 SurfaceAnimationThread.getHandler().post(() -> {
                     anim.cancel();
                     applyTransaction();
-                    //leash.release();
                 });
             }
         }
@@ -123,7 +118,7 @@ class SurfaceAnimationRunner {
 
         // Animation length is already expected to be scaled.
         result.overrideDurationScale(1.0f);
-        result.setDuration(a.animSpec.getDuration());
+        result.setDuration(a.mAnimSpec.getDuration());
         result.addUpdateListener(animation -> {
             applyTransformation(a, mFrameTransaction, result.getCurrentPlayTime());
 
@@ -136,7 +131,7 @@ class SurfaceAnimationRunner {
 
             @Override
             public void onAnimationStart(Animator animation) {
-                mFrameTransaction.show(a.leash);
+                mFrameTransaction.show(a.mLeash);
             }
 
             @Override
@@ -147,26 +142,20 @@ class SurfaceAnimationRunner {
             @Override
             public void onAnimationEnd(Animator animation) {
                 synchronized (mLock) {
-                    mRunningAnimations.remove(a.leash);
+                    mRunningAnimations.remove(a.mLeash);
                 }
                 if (!mCancelled) {
                     // Post on other thread that we can push final state without jank.
-                    AnimationThread.getHandler().post(() -> {
-                        a.finishCallback.run();
-
-                        // Make sure to release the leash after finishCallback has been invoked such
-                        // that reparenting is done already when releasing the leash.
-                        a.leash.release();
-                    });
+                    AnimationThread.getHandler().post(a.mFinishCallback);
                 }
             }
         });
         result.start();
-        mRunningAnimations.put(a.leash, result);
+        mRunningAnimations.put(a.mLeash, result);
     }
 
     private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
-        a.animSpec.apply(t, a.leash, currentPlayTime);
+        a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
     }
 
     private void stepAnimation(long frameTimeNanos) {
@@ -189,14 +178,14 @@ class SurfaceAnimationRunner {
     }
 
     private static final class RunningAnimation {
-        final AnimationSpec animSpec;
-        final SurfaceControl leash;
-        final Runnable finishCallback;
+        final AnimationSpec mAnimSpec;
+        final SurfaceControl mLeash;
+        final Runnable mFinishCallback;
 
         RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback) {
-            this.animSpec = animSpec;
-            this.leash = leash;
-            this.finishCallback = finishCallback;
+            mAnimSpec = animSpec;
+            mLeash = leash;
+            mFinishCallback = finishCallback;
         }
     }
 
index 713d58b..e165211 100644 (file)
@@ -97,7 +97,7 @@ class SurfaceAnimator {
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
         cancelAnimation(t, true /* restarting */);
         mAnimation = anim;
-        final SurfaceControl surface = mAnimatable.getSurface();
+        final SurfaceControl surface = mAnimatable.getSurfaceControl();
         if (surface == null) {
             Slog.w(TAG, "Unable to start animation, surface is null or no children.");
             cancelAnimation();
@@ -105,7 +105,7 @@ class SurfaceAnimator {
         }
         mLeash = createAnimationLeash(surface, t,
                 mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden);
-        mAnimatable.onLeashCreated(t, mLeash);
+        mAnimatable.onAnimationLeashCreated(t, mLeash);
         if (mAnimationStartDelayed) {
             if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
             return;
@@ -169,7 +169,16 @@ class SurfaceAnimator {
      * surface is reparented to the leash. This method takes care of that.
      */
     void setLayer(Transaction t, int layer) {
-        t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurface(), layer);
+        t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
+    }
+
+    /**
+     * Sets the surface to be relatively layered.
+     *
+     * @see #setLayer
+     */
+    void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
+        t.setRelativeLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), relativeTo, layer);
     }
 
     /**
@@ -178,7 +187,7 @@ class SurfaceAnimator {
      * @see #setLayer
      */
     void reparent(Transaction t, SurfaceControl newParent) {
-        t.reparent(mLeash != null ? mLeash : mAnimatable.getSurface(), newParent.getHandle());
+        t.reparent(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), newParent.getHandle());
     }
 
     /**
@@ -207,8 +216,8 @@ class SurfaceAnimator {
     }
 
     private void reset(Transaction t) {
-        final SurfaceControl surface = mAnimatable.getSurface();
-        final SurfaceControl parent = mAnimatable.getParentSurface();
+        final SurfaceControl surface = mAnimatable.getSurfaceControl();
+        final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
 
         // If the surface was destroyed, we don't care to reparent it back.
         final boolean destroy = mLeash != null && surface != null && parent != null;
@@ -216,19 +225,22 @@ class SurfaceAnimator {
             if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
             t.reparent(surface, parent.getHandle());
         }
+        if (mLeash != null) {
+            mAnimatable.destroyAfterPendingTransaction(mLeash);
+        }
         mLeash = null;
         mAnimation = null;
 
         // Make sure to inform the animatable after the leash was destroyed.
         if (destroy) {
-            mAnimatable.onLeashDestroyed(t);
+            mAnimatable.onAnimationLeashDestroyed(t);
         }
     }
 
     private SurfaceControl createAnimationLeash(SurfaceControl surface, Transaction t, int width,
             int height, boolean hidden) {
         if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
-        final SurfaceControl.Builder builder = mAnimatable.makeLeash()
+        final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
                 .setName(surface + " - animation-leash")
                 .setSize(width, height);
         final SurfaceControl leash = builder.build();
@@ -273,7 +285,7 @@ class SurfaceAnimator {
          * @param t The transaction to use to apply any necessary changes.
          * @param leash The leash that was created.
          */
-        void onLeashCreated(Transaction t, SurfaceControl leash);
+        void onAnimationLeashCreated(Transaction t, SurfaceControl leash);
 
         /**
          * Called when the leash is being destroyed, and the surface was reparented back to the
@@ -281,22 +293,30 @@ class SurfaceAnimator {
          *
          * @param t The transaction to use to apply any necessary changes.
          */
-        void onLeashDestroyed(Transaction t);
+        void onAnimationLeashDestroyed(Transaction t);
+
+        /**
+         * Destroy a given surface after executing {@link #getPendingTransaction}.
+         *
+         * @see WindowContainer#destroyAfterPendingTransaction
+         */
+        void destroyAfterPendingTransaction(SurfaceControl surface);
 
         /**
-         * @return A new child surface.
+         * @return A new surface to be used for the animation leash, inserted at the correct
+         *         position in the hierarchy.
          */
-        SurfaceControl.Builder makeLeash();
+        SurfaceControl.Builder makeAnimationLeash();
 
         /**
          * @return The surface of the object to be animated.
          */
-        @Nullable SurfaceControl getSurface();
+        @Nullable SurfaceControl getSurfaceControl();
 
         /**
          * @return The parent of the surface object to be animated.
          */
-        @Nullable SurfaceControl getParentSurface();
+        @Nullable SurfaceControl getParentSurfaceControl();
 
         /**
          * @return The width of the surface to be animated.
index 6ea8a47..244eb66 100644 (file)
@@ -22,7 +22,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRA
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.res.Configuration.EMPTY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -43,7 +42,6 @@ import android.graphics.Rect;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
-import android.view.DisplayInfo;
 import android.view.Surface;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -162,7 +160,7 @@ class Task extends WindowContainer<AppWindowToken> {
     boolean shouldDeferRemoval() {
         // TODO: This should probably return false if mChildren.isEmpty() regardless if the stack
         // is animating...
-        return hasWindowsAlive() && mStack.isAnimating();
+        return hasWindowsAlive() && mStack.isSelfOrChildAnimating();
     }
 
     @Override
index 28b1390..9946c6a 100644 (file)
@@ -935,7 +935,7 @@ public class TaskStack extends WindowContainer<Task> implements
 
     @Override
     void removeIfPossible() {
-        if (isAnimating()) {
+        if (isSelfOrChildAnimating()) {
             mDeferRemoval = true;
             return;
         }
@@ -1643,7 +1643,7 @@ public class TaskStack extends WindowContainer<Task> implements
 
     /** Returns true if a removal action is still being deferred. */
     boolean checkCompleteDeferredRemoval() {
-        if (isAnimating()) {
+        if (isSelfOrChildAnimating()) {
             return true;
         }
         if (mDeferRemoval) {
index a12c0e5..3389f71 100644 (file)
@@ -115,7 +115,7 @@ class WallpaperWindowToken extends WindowToken {
     void startAnimation(Animation anim) {
         for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) {
             final WindowState windowState = mChildren.get(ndx);
-            windowState.mWinAnimator.setAnimation(anim);
+            windowState.startAnimation(anim);
         }
     }
 
index 56175c7..bb25297 100644 (file)
@@ -31,7 +31,7 @@ public class WindowAnimationSpec implements AnimationSpec {
 
     private Animation mAnimation;
     private final Point mPosition = new Point();
-    private final ThreadLocal<Tmp> mThreadLocalTmps = ThreadLocal.withInitial(Tmp::new);
+    private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
 
     public WindowAnimationSpec(Animation animation, Point position)  {
         mAnimation = animation;
@@ -55,7 +55,7 @@ public class WindowAnimationSpec implements AnimationSpec {
 
     @Override
     public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
-        final Tmp tmp = mThreadLocalTmps.get();
+        final TmpValues tmp = mThreadLocalTmps.get();
         tmp.transformation.clear();
         mAnimation.getTransformation(currentPlayTime, tmp.transformation);
         tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
@@ -63,7 +63,7 @@ public class WindowAnimationSpec implements AnimationSpec {
         t.setAlpha(leash, tmp.transformation.getAlpha());
     }
 
-    private static class Tmp {
+    private static class TmpValues {
         final Transformation transformation = new Transformation();
         final float[] floats = new float[9];
     }
index d6329bf..b2b6119 100644 (file)
@@ -19,6 +19,9 @@ package com.android.server.wm;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
 import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
 import static com.android.server.wm.proto.WindowContainerProto.VISIBLE;
@@ -26,14 +29,20 @@ import static android.view.SurfaceControl.Transaction;
 
 import android.annotation.CallSuper;
 import android.content.res.Configuration;
+import android.graphics.PixelFormat.Opacity;
+import android.util.Slog;
 import android.view.MagnificationSpec;
 import android.view.SurfaceControl;
+import android.view.SurfaceControl.Builder;
 import android.view.SurfaceSession;
 import android.util.Pools;
 
 import android.util.proto.ProtoOutputStream;
+
 import com.android.internal.util.ToBooleanFunction;
+import com.android.server.wm.SurfaceAnimator.Animatable;
 
+import java.io.PrintWriter;
 import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.function.Consumer;
@@ -46,7 +55,9 @@ import java.util.function.Predicate;
  * changes are made to this class.
  */
 class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
-        implements Comparable<WindowContainer> {
+        implements Comparable<WindowContainer>, Animatable {
+
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
 
     static final int POSITION_TOP = Integer.MAX_VALUE;
     static final int POSITION_BOTTOM = Integer.MIN_VALUE;
@@ -56,7 +67,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
      * For removing or setting new parent {@link #setParent} should be used, because it also
      * performs configuration updates based on new parent's settings.
      */
-    private WindowContainer mParent = null;
+    private WindowContainer<WindowContainer> mParent = null;
 
     // List of children for this window container. List is in z-order as the children appear on
     // screen with the top-most window container at the tail of the list.
@@ -69,7 +80,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
             new Pools.SynchronizedPool<>(3);
 
     // The owner/creator for this container. No controller if null.
-     WindowContainerController mController;
+    WindowContainerController mController;
 
     protected SurfaceControl mSurfaceControl;
     private int mLastLayer = 0;
@@ -78,12 +89,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     /**
      * Applied as part of the animation pass in "prepareSurfaces".
      */
-    private final Transaction mPendingTransaction;
+    protected final Transaction mPendingTransaction;
+    protected final SurfaceAnimator mSurfaceAnimator;
     protected final WindowManagerService mService;
 
     WindowContainer(WindowManagerService service) {
         mService = service;
         mPendingTransaction = service.mTransactionFactory.make();
+        mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
     }
 
     @Override
@@ -101,7 +114,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
         return mChildren.get(index);
     }
 
-    final protected void setParent(WindowContainer parent) {
+    final protected void setParent(WindowContainer<WindowContainer> parent) {
         mParent = parent;
         // Removing parent usually means that we've detached this entity to destroy it or to attach
         // to another parent. In both cases we don't need to update the configuration now.
@@ -123,14 +136,18 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
         if (mParent == null) {
             return;
         }
+
         if (mSurfaceControl == null) {
             // If we don't yet have a surface, but we now have a parent, we should
             // build a surface.
             mSurfaceControl = makeSurface().build();
             getPendingTransaction().show(mSurfaceControl);
         } else {
-            // If we have a surface but a new parent, we just need to perform a reparent.
-            getPendingTransaction().reparent(mSurfaceControl, mParent.mSurfaceControl.getHandle());
+            // If we have a surface but a new parent, we just need to perform a reparent. Go through
+            // surface animator such that hierarchy is preserved when animating, i.e.
+            // mSurfaceControl stays attached to the leash and we just reparent the leash to the
+            // new parent.
+            mSurfaceAnimator.reparent(getPendingTransaction(), mParent.mSurfaceControl);
         }
 
         // Either way we need to ask the parent to assign us a Z-order.
@@ -139,8 +156,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     }
 
     // Temp. holders for a chain of containers we are currently processing.
-    private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
-    private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
+    private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList<>();
+    private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList<>();
 
     /**
      * Adds the input window container has a child of this container in order based on the input
@@ -214,7 +231,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     @CallSuper
     void removeImmediately() {
         while (!mChildren.isEmpty()) {
-            final WindowContainer child = mChildren.peekLast();
+            final E child = mChildren.peekLast();
             child.removeImmediately();
             // Need to do this after calling remove on the child because the child might try to
             // remove/detach itself from its parent which will cause an exception if we remove
@@ -401,16 +418,40 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
         }
     }
 
-    boolean isAnimating() {
+    /**
+     * @return Whether our own container is running an animation or any child, no matter how deep in
+     *         the hierarchy, is animating.
+     */
+    boolean isSelfOrChildAnimating() {
+        if (isSelfAnimating()) {
+            return true;
+        }
         for (int j = mChildren.size() - 1; j >= 0; j--) {
             final WindowContainer wc = mChildren.get(j);
-            if (wc.isAnimating()) {
+            if (wc.isSelfOrChildAnimating()) {
                 return true;
             }
         }
         return false;
     }
 
+    /**
+     * @return Whether our own container is running an animation or our parent is animating. This
+     *         doesn't consider whether children are animating.
+     */
+    boolean isAnimating() {
+
+        // We are animating if we ourselves are animating or if our parent is animating.
+        return isSelfAnimating() || mParent != null && mParent.isAnimating();
+    }
+
+    /**
+     * @return Whether our own container running an animation at the moment.
+     */
+    boolean isSelfAnimating() {
+        return mSurfaceAnimator.isAnimating();
+    }
+
     void sendAppVisibilityToClients() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowContainer wc = mChildren.get(i);
@@ -743,6 +784,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
                 .setParent(mSurfaceControl);
     }
 
+    @Override
+    public SurfaceControl getParentSurfaceControl() {
+        final WindowContainer parent = getParent();
+        if (parent == null) {
+            return null;
+        }
+        return parent.getSurfaceControl();
+    }
+
     /**
      * @return Whether this WindowContainer should be magnified by the accessibility magnifier.
      */
@@ -765,7 +815,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     void assignLayer(Transaction t, int layer) {
         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
         if (mSurfaceControl != null && changed) {
-            t.setLayer(mSurfaceControl, layer);
+
+            // Route through surface animator to accommodate that our surface control might be
+            // attached to the leash, and leash is attached to parent container.
+            mSurfaceAnimator.setLayer(t, layer);
             mLastLayer = layer;
             mLastRelativeToLayer = null;
         }
@@ -774,7 +827,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
         if (mSurfaceControl != null && changed) {
-            t.setRelativeLayer(mSurfaceControl, relativeTo, layer);
+
+            // Route through surface animator to accommodate that our surface control might be
+            // attached to the leash, and leash is attached to parent container.
+            mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
             mLastLayer = layer;
             mLastRelativeToLayer = relativeTo;
         }
@@ -897,7 +953,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
         }
     }
 
-    SurfaceControl getSurfaceControl() {
+    @Override
+    public SurfaceControl getSurfaceControl() {
         return mSurfaceControl;
     }
 
@@ -907,13 +964,105 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
      * rather than an intentional design, so please take care when
      * expanding use.
      */
-    void destroyAfterPendingTransaction(SurfaceControl surface) {
+    @Override
+    public void destroyAfterPendingTransaction(SurfaceControl surface) {
         if (mParent != null) {
             mParent.destroyAfterPendingTransaction(surface);
         }
     }
-    
-    Transaction getPendingTransaction() {
+
+    @Override
+    public Transaction getPendingTransaction() {
         return mPendingTransaction;
     }
+
+    /**
+     * Starts an animation on the container.
+     *
+     * @param anim The animation to run.
+     * @param hidden Whether our container is currently hidden. TODO This should use isVisible at
+     *               some point but the meaning is too weird to work for all containers.
+     */
+    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
+        if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim);
+
+        // TODO: This should use isVisible() but because isVisible has a really weird meaning at
+        // the moment this doesn't work for all animatable window containers.
+        mSurfaceAnimator.startAnimation(t, anim, hidden);
+    }
+
+    void cancelAnimation() {
+        mSurfaceAnimator.cancelAnimation();
+    }
+
+    @Override
+    public Builder makeAnimationLeash() {
+        return makeSurface();
+    }
+
+    @Override
+    public void commitPendingTransaction() {
+        scheduleAnimation();
+    }
+
+    private void reassignLayer(Transaction t) {
+        final WindowContainer parent = getParent();
+        if (parent != null) {
+            parent.assignChildLayers(t);
+        }
+    }
+
+    @Override
+    public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+        reassignLayer(t);
+    }
+
+    @Override
+    public void onAnimationLeashDestroyed(Transaction t) {
+        reassignLayer(t);
+    }
+
+    /**
+     * Called when an animation has finished running.
+     */
+    protected void onAnimationFinished() {
+    }
+
+    /**
+     * @return The currently running animation, if any, or {@code null} otherwise.
+     */
+    AnimationAdapter getAnimation() {
+        return mSurfaceAnimator.getAnimation();
+    }
+
+    /**
+     * @see SurfaceAnimator#startDelayingAnimationStart
+     */
+    void startDelayingAnimationStart() {
+        mSurfaceAnimator.startDelayingAnimationStart();
+    }
+
+    /**
+     * @see SurfaceAnimator#endDelayingAnimationStart
+     */
+    void endDelayingAnimationStart() {
+        mSurfaceAnimator.endDelayingAnimationStart();
+    }
+
+    @Override
+    public int getSurfaceWidth() {
+        return mSurfaceControl.getWidth();
+    }
+
+    @Override
+    public int getSurfaceHeight() {
+        return mSurfaceControl.getHeight();
+    }
+
+    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        if (mSurfaceAnimator.isAnimating()) {
+            pw.print(prefix); pw.println("ContainerAnimator:");
+            mSurfaceAnimator.dump(pw, prefix + "  ");
+        }
+    }
 }
index 8c9948e..7a3ba74 100644 (file)
@@ -725,8 +725,6 @@ public class WindowManagerService extends IWindowManager.Stub
         }
     }
 
-    boolean mAnimateWallpaperWithTarget;
-
     // TODO: Move to RootWindowContainer
     AppWindowToken mFocusedApp = null;
 
@@ -2182,18 +2180,15 @@ public class WindowManagerService extends IWindowManager.Stub
         if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
             focusMayChange = isDefaultDisplay;
             win.mAnimatingExit = true;
-            win.mWinAnimator.mAnimating = true;
         } else if (win.mWinAnimator.isAnimationSet()) {
             // Currently in a hide animation... turn this into
             // an exit.
             win.mAnimatingExit = true;
-            win.mWinAnimator.mAnimating = true;
         } else if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
             // If the wallpaper is currently behind this
             // window, we need to change both of them inside
             // of a transaction to avoid artifacts.
             win.mAnimatingExit = true;
-            win.mWinAnimator.mAnimating = true;
         } else {
             if (mInputMethodWindow == win) {
                 setInputMethodWindowLocked(null);
index e38605d..559d5b6 100644 (file)
@@ -19,11 +19,11 @@ package com.android.server.wm;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.SurfaceControl.Transaction;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-import static android.view.SurfaceControl.Transaction;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
@@ -91,6 +91,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIG
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -160,10 +161,14 @@ import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.WindowInfo;
 import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.input.InputWindowHandle;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -594,6 +599,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
      */
     private boolean mDrawnStateEvaluated;
 
+    private final Point mSurfacePosition = new Point();
+
     /**
      * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
      * of z-order and 1 otherwise.
@@ -1470,9 +1477,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         final AppWindowToken atoken = mAppToken;
         if (atoken != null) {
             return ((!isParentWindowHidden() && !atoken.hiddenRequested)
-                    || mWinAnimator.mAnimation != null || atoken.mAppAnimator.animation != null);
+                    || mWinAnimator.isAnimationSet() || atoken.mAppAnimator.animation != null);
         }
-        return !isParentWindowHidden() || mWinAnimator.mAnimation != null;
+        return !isParentWindowHidden() || mWinAnimator.isAnimationSet();
     }
 
     /**
@@ -1505,7 +1512,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         }
         return mHasSurface && mPolicyVisibility && !mDestroying
                 && ((!isParentWindowHidden() && mViewVisibility == View.VISIBLE && !mToken.hidden)
-                        || mWinAnimator.mAnimation != null
+                        || mWinAnimator.isAnimationSet()
                         || ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null)));
     }
 
@@ -1520,8 +1527,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         // started.
         final boolean appAnimationStarting = mAppToken != null
                 && mAppToken.mAppAnimator.isAnimationStarting();
-        final boolean exitingSelf = mAnimatingExit && (!mWinAnimator.isAnimationStarting()
-                && !appAnimationStarting);
+        final boolean exitingSelf = mAnimatingExit && !appAnimationStarting;
         final boolean appExiting = mAppToken != null && mAppToken.hidden && !appAnimationStarting;
 
         final boolean exiting = exitingSelf || mDestroying || appExiting;
@@ -1544,7 +1550,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         return isDrawnLw() && mPolicyVisibility
             && ((!isParentWindowHidden() &&
                     (atoken == null || !atoken.hiddenRequested))
-                        || mWinAnimator.mAnimating
+                        || mWinAnimator.isAnimationSet()
                         || (atoken != null && atoken.mAppAnimator.animation != null));
     }
 
@@ -1553,7 +1559,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
      */
     @Override
     public boolean isAnimatingLw() {
-        return mWinAnimator.mAnimation != null
+        return mWinAnimator.isAnimationSet()
                 || (mAppToken != null && mAppToken.mAppAnimator.animation != null);
     }
 
@@ -1600,7 +1606,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         // to determine if it's occluding apps.
         return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
                 || (mIsWallpaper && mWallpaperVisible))
-                && isDrawnLw() && mWinAnimator.mAnimation == null
+                && isDrawnLw() && !mWinAnimator.isAnimationSet()
                 && (mAppToken == null || mAppToken.mAppAnimator.animation == null);
     }
 
@@ -1732,7 +1738,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
      * listeners and optionally animate it. Simply checking a change of position is not enough,
      * because being move due to dock divider is not a trigger for animation.
      */
-    void handleWindowMovedIfNeeded() {
+    void handleWindowMovedIfNeeded(Transaction t) {
         if (!hasMoved()) {
             return;
         }
@@ -1750,7 +1756,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                 && !isDragResizing() && !adjustedForMinimizedDockOrIme
                 && getWindowConfiguration().hasMovementAnimations()
                 && !mWinAnimator.mLastHidden) {
-            mWinAnimator.setMoveAnimation(left, top);
+            startMoveAnimation(t, left, top);
         }
 
         //TODO (multidisplay): Accessibility supported only for the default display.
@@ -2457,10 +2463,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
         if (doAnimation) {
             if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
-                    + mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation);
+                    + mPolicyVisibility + " isAnimationSet=" + mWinAnimator.isAnimationSet());
             if (!mToken.okToAnimate()) {
                 doAnimation = false;
-            } else if (mPolicyVisibility && mWinAnimator.mAnimation == null) {
+            } else if (mPolicyVisibility && !mWinAnimator.isAnimationSet()) {
                 // Check for the case where we are currently visible and
                 // not animating; we do not want to do animation at such a
                 // point to become visible when we already are.
@@ -2499,7 +2505,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         }
         if (doAnimation) {
             mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
-            if (mWinAnimator.mAnimation == null) {
+            if (!mWinAnimator.isAnimationSet()) {
                 doAnimation = false;
             }
         }
@@ -2599,14 +2605,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
     }
 
-    @Override
-    boolean isAnimating() {
-        if (mWinAnimator.isAnimationSet() || mAnimatingExit) {
-            return true;
-        }
-        return super.isAnimating();
-    }
-
     void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
         animators.add(mWinAnimator);
 
@@ -3133,6 +3131,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         proto.end(token);
     }
 
+    @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         final TaskStack stack = getStack();
         pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
@@ -3275,6 +3274,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                     pw.print(" cutout=" + mLastDisplayCutout);
                     pw.println();
         }
+        super.dump(pw, prefix, dumpAll);
         pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
         mWinAnimator.dump(pw, prefix + "  ", dumpAll);
         if (mAnimatingExit || mRemoveOnExit || mDestroying || mRemoved) {
@@ -3333,7 +3333,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
     @Override
     String getName() {
         return Integer.toHexString(System.identityHashCode(this))
-            + " " + getWindowTag();
+                + " " + getWindowTag();
     }
 
     CharSequence getWindowTag() {
@@ -3694,7 +3694,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                     + " tok.hiddenRequested="
                     + (mAppToken != null && mAppToken.hiddenRequested)
                     + " tok.hidden=" + (mAppToken != null && mAppToken.hidden)
-                    + " animating=" + mWinAnimator.mAnimating
+                    + " animationSet=" + mWinAnimator.isAnimationSet()
                     + " tok animating="
                     + (mWinAnimator.mAppAnimator != null && mWinAnimator.mAppAnimator.animating)
                     + " Callers=" + Debug.getCallers(4));
@@ -3900,23 +3900,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         return null;
     }
 
-    boolean isWindowAnimationSet() {
-        if (mWinAnimator.isWindowAnimationSet()) {
-            return true;
-        }
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowState c = mChildren.get(i);
-            if (c.isWindowAnimationSet()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     void onExitAnimationDone() {
         if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this
                 + ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit
-                + " windowAnimating=" + mWinAnimator.isWindowAnimationSet());
+                + " selfAnimating=" + isSelfAnimating());
 
         if (!mChildren.isEmpty()) {
             // Copying to a different list as multiple children can be removed.
@@ -3940,18 +3927,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
             }
         }
 
-        if (!mWinAnimator.isWindowAnimationSet()) {
-            //TODO (multidisplay): Accessibility is supported only for the default display.
-            if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
-                mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
-            }
+        if (isSelfAnimating()) {
+            return;
         }
 
-        if (!mAnimatingExit) {
-            return;
+        //TODO (multidisplay): Accessibility is supported only for the default display.
+        if (mService.mAccessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
+            mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
         }
 
-        if (mWinAnimator.isWindowAnimationSet()) {
+        if (!mAnimatingExit) {
             return;
         }
 
@@ -4005,10 +3990,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                 mAnimatingExit = false;
                 didSomething = true;
             }
-            if (mWinAnimator.mAnimating) {
-                mWinAnimator.mAnimating = false;
-                didSomething = true;
-            }
             if (mDestroying) {
                 mDestroying = false;
                 mService.mDestroySurface.remove(this);
@@ -4097,7 +4078,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                         + " mDrawState=" + mWinAnimator.mDrawState
                         + " ph=" + isParentWindowHidden()
                         + " th=" + (mAppToken != null ? mAppToken.hiddenRequested : false)
-                        + " a=" + mWinAnimator.mAnimating);
+                        + " a=" + mWinAnimator.isAnimationSet());
             }
         }
 
@@ -4300,6 +4281,35 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         mLastDisplayCutout = mDisplayCutout;
     }
 
+    void startAnimation(Animation anim) {
+        final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+        anim.initialize(mFrame.width(), mFrame.height(),
+                displayInfo.appWidth, displayInfo.appHeight);
+        anim.restrictDuration(MAX_ANIMATION_DURATION);
+        anim.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
+        final AnimationAdapter adapter = new LocalAnimationAdapter(
+                new WindowAnimationSpec(anim, mSurfacePosition), mService.mSurfaceAnimationRunner);
+        startAnimation(mPendingTransaction, adapter);
+        commitPendingTransaction();
+    }
+
+    private void startMoveAnimation(Transaction t, int left, int top) {
+        if (DEBUG_ANIM) Slog.v(TAG, "Setting move animation on " + this);
+        final AnimationAdapter adapter = new LocalAnimationAdapter(
+                new MoveAnimationSpec(mLastFrame.left, mLastFrame.top, left, top),
+                mService.mSurfaceAnimationRunner);
+        startAnimation(t, adapter);
+    }
+
+    private void startAnimation(Transaction t, AnimationAdapter adapter) {
+        startAnimation(t, adapter, mWinAnimator.mLastHidden);
+    }
+
+    @Override
+    protected void onAnimationFinished() {
+        mWinAnimator.onAnimationFinished();
+    }
+
     // TODO: Hack to work around the number of states AppWindowToken needs to access without having
     // access to its windows children. Need to investigate re-writing
     // {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed.
@@ -4381,11 +4391,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
         return getAnimLayerAdjustment() > 0 || mWillReplaceWindow;
     }
 
-    @Override
-    SurfaceControl.Builder makeSurface() {
-        return getParent().makeChildSurface(this);
-    }
-
     private void applyDims(Dimmer dimmer) {
         if (!mAnimatingExit && mAppDied) {
             mIsDimming = true;
@@ -4405,11 +4410,47 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
             applyDims(dimmer);
         }
 
+        updateSurfacePosition(mPendingTransaction);
+
         mWinAnimator.prepareSurfaceLocked(true);
         super.prepareSurfaces();
     }
 
     @Override
+    public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+        super.onAnimationLeashCreated(t, leash);
+
+        // Leash is now responsible for position, so set our position to 0.
+        t.setPosition(mSurfaceControl, 0, 0);
+    }
+
+    @Override
+    public void onAnimationLeashDestroyed(Transaction t) {
+        super.onAnimationLeashDestroyed(t);
+        updateSurfacePosition(t);
+    }
+
+    void updateSurfacePosition(Transaction t) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+
+        int left = mFrame.left;
+        int top = mFrame.top;
+        if (isChildWindow()) {
+            // TODO: This probably falls apart at some point and we should
+            // actually compute relative coordinates.
+            final WindowState parent = getParentWindow();
+            left -= parent.mFrame.left;
+            top -= parent.mFrame.top;
+        }
+        mSurfacePosition.set(left, top);
+        if (!mSurfaceAnimator.hasLeash()) {
+            t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+        }
+    }
+
+    @Override
     void assignLayer(Transaction t, int layer) {
         // See comment in assignRelativeLayerForImeTargetChild
         if (!isChildWindow()
@@ -4449,4 +4490,34 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
             layer++;
         }
     }
+
+    private final class MoveAnimationSpec implements AnimationSpec {
+
+        private final long mDuration;
+        private Interpolator mInterpolator;
+        private Point mFrom = new Point();
+        private Point mTo = new Point();
+
+        private MoveAnimationSpec(int fromX, int fromY, int toX, int toY) {
+            final Animation anim = AnimationUtils.loadAnimation(mContext,
+                    com.android.internal.R.anim.window_move_from_decor);
+            mDuration = anim.computeDurationHint();
+            mInterpolator = anim.getInterpolator();
+            mFrom.set(fromX, fromY);
+            mTo.set(toX, toY);
+        }
+
+        @Override
+        public long getDuration() {
+            return mDuration;
+        }
+
+        @Override
+        public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
+            final float fraction = (float) currentPlayTime / getDuration();
+            final float v = mInterpolator.getInterpolation(fraction);
+            t.setPosition(leash, mFrom.x + (mTo.x - mFrom.x) * v,
+                    mFrom.y + (mTo.y - mFrom.y) * v);
+        }
+    }
 }
index 54c84ea..e3d2d1c 100644 (file)
@@ -23,16 +23,16 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CO
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
@@ -40,7 +40,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
-import static com.android.server.wm.WindowManagerService.localLOGV;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
@@ -65,14 +64,13 @@ import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
 import com.android.server.policy.WindowManagerPolicy;
 
-import java.io.PrintWriter;
 import java.io.FileDescriptor;
+import java.io.PrintWriter;
 
 /**
  * Keep track of animations and surface operations for a single WindowState.
@@ -112,20 +110,9 @@ class WindowStateAnimator {
     final boolean mIsWallpaper;
     private final WallpaperController mWallpaperControllerLocked;
 
-    // Currently running animation.
-    boolean mAnimating;
-    boolean mLocalAnimating;
-    Animation mAnimation;
     boolean mAnimationIsEntrance;
-    boolean mHasTransformation;
-    boolean mHasLocalTransformation;
-    final Transformation mTransformation = new Transformation();
-    boolean mWasAnimating;      // Were we animating going into the most recent animation step?
     int mAnimLayer;
     int mLastLayer;
-    long mAnimationStartTime;
-    long mLastAnimationTime;
-    int mStackClip = STACK_CLIP_BEFORE_ANIM;
 
     /**
      * Set when we have changed the size of the surface, to know that
@@ -168,13 +155,6 @@ class WindowStateAnimator {
     private final Rect mSystemDecorRect = new Rect();
     private final Rect mLastSystemDecorRect = new Rect();
 
-    // Used to save animation distances between the time they are calculated and when they are used.
-    private int mAnimDx;
-    private int mAnimDy;
-
-    /** Is the next animation to be started a window move animation? */
-    private boolean mAnimateMove = false;
-
     float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
     private float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
 
@@ -226,8 +206,6 @@ class WindowStateAnimator {
 
     int mAttrType;
 
-    static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
-
     boolean mForceScaleUntilResize;
 
     // WindowState.mHScale and WindowState.mVScale contain the
@@ -247,15 +225,6 @@ class WindowStateAnimator {
         mAnimator = service.mAnimator;
         mPolicy = service.mPolicy;
         mContext = service.mContext;
-        final DisplayContent displayContent = win.getDisplayContent();
-        if (displayContent != null) {
-            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-            mAnimDx = displayInfo.appWidth;
-            mAnimDy = displayInfo.appHeight;
-        } else {
-            Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed");
-            // This is checked on return and dealt with.
-        }
 
         mWin = win;
         mParentWinAnimator = !win.isChildWindow() ? null : win.getParentWindow().mWinAnimator;
@@ -266,54 +235,11 @@ class WindowStateAnimator {
         mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
     }
 
-    public void setAnimation(Animation anim, long startTime, int stackClip) {
-        if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
-        mAnimating = false;
-        mLocalAnimating = false;
-        mAnimation = anim;
-        mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
-        mAnimation.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
-        // Start out animation gone if window is gone, or visible if window is visible.
-        mTransformation.clear();
-        mTransformation.setAlpha(mLastHidden ? 0 : 1);
-        mHasLocalTransformation = true;
-        mAnimationStartTime = startTime;
-        mStackClip = stackClip;
-    }
-
-    public void setAnimation(Animation anim, int stackClip) {
-        setAnimation(anim, -1, stackClip);
-    }
-
-    public void setAnimation(Animation anim) {
-        setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
-    }
-
-    public void clearAnimation() {
-        if (mAnimation != null) {
-            mAnimating = true;
-            mLocalAnimating = false;
-            mAnimation.cancel();
-            mAnimation = null;
-            mStackClip = STACK_CLIP_BEFORE_ANIM;
-        }
-    }
-
     /**
      * Is the window or its container currently set to animate or currently animating?
      */
     boolean isAnimationSet() {
-        return mAnimation != null
-                || (mParentWinAnimator != null && mParentWinAnimator.mAnimation != null)
-                || (mAppAnimator != null && mAppAnimator.isAnimating());
-    }
-
-    /**
-     * @return whether an animation is about to start, i.e. the animation is set already but we
-     *         haven't processed the first frame yet.
-     */
-    boolean isAnimationStarting() {
-        return isAnimationSet() && !mAnimating;
+        return mWin.isAnimating();
     }
 
     /** Is the window animating the DummyAnimation? */
@@ -323,13 +249,6 @@ class WindowStateAnimator {
     }
 
     /**
-     * Is this window currently set to animate or currently animating?
-     */
-    boolean isWindowAnimationSet() {
-        return mAnimation != null;
-    }
-
-    /**
      * Is this window currently waiting to run an opening animation?
      */
     boolean isWaitingForOpening() {
@@ -341,130 +260,23 @@ class WindowStateAnimator {
         if (DEBUG_ANIM) Slog.d(TAG,
                 "cancelExitAnimationForNextAnimationLocked: " + mWin);
 
-        if (mAnimation != null) {
-            mAnimation.cancel();
-            mAnimation = null;
-            mLocalAnimating = false;
-            mWin.destroySurfaceUnchecked();
-        }
+        mWin.cancelAnimation();
+        mWin.destroySurfaceUnchecked();
     }
 
-    private boolean stepAnimation(long currentTime) {
-        if ((mAnimation == null) || !mLocalAnimating) {
-            return false;
-        }
-        currentTime = getAnimationFrameTime(mAnimation, currentTime);
-        mTransformation.clear();
-        final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
-        if (mAnimationStartDelayed && mAnimationIsEntrance) {
-            mTransformation.setAlpha(0f);
-        }
-        if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
-                + ", xform=" + mTransformation);
-        return more;
-    }
-
-    // This must be called while inside a transaction.  Returns true if
-    // there is more animation to run.
-    boolean stepAnimationLocked(long currentTime) {
-        // Save the animation state as it was before this step so WindowManagerService can tell if
-        // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
-        mWasAnimating = mAnimating;
-        final DisplayContent displayContent = mWin.getDisplayContent();
-        if (mWin.mToken.okToAnimate()) {
-            // We will run animations as long as the display isn't frozen.
-
-            if (mWin.isDrawnLw() && mAnimation != null) {
-                mHasTransformation = true;
-                mHasLocalTransformation = true;
-                if (!mLocalAnimating) {
-                    if (DEBUG_ANIM) Slog.v(
-                        TAG, "Starting animation in " + this +
-                        " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
-                        " wh=" + mWin.mFrame.height() +
-                        " dx=" + mAnimDx + " dy=" + mAnimDy +
-                        " scale=" + mService.getWindowAnimationScaleLocked());
-                    final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-                    if (mAnimateMove) {
-                        mAnimateMove = false;
-                        mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
-                                mAnimDx, mAnimDy);
-                    } else {
-                        mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
-                                displayInfo.appWidth, displayInfo.appHeight);
-                    }
-                    mAnimDx = displayInfo.appWidth;
-                    mAnimDy = displayInfo.appHeight;
-                    mAnimation.setStartTime(mAnimationStartTime != -1
-                            ? mAnimationStartTime
-                            : currentTime);
-                    mLocalAnimating = true;
-                    mAnimating = true;
-                }
-                if ((mAnimation != null) && mLocalAnimating) {
-                    mLastAnimationTime = currentTime;
-                    if (stepAnimation(currentTime)) {
-                        return true;
-                    }
-                }
-                if (DEBUG_ANIM) Slog.v(
-                    TAG, "Finished animation in " + this +
-                    " @ " + currentTime);
-                //WindowManagerService.this.dump();
-            }
-            mHasLocalTransformation = false;
-            if ((!mLocalAnimating || mAnimationIsEntrance) && mAppAnimator != null
-                    && mAppAnimator.animation != null) {
-                // When our app token is animating, we kind-of pretend like
-                // we are as well.  Note the mLocalAnimating mAnimationIsEntrance
-                // part of this check means that we will only do this if
-                // our window is not currently exiting, or it is not
-                // locally animating itself.  The idea being that one that
-                // is exiting and doing a local animation should be removed
-                // once that animation is done.
-                mAnimating = true;
-                mHasTransformation = true;
-                mTransformation.clear();
-                return false;
-            } else if (mHasTransformation) {
-                // Little trick to get through the path below to act like
-                // we have finished an animation.
-                mAnimating = true;
-            } else if (isAnimationSet()) {
-                mAnimating = true;
-            }
-        } else if (mAnimation != null) {
-            // If the display is frozen, and there is a pending animation,
-            // clear it and make sure we run the cleanup code.
-            mAnimating = true;
-        }
-
-        if (!mAnimating && !mLocalAnimating) {
-            return false;
-        }
-
+    void onAnimationFinished() {
         // Done animating, clean up.
         if (DEBUG_ANIM) Slog.v(
-            TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
-            + ", reportedVisible="
-            + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
+                TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
+                        + ", reportedVisible="
+                        + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
 
-        mAnimating = false;
-        mLocalAnimating = false;
-        if (mAnimation != null) {
-            mAnimation.cancel();
-            mAnimation = null;
-        }
         if (mAnimator.mWindowDetachedWallpaper == mWin) {
             mAnimator.mWindowDetachedWallpaper = null;
         }
-        mAnimLayer = mWin.getSpecialWindowAnimLayerAdjustment();
-        if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
-        mHasTransformation = false;
-        mHasLocalTransformation = false;
-        mStackClip = STACK_CLIP_BEFORE_ANIM;
+
         mWin.checkPolicyVisibilityChange();
-        mTransformation.clear();
+        final DisplayContent displayContent = mWin.getDisplayContent();
         if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
             // Upon completion of a not-visible to visible status bar animation a relayout is
             // required.
@@ -475,7 +287,11 @@ class WindowStateAnimator {
 
         mWin.onExitAnimationDone();
         final int displayId = mWin.getDisplayId();
-        mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
+        int pendingLayoutChanges = FINISH_LAYOUT_REDO_ANIM;
+        if (displayContent.mWallpaperController.isWallpaperTarget(mWin)) {
+            pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+        }
+        mAnimator.setPendingLayoutChanges(displayId, pendingLayoutChanges);
         if (DEBUG_LAYOUT_REPEATS)
             mService.mWindowPlacerLocked.debugLayoutRepeats(
                     "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
@@ -483,8 +299,6 @@ class WindowStateAnimator {
         if (mWin.mAppToken != null) {
             mWin.mAppToken.updateReportedVisibilityLocked();
         }
-
-        return false;
     }
 
     void hide(String reason) {
@@ -683,8 +497,8 @@ class WindowStateAnimator {
             }
 
             mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
-                    attrs.getTitle().toString(),
-                    width, height, format, flags, this, windowType, ownerUid);
+                    attrs.getTitle().toString(), width, height, format, flags, this,
+                    windowType, ownerUid);
             mSurfaceFormat = format;
 
             w.setHasSurface(true);
@@ -853,35 +667,8 @@ class WindowStateAnimator {
     }
 
     void computeShownFrameLocked() {
-        final boolean selfTransformation = mHasLocalTransformation;
         Transformation appTransformation = (mAppAnimator != null && mAppAnimator.hasTransformation)
                 ? mAppAnimator.transformation : null;
-        Transformation wallpaperTargetTransformation = null;
-
-        // Wallpapers are animated based on the "real" window they
-        // are currently targeting.
-        final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
-        if (mIsWallpaper && wallpaperTarget != null && mService.mAnimateWallpaperWithTarget) {
-            final WindowStateAnimator wallpaperAnimator = wallpaperTarget.mWinAnimator;
-            if (wallpaperAnimator.mHasLocalTransformation &&
-                    wallpaperAnimator.mAnimation != null &&
-                    !wallpaperAnimator.mAnimation.getDetachWallpaper()) {
-                wallpaperTargetTransformation = wallpaperAnimator.mTransformation;
-                if (DEBUG_WALLPAPER && wallpaperTargetTransformation != null) {
-                    Slog.v(TAG, "WP target attached xform: " + wallpaperTargetTransformation);
-                }
-            }
-            final AppWindowAnimator wpAppAnimator = wallpaperTarget.mAppToken == null ?
-                    null : wallpaperTarget.mAppToken.mAppAnimator;
-                if (wpAppAnimator != null && wpAppAnimator.hasTransformation
-                    && wpAppAnimator.animation != null
-                    && !wpAppAnimator.animation.getDetachWallpaper()) {
-                appTransformation = wpAppAnimator.transformation;
-                if (DEBUG_WALLPAPER && appTransformation != null) {
-                    Slog.v(TAG, "WP target app xform: " + appTransformation);
-                }
-            }
-        }
 
         final int displayId = mWin.getDisplayId();
         final ScreenRotationAnimation screenRotationAnimation =
@@ -890,8 +677,7 @@ class WindowStateAnimator {
                 screenRotationAnimation != null && screenRotationAnimation.isAnimating();
 
         mHasClipRect = false;
-        if (selfTransformation || wallpaperTargetTransformation != null
-                || appTransformation != null || screenAnimation) {
+        if (appTransformation != null || screenAnimation) {
             // cache often used attributes locally
             final Rect frame = mWin.mFrame;
             final float tmpFloats[] = mService.mTmpFloats;
@@ -917,30 +703,13 @@ class WindowStateAnimator {
                 tmpMatrix.reset();
             }
             tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
-            if (selfTransformation) {
-                tmpMatrix.postConcat(mTransformation.getMatrix());
-            }
 
-            if (wallpaperTargetTransformation != null) {
-                tmpMatrix.postConcat(wallpaperTargetTransformation.getMatrix());
-            }
             if (appTransformation != null) {
                 tmpMatrix.postConcat(appTransformation.getMatrix());
             }
 
-            int left = frame.left;
-            int top = frame.top;
-            if (mWin.isChildWindow()) {
-                WindowState parent = mWin.getParentWindow();
-                left -= parent.mFrame.left;
-                top  -= parent.mFrame.top;
-            }
+            tmpMatrix.postTranslate(mWin.mXOffset, mWin.mYOffset);
 
-            // The translation that applies the position of the window needs to be applied at the
-            // end in case that other translations include scaling. Otherwise the scaling will
-            // affect this translation. But it needs to be set before the screen rotation animation
-            // so the pivot point is at the center of the screen for all windows.
-            tmpMatrix.postTranslate(left + mWin.mXOffset, top + mWin.mYOffset);
             if (screenAnimation) {
                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
@@ -972,12 +741,6 @@ class WindowStateAnimator {
                     || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
                             && x == frame.left && y == frame.top))) {
                 //Slog.i(TAG_WM, "Applying alpha transform");
-                if (selfTransformation) {
-                    mShownAlpha *= mTransformation.getAlpha();
-                }
-                if (wallpaperTargetTransformation != null) {
-                    mShownAlpha *= wallpaperTargetTransformation.getAlpha();
-                }
                 if (appTransformation != null) {
                     mShownAlpha *= appTransformation.getAlpha();
                     if (appTransformation.hasClipRect()) {
@@ -1006,9 +769,6 @@ class WindowStateAnimator {
             if ((DEBUG_ANIM || WindowManagerService.localLOGV)
                     && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
                     TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
-                    + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
-                    + " attached=" + (wallpaperTargetTransformation == null ?
-                            "null" : wallpaperTargetTransformation.getAlpha())
                     + " app=" + (appTransformation == null ? "null" : appTransformation.getAlpha())
                     + " screen=" + (screenAnimation ?
                             screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
@@ -1028,10 +788,7 @@ class WindowStateAnimator {
                 TAG, "computeShownFrameLocked: " + this +
                 " not attached, mAlpha=" + mAlpha);
 
-        mWin.mShownPosition.set(mWin.mFrame.left, mWin.mFrame.top);
-        if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
-            mWin.mShownPosition.offset(mWin.mXOffset, mWin.mYOffset);
-        }
+        mWin.mShownPosition.set(mWin.mXOffset, mWin.mYOffset);
         mShownAlpha = mAlpha;
         mHaveMatrix = false;
         mDsDx = mWin.mGlobalScale;
@@ -1182,7 +939,7 @@ class WindowStateAnimator {
         if (mAppAnimator != null && mAppAnimator.animation != null) {
             return mAppAnimator.getStackClip();
         } else {
-            return mStackClip;
+            return STACK_CLIP_AFTER_ANIM;
         }
     }
 
@@ -1434,7 +1191,7 @@ class WindowStateAnimator {
         if (mSurfaceResized) {
             mReportSurfaceResized = true;
             mAnimator.setPendingLayoutChanges(w.getDisplayId(),
-                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
+                    FINISH_LAYOUT_REDO_WALLPAPER);
         }
     }
 
@@ -1546,7 +1303,7 @@ class WindowStateAnimator {
                         // Run another pass through performLayout to set mHasContent in the
                         // LogicalDisplay.
                         mAnimator.setPendingLayoutChanges(w.getDisplayId(),
-                                WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
+                                FINISH_LAYOUT_REDO_ANIM);
                     } else {
                         w.setOrientationChanging(false);
                     }
@@ -1720,12 +1477,18 @@ class WindowStateAnimator {
      * @return true if an animation has been loaded.
      */
     boolean applyAnimationLocked(int transit, boolean isEntrance) {
-        if (mLocalAnimating && mAnimationIsEntrance == isEntrance) {
+        if (mWin.isSelfAnimating() && mAnimationIsEntrance == isEntrance) {
             // If we are trying to apply an animation, but already running
             // an animation of the same type, then just leave that one alone.
             return true;
         }
 
+        if (isEntrance && mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+            mWin.getDisplayContent().adjustForImeIfNeeded();
+            mWin.setDisplayLayoutNeeded();
+            mService.mWindowPlacerLocked.requestTraversal();
+        }
+
         // Only apply an animation if the display isn't frozen.  If it is
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
@@ -1764,44 +1527,19 @@ class WindowStateAnimator {
                     + " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
             if (a != null) {
                 if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
-                setAnimation(a);
+                mWin.startAnimation(a);
                 mAnimationIsEntrance = isEntrance;
             }
         } else {
-            clearAnimation();
+            mWin.cancelAnimation();
         }
-        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
 
-        if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+        if (!isEntrance && mWin.mAttrs.type == TYPE_INPUT_METHOD) {
             mWin.getDisplayContent().adjustForImeIfNeeded();
-            if (isEntrance) {
-                mWin.setDisplayLayoutNeeded();
-                mService.mWindowPlacerLocked.requestTraversal();
-            }
         }
-        return mAnimation != null;
-    }
 
-    private void applyFadeoutDuringKeyguardExitAnimation() {
-        long startTime = mAnimation.getStartTime();
-        long duration = mAnimation.getDuration();
-        long elapsed = mLastAnimationTime - startTime;
-        long fadeDuration = duration - elapsed;
-        if (fadeDuration <= 0) {
-            // Never mind, this would be no visible animation, so abort the animation change.
-            return;
-        }
-        AnimationSet newAnimation = new AnimationSet(false /* shareInterpolator */);
-        newAnimation.setDuration(duration);
-        newAnimation.setStartTime(startTime);
-        newAnimation.addAnimation(mAnimation);
-        Animation fadeOut = AnimationUtils.loadAnimation(
-                mContext, com.android.internal.R.anim.app_starting_exit);
-        fadeOut.setDuration(fadeDuration);
-        fadeOut.setStartOffset(elapsed);
-        newAnimation.addAnimation(fadeOut);
-        newAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDx, mAnimDy);
-        mAnimation = newAnimation;
+        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        return isAnimationSet();
     }
 
     void writeToProto(ProtoOutputStream proto, long fieldId) {
@@ -1814,20 +1552,8 @@ class WindowStateAnimator {
     }
 
     public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
-        if (mAnimating || mLocalAnimating || mAnimationIsEntrance
-                || mAnimation != null) {
-            pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
-                    pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
-                    pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
-                    pw.print(" mAnimation="); pw.print(mAnimation);
-                    pw.print(" mStackClip="); pw.println(mStackClip);
-        }
-        if (mHasTransformation || mHasLocalTransformation) {
-            pw.print(prefix); pw.print("XForm: has=");
-                    pw.print(mHasTransformation);
-                    pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
-                    pw.print(" "); mTransformation.printShortString(pw);
-                    pw.println();
+        if (mAnimationIsEntrance) {
+            pw.print(prefix); pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
         }
         if (mSurfaceController != null) {
             mSurfaceController.dump(pw, prefix, dumpAll);
@@ -1907,44 +1633,6 @@ class WindowStateAnimator {
         }
     }
 
-    void setMoveAnimation(int left, int top) {
-        final Animation a = AnimationUtils.loadAnimation(mContext,
-                com.android.internal.R.anim.window_move_from_decor);
-        setAnimation(a);
-        mAnimDx = mWin.mLastFrame.left - left;
-        mAnimDy = mWin.mLastFrame.top - top;
-        mAnimateMove = true;
-    }
-
-    void deferTransactionUntilParentFrame(long frameNumber) {
-        if (!mWin.isChildWindow()) {
-            return;
-        }
-        mSurfaceController.deferTransactionUntil(
-                mWin.getParentWindow().mWinAnimator.mSurfaceController.getHandle(), frameNumber);
-    }
-
-    /**
-     * Sometimes we need to synchronize the first frame of animation with some external event.
-     * To achieve this, we prolong the start of the animation and keep producing the first frame of
-     * the animation.
-     */
-    private long getAnimationFrameTime(Animation animation, long currentTime) {
-        if (mAnimationStartDelayed) {
-            animation.setStartTime(currentTime);
-            return currentTime + 1;
-        }
-        return currentTime;
-    }
-
-    void startDelayingAnimationStart() {
-        mAnimationStartDelayed = true;
-    }
-
-    void endDelayingAnimationStart() {
-        mAnimationStartDelayed = false;
-    }
-
     void seamlesslyRotateWindow(int oldRotation, int newRotation) {
         final WindowState w = mWin;
         if (!w.isVisibleNow() || w.mIsWallpaper) {
@@ -2026,4 +1714,8 @@ class WindowStateAnimator {
             mSurfaceController.detachChildren();
         }
     }
+
+    int getLayer() {
+        return mLastLayer;
+    }
 }
index 6746754..e26a362 100644 (file)
@@ -59,8 +59,8 @@ class WindowSurfaceController {
     private boolean mSurfaceShown = false;
     private float mSurfaceX = 0;
     private float mSurfaceY = 0;
-    private float mSurfaceW = 0;
-    private float mSurfaceH = 0;
+    private int mSurfaceW = 0;
+    private int mSurfaceH = 0;
 
     // Initialize to the identity matrix.
     private float mLastDsdx = 1;
@@ -517,11 +517,11 @@ class WindowSurfaceController {
         return mSurfaceY;
     }
 
-    float getWidth() {
+    int getWidth() {
         return mSurfaceW;
     }
 
-    float getHeight() {
+    int getHeight() {
         return mSurfaceH;
     }
 
index 169d0a3..d8e7457 100644 (file)
@@ -462,6 +462,7 @@ class WindowSurfacePlacer {
             appAnimator.setNullAnimation();
             // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
             //       animating?
+            wtoken.setAllAppWinAnimators();
             wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
             wtoken.updateReportedVisibilityLocked();
             // setAllAppWinAnimators so the windows get onExitAnimationDone once the animation is
@@ -606,7 +607,7 @@ class WindowSurfacePlacer {
                         + ", oldWallpaper=" + oldWallpaper
                         + ", openingApps=" + openingApps
                         + ", closingApps=" + closingApps);
-        mService.mAnimateWallpaperWithTarget = false;
+
         if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
             transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
@@ -645,8 +646,6 @@ class WindowSurfacePlacer {
                 transit = TRANSIT_WALLPAPER_OPEN;
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
                         + AppTransition.appTransitionToString(transit));
-            } else {
-                mService.mAnimateWallpaperWithTarget = true;
             }
         }
         return transit;
index 4dd51eb..70906df 100644 (file)
@@ -53,12 +53,12 @@ public class DimmerTests extends WindowTestsBase {
         }
 
         @Override
-        SurfaceControl getSurfaceControl() {
+        public SurfaceControl getSurfaceControl() {
             return mControl;
         }
 
         @Override
-        SurfaceControl.Transaction getPendingTransaction() {
+        public SurfaceControl.Transaction getPendingTransaction() {
             return mTransaction;
         }
     }
@@ -93,12 +93,12 @@ public class DimmerTests extends WindowTestsBase {
         }
 
         @Override
-        SurfaceControl getSurfaceControl() {
+        public SurfaceControl getSurfaceControl() {
             return mHostControl;
         }
 
         @Override
-        SurfaceControl.Transaction getPendingTransaction() {
+        public SurfaceControl.Transaction getPendingTransaction() {
             return mHostTransaction;
         }
     }
@@ -110,8 +110,8 @@ public class DimmerTests extends WindowTestsBase {
     @Before
     public void setUp() throws Exception {
         super.setUp();
-
         mHost = new MockSurfaceBuildingContainer();
+
         mTransaction = mock(SurfaceControl.Transaction.class);
         mDimmer = new Dimmer(mHost);
     }
index 9ecf51e..28b0c55 100644 (file)
@@ -54,7 +54,7 @@ import java.util.concurrent.CountDownLatch;
 /**
  * Test class for {@link SurfaceAnimationRunner}.
  *
- * runtest frameworks-services -c com.android.server.wm.SurfaceAnimationRunnerTest
+ * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest
  */
 @SmallTest
 @Presubmit
@@ -104,7 +104,8 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase {
 
     @Test
     public void testCancel_notStarted() throws Exception {
-        mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), mMockTransaction);
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(),
+                mMockTransaction);
         mSurfaceAnimationRunner
                 .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
                 this::finishedCallback);
@@ -112,12 +113,12 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase {
         waitUntilHandlersIdle();
         assertTrue(mSurfaceAnimationRunner.mPendingAnimations.isEmpty());
         assertFinishCallbackNotCalled();
-        //verify(mMockSurface).release();
     }
 
     @Test
     public void testCancel_running() throws Exception {
-        mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), mMockTransaction);
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(),
+                mMockTransaction);
         mSurfaceAnimationRunner
                 .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
                 this::finishedCallback);
@@ -127,7 +128,6 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase {
         assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
         waitUntilHandlersIdle();
         assertFinishCallbackNotCalled();
-        //verify(mMockSurface).release();
     }
 
     private void waitUntilNextFrame() throws Exception {
index 9a52042..6f739ca 100644 (file)
@@ -33,8 +33,6 @@ import android.view.SurfaceControl.Builder;
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
 
-import com.google.android.collect.Lists;
-
 import com.android.server.wm.SurfaceAnimator.Animatable;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
@@ -50,168 +48,183 @@ import java.util.ArrayList;
 /**
  * Test class for {@link SurfaceAnimatorTest}.
  *
- * runtest frameworks-services -c com.android.server.wm.SurfaceAnimatorTest
+ * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimatorTest
  */
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class SurfaceAnimatorTest extends WindowTestsBase {
 
-    @Mock
-    AnimationAdapter mSpec;
-    @Mock
-    AnimationAdapter mSpec2;
+    @Mock AnimationAdapter mSpec;
+    @Mock AnimationAdapter mSpec2;
     @Mock Transaction mTransaction;
 
-    private SurfaceAnimator mSurfaceAnimator;
-    private SurfaceControl mParent;
-    private SurfaceControl mSurface;
-    private boolean mFinishedCallbackCalled;
-    private SurfaceControl mLeash;
     private SurfaceSession mSession = new SurfaceSession();
-
-    private final Animatable mAnimatable = new Animatable() {
-        @Override
-        public Transaction getPendingTransaction() {
-            return mTransaction;
-        }
-
-        @Override
-        public void commitPendingTransaction() {
-        }
-
-        @Override
-        public void onLeashCreated(Transaction t, SurfaceControl leash) {
-        }
-
-        @Override
-        public void onLeashDestroyed(Transaction t) {
-        }
-
-        @Override
-        public Builder makeLeash() {
-            return new SurfaceControl.Builder(mSession) {
-
-                @Override
-                public SurfaceControl build() {
-                    mLeash = super.build();
-                    return mLeash;
-                }
-            }.setParent(mParent);
-        }
-
-        @Override
-        public SurfaceControl getSurface() {
-            return mSurface;
-        }
-
-        @Override
-        public SurfaceControl getParentSurface() {
-            return mParent;
-        }
-
-        @Override
-        public int getSurfaceWidth() {
-            return 1;
-        }
-
-        @Override
-        public int getSurfaceHeight() {
-            return 1;
-        }
-    };
-
-    private final Runnable mFinishedCallback = () -> {
-        mFinishedCallbackCalled = true;
-    };
+    private MyAnimatable mAnimatable;
 
     @Before
     public void setUp() throws Exception {
         super.setUp();
         MockitoAnnotations.initMocks(this);
-        mParent = sWm.makeSurfaceBuilder(mSession)
-                .setName("test surface parent")
-                .setSize(3000, 3000)
-                .build();
-        mSurface = sWm.makeSurfaceBuilder(mSession)
-                .setName("test surface")
-                .setSize(1, 1)
-                .build();
-        mFinishedCallbackCalled = false;
-        mLeash = null;
-        mSurfaceAnimator = new SurfaceAnimator(mAnimatable, mFinishedCallback, sWm);
+        mAnimatable = new MyAnimatable();
     }
 
     @Test
     public void testRunAnimation() throws Exception {
-        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
                 OnAnimationFinishedCallback.class);
 
-        assertTrue(mSurfaceAnimator.isAnimating());
-        assertNotNull(mSurfaceAnimator.getAnimation());
-        verify(mTransaction).reparent(eq(mSurface), eq(mLeash.getHandle()));
+        assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+        assertNotNull(mAnimatable.mSurfaceAnimator.getAnimation());
+        verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash.getHandle()));
         verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
 
         callbackCaptor.getValue().onAnimationFinished(mSpec);
-        assertFalse(mSurfaceAnimator.isAnimating());
-        assertNull(mSurfaceAnimator.getAnimation());
-        assertTrue(mFinishedCallbackCalled);
-
+        assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+        assertNull(mAnimatable.mSurfaceAnimator.getAnimation());
+        assertTrue(mAnimatable.mFinishedCallbackCalled);
+        assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
         // TODO: Verify reparenting once we use mPendingTransaction to reparent it back
     }
 
     @Test
     public void testOverrideAnimation() throws Exception {
-        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
-        mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
+        mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        final SurfaceControl firstLeash = mAnimatable.mLeash;
+        mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
 
-        assertFalse(mFinishedCallbackCalled);
+        assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
+        assertFalse(mAnimatable.mFinishedCallbackCalled);
 
         final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
                 OnAnimationFinishedCallback.class);
-        assertTrue(mSurfaceAnimator.isAnimating());
-        assertNotNull(mSurfaceAnimator.getAnimation());
+        assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+        assertNotNull(mAnimatable.mSurfaceAnimator.getAnimation());
         verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
 
         // First animation was finished, but this shouldn't cancel the second animation
         callbackCaptor.getValue().onAnimationFinished(mSpec);
-        assertTrue(mSurfaceAnimator.isAnimating());
+        assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
 
         // Second animation was finished
         verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
         callbackCaptor.getValue().onAnimationFinished(mSpec2);
-        assertFalse(mSurfaceAnimator.isAnimating());
-        assertTrue(mFinishedCallbackCalled);
+        assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+        assertTrue(mAnimatable.mFinishedCallbackCalled);
     }
 
     @Test
     public void testCancelAnimation() throws Exception {
-        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
-        assertTrue(mSurfaceAnimator.isAnimating());
-        mSurfaceAnimator.cancelAnimation();
-        assertFalse(mSurfaceAnimator.isAnimating());
+        mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+        mAnimatable.mSurfaceAnimator.cancelAnimation();
+        assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
         verify(mSpec).onAnimationCancelled(any());
-        assertTrue(mFinishedCallbackCalled);
+        assertTrue(mAnimatable.mFinishedCallbackCalled);
+        assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
     }
 
     @Test
     public void testDelayingAnimationStart() throws Exception {
-        mSurfaceAnimator.startDelayingAnimationStart();
-        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
+        mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         verifyZeroInteractions(mSpec);
-        assertTrue(mSurfaceAnimator.isAnimating());
-        mSurfaceAnimator.endDelayingAnimationStart();
+        assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
+        mAnimatable.mSurfaceAnimator.endDelayingAnimationStart();
         verify(mSpec).startAnimation(any(), any(), any());
     }
 
     @Test
     public void testDelayingAnimationStartAndCancelled() throws Exception {
-        mSurfaceAnimator.startDelayingAnimationStart();
-        mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
-        mSurfaceAnimator.cancelAnimation();
+        mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
+        mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+        mAnimatable.mSurfaceAnimator.cancelAnimation();
         verifyZeroInteractions(mSpec);
-        assertFalse(mSurfaceAnimator.isAnimating());
-        assertTrue(mFinishedCallbackCalled);
+        assertFalse(mAnimatable.mSurfaceAnimator.isAnimating());
+        assertTrue(mAnimatable.mFinishedCallbackCalled);
+        assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+    }
+
+    private class MyAnimatable implements Animatable {
+
+        final SurfaceControl mParent;
+        final SurfaceControl mSurface;
+        final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
+        final SurfaceAnimator mSurfaceAnimator;
+        SurfaceControl mLeash;
+        boolean mFinishedCallbackCalled;
+
+        MyAnimatable() {
+            mParent = sWm.makeSurfaceBuilder(mSession)
+                    .setName("test surface parent")
+                    .setSize(3000, 3000)
+                    .build();
+            mSurface = sWm.makeSurfaceBuilder(mSession)
+                    .setName("test surface")
+                    .setSize(1, 1)
+                    .build();
+            mFinishedCallbackCalled = false;
+            mLeash = null;
+            mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+        }
+
+        @Override
+        public Transaction getPendingTransaction() {
+            return mTransaction;
+        }
+
+        @Override
+        public void commitPendingTransaction() {
+        }
+
+        @Override
+        public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+        }
+
+        @Override
+        public void onAnimationLeashDestroyed(Transaction t) {
+        }
+
+        @Override
+        public void destroyAfterPendingTransaction(SurfaceControl surface) {
+            mPendingDestroySurfaces.add(surface);
+        }
+
+        @Override
+        public Builder makeAnimationLeash() {
+            return new SurfaceControl.Builder(mSession) {
+
+                @Override
+                public SurfaceControl build() {
+                    mLeash = super.build();
+                    return mLeash;
+                }
+            }.setParent(mParent);
+        }
+
+        @Override
+        public SurfaceControl getSurfaceControl() {
+            return mSurface;
+        }
+
+        @Override
+        public SurfaceControl getParentSurfaceControl() {
+            return mParent;
+        }
+
+        @Override
+        public int getSurfaceWidth() {
+            return 1;
+        }
+
+        @Override
+        public int getSurfaceHeight() {
+            return 1;
+        }
+
+        private final Runnable mFinishedCallback = () -> {
+            mFinishedCallbackCalled = true;
+        };
     }
 }
index 5cb9467..307deb4 100644 (file)
@@ -29,8 +29,6 @@ import java.util.Comparator;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
@@ -333,12 +331,19 @@ public class WindowContainerTests extends WindowTestsBase {
         final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
         final TestWindowContainer child21 = child2.addChildWindow();
 
-        assertTrue(root.isAnimating());
+        assertFalse(root.isAnimating());
         assertTrue(child1.isAnimating());
-        assertFalse(child11.isAnimating());
+        assertTrue(child11.isAnimating());
         assertTrue(child12.isAnimating());
         assertFalse(child2.isAnimating());
         assertFalse(child21.isAnimating());
+
+        assertTrue(root.isSelfOrChildAnimating());
+        assertTrue(child1.isSelfOrChildAnimating());
+        assertFalse(child11.isSelfOrChildAnimating());
+        assertTrue(child12.isSelfOrChildAnimating());
+        assertFalse(child2.isSelfOrChildAnimating());
+        assertFalse(child21.isSelfOrChildAnimating());
     }
 
     @Test
@@ -630,8 +635,8 @@ public class WindowContainerTests extends WindowTestsBase {
         }
 
         @Override
-        boolean isAnimating() {
-            return mIsAnimating || super.isAnimating();
+        boolean isSelfAnimating() {
+            return mIsAnimating;
         }
 
         @Override
index b2334e8..5f58744 100644 (file)
@@ -189,7 +189,6 @@ public class WindowTestUtils {
     public static class TestTask extends Task {
         boolean mShouldDeferRemoval = false;
         boolean mOnDisplayChangedCalled = false;
-        private boolean mUseLocalIsAnimating = false;
         private boolean mIsAnimating = false;
 
         TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service,
@@ -214,12 +213,11 @@ public class WindowTestUtils {
         }
 
         @Override
-        boolean isAnimating() {
-            return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
+        boolean isSelfAnimating() {
+            return mIsAnimating;
         }
 
         void setLocalIsAnimating(boolean isAnimating) {
-            mUseLocalIsAnimating = true;
             mIsAnimating = isAnimating;
         }
     }