Settle auto PiP transaction in WindowContainerTransaction

At the end of autoEnterPip transition, followings happen in sequence
- Transition finishes in Launcher side, which operates on the
  animation leash
- RecentsAnimationController.TaskAnimationAdapter#onCleanup has the final
  chance to set the Task leash
- PipTaskOrganizer gets onTaskAppeared callback and commits Task into
  pinned mode

What's been changed here
- Transition in Launcher no longer in charge of settle the final transaction
- RecentsAnimationController.TaskAnimationAdapter#onCleanup sets the
  Task leash to be in sync with the final state in Launcher side
- PipTaskOrganizer commits the final leash transaction together with
  WindowContainerTransaction that enters PiP

Known issue: transition from landscape is not polished

Video: http://rcll/aaaaaabFQoRHlzixHdtY/hT5SXvaCy28P4UtfuoKiDw
Bug: 181342797
Test: see video
Change-Id: Ieabd6991ea5174099714ec22970198bebde1e336
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index ddb49786..10721ad 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -43,8 +43,11 @@
      * accordingly. This should be called before `finish`
      * @param taskId for which the leash should be updated
      * @param destinationBounds bounds of the final PiP window
+     * @param windowCrop bounds to crop as part of final transform.
+     * @param float9 An array of 9 floats to be used as matrix transform.
      */
-     void setFinishTaskBounds(int taskId, in Rect destinationBounds);
+     void setFinishTaskBounds(int taskId, in Rect destinationBounds, in Rect windowCrop,
+             in float[] float9);
 
     /**
      * Notifies to the system that the animation into Recents should end, and all leashes associated
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 9ec7c0d..36dc4e4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -41,6 +41,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.PictureInPictureParams;
@@ -423,12 +424,16 @@
 
         if (mInSwipePipToHomeTransition) {
             final Rect destinationBounds = mPipBoundsState.getBounds();
+            final SurfaceControl.Transaction tx =
+                    mSurfaceControlTransactionFactory.getTransaction();
+            mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds);
+            mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds);
             // animation is finished in the Launcher and here we directly apply the final touch.
             applyEnterPipSyncTransaction(destinationBounds, () -> {
                 // ensure menu's settled in its final bounds first
                 finishResizeForMenu(destinationBounds);
                 sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
-            });
+            }, tx);
             mInSwipePipToHomeTransition = false;
             return;
         }
@@ -490,16 +495,20 @@
             // mState is set right after the animation is kicked off to block any resize
             // requests such as offsetPip that may have been called prior to the transition.
             mState = State.ENTERING_PIP;
-        });
+        }, null /* boundsChangeTransaction */);
     }
 
