Merge "Fix enter/exit horizontal ActivityEmbedding split with Shell transition" into tm-qpr-dev am: 4013b5600d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20505728

Change-Id: I47186d15111d7ea14218e6ba197db9e9e9b201dd
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index 215308d..00b9fced 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -30,6 +30,8 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.wm.shell.transition.Transitions;
+
 /**
  * Wrapper to handle the ActivityEmbedding animation update in one
  * {@link SurfaceControl.Transaction}.
@@ -50,6 +52,16 @@
     /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
     @NonNull
     private final Rect mWholeAnimationBounds = new Rect();
+    /**
+     * Area in absolute coordinate that should represent all the content to show for this window.
+     * This should be the end bounds for opening window, and start bounds for closing window in case
+     * the window is resizing during the open/close transition.
+     */
+    @NonNull
+    private final Rect mContentBounds = new Rect();
+    /** Offset relative to the window parent surface for {@link #mContentBounds}. */
+    @NonNull
+    private final Point mContentRelOffset = new Point();
 
     @NonNull
     final Transformation mTransformation = new Transformation();
@@ -80,6 +92,21 @@
         mChange = change;
         mLeash = leash;
         mWholeAnimationBounds.set(wholeAnimationBounds);
+        if (Transitions.isClosingType(change.getMode())) {
+            // When it is closing, we want to show the content at the start position in case the
+            // window is resizing as well. For example, when the activities is changing from split
+            // to stack, the bottom TaskFragment will be resized to fullscreen when hiding.
+            final Rect startBounds = change.getStartAbsBounds();
+            final Rect endBounds = change.getEndAbsBounds();
+            mContentBounds.set(startBounds);
+            mContentRelOffset.set(change.getEndRelOffset());
+            mContentRelOffset.offset(
+                    startBounds.left - endBounds.left,
+                    startBounds.top - endBounds.top);
+        } else {
+            mContentBounds.set(change.getEndAbsBounds());
+            mContentRelOffset.set(change.getEndRelOffset());
+        }
     }
 
     /**
@@ -110,8 +137,7 @@
     /** To be overridden by subclasses to adjust the animation surface change. */
     void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
         // Update the surface position and alpha.
-        final Point offset = mChange.getEndRelOffset();
-        mTransformation.getMatrix().postTranslate(offset.x, offset.y);
+        mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
         t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
         t.setAlpha(mLeash, mTransformation.getAlpha());
 
@@ -119,8 +145,8 @@
         // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
         final int positionX = Math.round(mMatrix[MTRANS_X]);
         final int positionY = Math.round(mMatrix[MTRANS_Y]);
-        final Rect cropRect = new Rect(mChange.getEndAbsBounds());
-        cropRect.offset(positionX - offset.x, positionY - offset.y);
+        final Rect cropRect = new Rect(mContentBounds);
+        cropRect.offset(positionX - mContentRelOffset.x, positionY - mContentRelOffset.y);
 
         // Store the current offset of the surface top left from (0,0) in absolute coordinate.
         final int offsetX = cropRect.left;
@@ -133,7 +159,7 @@
         } else if (mAnimation.hasExtension()) {
             // Allow the surface to be shown in its original bounds in case we want to use edge
             // extensions.
-            cropRect.union(mChange.getEndAbsBounds());
+            cropRect.union(mContentBounds);
         }
 
         // cropRect is in absolute coordinate, so we need to translate it to surface top left.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 921861a..c0a6456 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -304,6 +304,7 @@
         // This is because the TaskFragment surface/change won't contain the Activity's before its
         // reparent.
         Animation changeAnimation = null;
+        Rect parentBounds = new Rect();
         for (TransitionInfo.Change change : info.getChanges()) {
             if (change.getMode() != TRANSIT_CHANGE
                     || change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
@@ -326,10 +327,15 @@
                 }
             }
 
+            // The TaskFragment may be enter/exit split, so we take the union of both as the parent
+            // size.
+            parentBounds.union(boundsAnimationChange.getStartAbsBounds());
+            parentBounds.union(boundsAnimationChange.getEndAbsBounds());
+
             // There are two animations in the array. The first one is for the start leash
             // (snapshot), and the second one is for the end leash (TaskFragment).
             final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change,
