Lock free app animations (4/n): Implement thubmnail

Bug: 64674361
Test: go/wm-smoke
Change-Id: I8f25dae04b69613c93ccb5416c2cda2df6373103
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index dcf2a87..de4b426 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -55,6 +55,7 @@
 import android.annotation.NonNull;
 import android.app.Activity;
 import android.content.res.Configuration;
+import android.graphics.GraphicBuffer;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -208,6 +209,8 @@
     /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
     private boolean mLastSurfaceShowing;
 
+    private AppWindowThumbnail mThumbnail;
+
     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
@@ -1618,6 +1621,8 @@
         setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
                 "AppWindowToken");
 
+        clearThumbnail();
+
         if (mService.mInputMethodTarget != null && mService.mInputMethodTarget.mAppToken == this) {
             getDisplayContent().computeImeTarget(true /* updateImeTarget */);
         }
@@ -1657,6 +1662,12 @@
         return super.isSelfAnimating();
     }
 
+    @Override
+    void cancelAnimation() {
+        super.cancelAnimation();
+        clearThumbnail();
+    }
+
     boolean isWaitingForTransitionStart() {
         return mService.mAppTransition.isTransitionSet()
                 && (mService.mOpeningApps.contains(this) || mService.mClosingApps.contains(this));
@@ -1670,8 +1681,44 @@
         return mTransitFlags;
     }
 
-    void clearThumbnail() {
-        // TODO
+    void attachThumbnailAnimation() {
+        if (!isReallyAnimating()) {
+            return;
+        }
+        final int taskId = getTask().mTaskId;
+        final GraphicBuffer thumbnailHeader =
+                mService.mAppTransition.getAppTransitionThumbnailHeader(taskId);
+        if (thumbnailHeader == null) {
+            if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId);
+            return;
+        }
+        clearThumbnail();
+        mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnailHeader);
+        mThumbnail.startAnimation(getPendingTransaction(), loadThumbnailAnimation(thumbnailHeader));
+    }
+
+    private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) {
+        final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+
+        // If this is a multi-window scenario, we use the windows frame as
+        // destination of the thumbnail header animation. If this is a full screen
+        // window scenario, we use the whole display as the target.
+        WindowState win = findMainWindow();
+        Rect appRect = win != null ? win.getContentFrameLw() :
+                new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
+        Rect insets = win != null ? win.mContentInsets : null;
+        final Configuration displayConfig = mDisplayContent.getConfiguration();
+        return mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(
+                appRect, insets, thumbnailHeader, getTask().mTaskId, displayConfig.uiMode,
+                displayConfig.orientation);
+    }
+
+    private void clearThumbnail() {
+        if (mThumbnail == null) {
+            return;
+        }
+        mThumbnail.destroy();
+        mThumbnail = null;
     }
 
     @Override
@@ -1753,6 +1800,9 @@
         } else if (!show && mLastSurfaceShowing) {
             mPendingTransaction.hide(mSurfaceControl);
         }
+        if (mThumbnail != null) {
+            mThumbnail.setShowing(mPendingTransaction, show);
+        }
         mLastSurfaceShowing = show;
         super.prepareSurfaces();
     }