-    private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable) {
+    private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable,
+            @Nullable SurfaceControl.Transaction boundsChangeTransaction) {
         // PiP menu is attached late in the process here to avoid any artifacts on the leash
         // caused by addShellRoot when in gesture navigation mode.
         mPipMenuController.attach(mLeash);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
         wct.setBounds(mToken, destinationBounds);
+        if (boundsChangeTransaction != null) {
+            wct.setBoundsChangeTransaction(mToken, boundsChangeTransaction);
+        }
         wct.scheduleFinishEnterPip(mToken, destinationBounds);
         mSyncTransactionQueue.queue(wct);
         if (runnable != null) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 72e4061..f50c3c92 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -20,7 +20,6 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.view.Choreographer;
-import android.view.Surface;
 import android.view.SurfaceControl;
 
 /**
@@ -91,24 +90,6 @@
                 .setPosition(leash, positionX, positionY);
     }
 
-    public void reset(SurfaceControl.Transaction tx, SurfaceControl leash, Rect destinationBounds,
-            @Surface.Rotation int rotation) {
-        resetScale(tx, leash, destinationBounds);
-        if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
-            final int degree = (rotation == Surface.ROTATION_90) ? -90 : 90;
-            mTmpTransform.setRotate(degree, 0, 0);
-            tx.setMatrix(leash, mTmpTransform, mTmpFloat9);
-        }
-        resetCornerRadius(tx, leash);
-        crop(tx, leash, destinationBounds);
-    }
-
-    public void resetScale(SurfaceControl.Transaction tx, SurfaceControl leash,
-            Rect destinationBounds) {
-        tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, mTmpFloat9)
-                .setPosition(leash, destinationBounds.left, destinationBounds.top);
-    }
-
     public void resetCornerRadius(SurfaceControl.Transaction tx, SurfaceControl leash) {
         tx.setCornerRadius(leash, 0);
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index c2d52a7..bf0d29a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -76,10 +76,14 @@
      * accordingly. This should be called before `finish`
      * @param taskId Task id of the Activity in PiP mode.
      * @param destinationBounds Bounds of the PiP window on home.
+     * @param windowCrop bounds to crop as part of final transform.
+     * @param float9 An array of 9 floats to be used as matrix transform.
      */
-    public void setFinishTaskBounds(int taskId, Rect destinationBounds) {
+    public void setFinishTaskBounds(int taskId, Rect destinationBounds, Rect windowCrop,
+            float[] float9) {
         try {
-            mAnimationController.setFinishTaskBounds(taskId, destinationBounds);
+            mAnimationController.setFinishTaskBounds(taskId, destinationBounds, windowCrop,
+                    float9);
         } catch (RemoteException e) {
             Log.d(TAG, "Failed to set finish task bounds", e);
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 7ba9069..06155bc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -137,8 +137,11 @@
             mWrapped.hideCurrentInputMethod();
         }
 
-        @Override public void setFinishTaskBounds(int taskId, Rect destinationBounds) {
-            if (mWrapped != null) mWrapped.setFinishTaskBounds(taskId, destinationBounds);
+        @Override public void setFinishTaskBounds(int taskId, Rect destinationBounds,
+                Rect windowCrop, float[] float9) {
+            if (mWrapped != null) {
+                mWrapped.setFinishTaskBounds(taskId, destinationBounds, windowCrop, float9);
+            }
         }
 
         @Override public void finish(boolean toHome, boolean sendUserLeaveHint) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 914e456..64ff108 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -20,6 +20,10 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.graphics.Matrix.MSCALE_X;
+import static android.graphics.Matrix.MSCALE_Y;
+import static android.graphics.Matrix.MSKEW_X;
+import static android.graphics.Matrix.MSKEW_Y;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
@@ -229,7 +233,8 @@
         }
 
         @Override
-        public void setFinishTaskBounds(int taskId, Rect destinationBounds) {
+        public void setFinishTaskBounds(int taskId, Rect destinationBounds, Rect windowCrop,
+                float[] float9) {
             ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
                     "setFinishTaskBounds(%d): bounds=%s", taskId, destinationBounds);
             final long token = Binder.clearCallingIdentity();
@@ -239,6 +244,8 @@
                         final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
                         if (taskAdapter.mTask.mTaskId == taskId) {
                             taskAdapter.mFinishBounds.set(destinationBounds);
+                            taskAdapter.mFinishWindowCrop.set(windowCrop);
+                            taskAdapter.mFinishTransform = float9;
                             break;
                         }
                     }
@@ -1084,6 +1091,9 @@
         private final Rect mLocalBounds = new Rect();
         // The bounds of the target when animation is finished
         private final Rect mFinishBounds = new Rect();
+        // Bounds and transform for the final transaction.
+        private final Rect mFinishWindowCrop = new Rect();
+        private float[] mFinishTransform;
 
         TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
             mTask = task;
@@ -1120,13 +1130,31 @@
 
         void onCleanup() {
             if (!mFinishBounds.isEmpty()) {
-                // Apply any pending bounds changes
-                final SurfaceControl taskSurface = mTask.getSurfaceControl();
-                mTask.getPendingTransaction()
-                        .setPosition(taskSurface, mFinishBounds.left, mFinishBounds.top)
-                        .setWindowCrop(taskSurface, mFinishBounds.width(), mFinishBounds.height())
+                final SurfaceControl taskSurface = mTask.mSurfaceControl;
+                final Transaction pendingTransaction = mTask.getPendingTransaction();
+                if (mFinishTransform != null) {
+                    pendingTransaction
+                            .setMatrix(taskSurface,
+                                    mFinishTransform[MSCALE_X], mFinishTransform[MSKEW_Y],
+                                    mFinishTransform[MSKEW_X], mFinishTransform[MSCALE_Y]);
+                }
+                float left = mFinishBounds.left;
+                float top = mFinishBounds.top;
+                if (!mFinishWindowCrop.isEmpty()) {
+                    pendingTransaction.setWindowCrop(taskSurface, mFinishWindowCrop);
+                    if (mFinishTransform != null) {
+                        // adjust the position for insets.
+                        left -= mFinishWindowCrop.left * mFinishTransform[MSCALE_X];
+                        top -= mFinishWindowCrop.top * mFinishTransform[MSCALE_Y];
+                    }
+                }
+                pendingTransaction
+                        .setPosition(taskSurface, left, top)
                         .apply();
                 mTask.mLastRecentsAnimationBounds.set(mFinishBounds);
+                // reset the variables
+                mFinishTransform = null;
+                mFinishWindowCrop.setEmpty();
                 mFinishBounds.setEmpty();
             } else if (!mTask.isAttached()) {
                 // Apply the task's pending transaction in case it is detached and its transaction