-                    boundsAnimationChange.getEndAbsBounds());
+                    parentBounds);
             // Keep track as we might need to add background color for the animation.
             // Although there may be multiple change animation, record one of them is sufficient
             // because the background color will be added to the root leash for the whole animation.
@@ -352,6 +358,11 @@
                     animations[1], boundsAnimationChange));
         }
 
+        if (parentBounds.isEmpty()) {
+            throw new IllegalStateException(
+                    "There should be at least one changing window to play the change animation");
+        }
+
         // If there is no corresponding open/close window with the change, we should show background
         // color to cover the empty part of the screen.
         boolean shouldShouldBackgroundColor = true;
@@ -368,10 +379,10 @@
                 // No-op if it will be covered by the changing parent window.
                 animation = ActivityEmbeddingAnimationSpec.createNoopAnimation(change);
             } else if (Transitions.isClosingType(change.getMode())) {
-                animation = mAnimationSpec.createChangeBoundsCloseAnimation(change);
+                animation = mAnimationSpec.createChangeBoundsCloseAnimation(change, parentBounds);
                 shouldShouldBackgroundColor = false;
             } else {
-                animation = mAnimationSpec.createChangeBoundsOpenAnimation(change);
+                animation = mAnimationSpec.createChangeBoundsOpenAnimation(change, parentBounds);
                 shouldShouldBackgroundColor = false;
             }
             adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 2bb7369..65a7d09 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -21,7 +21,6 @@
 import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
 
 import android.content.Context;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
@@ -80,15 +79,25 @@
 
     /** Animation for window that is opening in a change transition. */
     @NonNull
-    Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change) {
+    Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change,
+            @NonNull Rect parentBounds) {
+        // Use end bounds for opening.
         final Rect bounds = change.getEndAbsBounds();
-        final Point offset = change.getEndRelOffset();
-        // The window will be animated in from left or right depends on its position.
-        final int startLeft = offset.x == 0 ? -bounds.width() : bounds.width();
+        final int startLeft;
+        final int startTop;
+        if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
+            // The window will be animated in from left or right depends on its position.
+            startTop = 0;
+            startLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width();
+        } else {
+            // The window will be animated in from top or bottom depends on its position.
+            startTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height();
+            startLeft = 0;
+        }
 
         // The position should be 0-based as we will post translate in
         // ActivityEmbeddingAnimationAdapter#onAnimationUpdate
-        final Animation animation = new TranslateAnimation(startLeft, 0, 0, 0);
+        final Animation animation = new TranslateAnimation(startLeft, 0, startTop, 0);
         animation.setInterpolator(mFastOutExtraSlowInInterpolator);
         animation.setDuration(CHANGE_ANIMATION_DURATION);
         animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height());
@@ -98,15 +107,25 @@
 
     /** Animation for window that is closing in a change transition. */
     @NonNull
-    Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo.Change change) {
-        final Rect bounds = change.getEndAbsBounds();
-        final Point offset = change.getEndRelOffset();
-        // The window will be animated out to left or right depends on its position.
-        final int endLeft = offset.x == 0 ? -bounds.width() : bounds.width();
+    Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo.Change change,
+            @NonNull Rect parentBounds) {
+        // Use start bounds for closing.
+        final Rect bounds = change.getStartAbsBounds();
+        final int endTop;
+        final int endLeft;
+        if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
+            // The window will be animated out to left or right depends on its position.
+            endTop = 0;
+            endLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width();
+        } else {
+            // The window will be animated out to top or bottom depends on its position.
+            endTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height();
+            endLeft = 0;
+        }
 
         // The position should be 0-based as we will post translate in
         // ActivityEmbeddingAnimationAdapter#onAnimationUpdate
-        final Animation animation = new TranslateAnimation(0, endLeft, 0, 0);
+        final Animation animation = new TranslateAnimation(0, endLeft, 0, endTop);
         animation.setInterpolator(mFastOutExtraSlowInInterpolator);
         animation.setDuration(CHANGE_ANIMATION_DURATION);
         animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height());