Fix issue with aspect ratio not applying correctly when PIP is expanded

- The current code always used the default min edge size to calculate the
  PIP bounds when the aspect ratio changes, so if a PIP app sets the aspect
  ratio in response to the an action, the bounds would be resized down
  incorrectly.
- This CL fixes the issue with current aspect ratio not being initialized
  correctly, and also ensures that SystemUI always updates the min edge
  size when expanding the PIP.

Bug: 38324839
Test: android.server.cts.ActivityManagerPinnedStackTests
Test: go/wm-smoke

Change-Id: Ida0f68b2f8f93f9bf1915dda8762a156704d4709
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index dbeb747..d2dcb56 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -30,6 +30,14 @@
     oneway void setIsMinimized(boolean isMinimized);
 
     /**
+     * Notifies the controller of the current min edge size, this is needed to allow the system to
+     * properly calculate the aspect ratio of the expanded PIP.  The given {@param minEdgeSize} is
+     * always bounded to be larger than the default minEdgeSize, so the caller can call this method
+     * with 0 to reset to the default size.
+     */
+    oneway void setMinEdgeSize(int minEdgeSize);
+
+    /**
      * @return what WM considers to be the current device rotation.
      */
     int getDisplayRotation();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index c35fdd5..854696e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -716,9 +716,15 @@
      * Updates the current movement bounds based on whether the menu is currently visible.
      */
     private void updateMovementBounds(int menuState) {
-        mMovementBounds = menuState == MENU_STATE_FULL
+        boolean isMenuExpanded = menuState == MENU_STATE_FULL;
+        mMovementBounds = isMenuExpanded
                 ? mExpandedMovementBounds
                 : mNormalMovementBounds;
+        try {
+            mPinnedStackController.setMinEdgeSize(isMenuExpanded ? mExpandedShortestEdgeSize : 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not set minimized state", e);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e180aef..e828d38 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2989,8 +2989,8 @@
         // Calculate the default bounds (don't use existing stack bounds as we may have just created
         // the stack, and schedule the start of the animation into PiP (the bounds animator that
         // is triggered by this is posted on another thread)
-        final Rect destBounds = stack.getPictureInPictureBounds(aspectRatio,
-                false /* useExistingStackBounds */);
+        final Rect destBounds = stack.getDefaultPictureInPictureBounds(aspectRatio);
+
         stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */,
                 true /* fromFullscreen */);
 
diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java
index 702bf92..2010c24 100644
--- a/services/core/java/com/android/server/am/PinnedActivityStack.java
+++ b/services/core/java/com/android/server/am/PinnedActivityStack.java
@@ -44,9 +44,9 @@
         return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds);
     }
 
-    Rect getPictureInPictureBounds(float aspectRatio, boolean useExistingStackBounds) {
+    Rect getDefaultPictureInPictureBounds(float aspectRatio) {
         return getWindowContainerController().getPictureInPictureBounds(aspectRatio,
-                useExistingStackBounds);
+                null /* currentStackBounds */);
     }
 
     void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index fc4ec28..9a9e29a 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -92,17 +92,16 @@
     private final Rect mStableInsets = new Rect();
 
     // The size and position information that describes where the pinned stack will go by default.
+    private int mDefaultMinSize;
     private int mDefaultStackGravity;
     private float mDefaultAspectRatio;
     private Point mScreenEdgeInsets;
+    private int mCurrentMinSize;
 
     // The aspect ratio bounds of the PIP.
     private float mMinAspectRatio;
     private float mMaxAspectRatio;
 
-    // The minimum edge size of the normal PiP bounds.
-    private int mMinSize;
-
     // Temp vars for calculation
     private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
     private final Rect mTmpInsets = new Rect();
@@ -124,6 +123,13 @@
         }
 
         @Override
+        public void setMinEdgeSize(int minEdgeSize) {
+            mHandler.post(() -> {
+                mCurrentMinSize = Math.max(mDefaultMinSize, minEdgeSize);
+            });
+        }
+
+        @Override
         public int getDisplayRotation() {
             synchronized (mService.mWindowMap) {
                 return mDisplayInfo.rotation;
@@ -160,10 +166,12 @@
      */
     private void reloadResources() {
         final Resources res = mService.mContext.getResources();
-        mMinSize = res.getDimensionPixelSize(
+        mDefaultMinSize = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
+        mCurrentMinSize = mDefaultMinSize;
         mDefaultAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
+        mAspectRatio = mDefaultAspectRatio;
         final String screenEdgeInsetsDpString = res.getString(
                 com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
         final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
@@ -212,11 +220,15 @@
      * Returns the current bounds (or the default bounds if there are no current bounds) with the
      * specified aspect ratio.
      */
-    Rect transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio) {
+    Rect transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
+            boolean useCurrentMinEdgeSize) {
         // Save the snap fraction, calculate the aspect ratio based on screen size
         final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
                 getMovementBounds(stackBounds));
-        final Size size = getSize(aspectRatio);
+
+        final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
+        final Size size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
+                mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
         final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
         final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
         stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
@@ -228,16 +240,6 @@
     }
 
     /**
-     * @return the size of the PIP based on the given {@param aspectRatio}.
-     */
-    Size getSize(float aspectRatio) {
-        synchronized (mService.mWindowMap) {
-            return mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mMinSize,
-                    mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
-        }
-    }
-
-    /**
      * @return the default bounds to show the PIP when there is no active PIP.
      */
     Rect getDefaultBounds() {
@@ -246,7 +248,8 @@
             getInsetBounds(insetBounds);
 
             final Rect defaultBounds = new Rect();
-            final Size size = getSize(mDefaultAspectRatio);
+            final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
+                    mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
             Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
                     0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
             return defaultBounds;
@@ -401,7 +404,8 @@
                     getInsetBounds(insetBounds);
                     final Rect normalBounds = getDefaultBounds();
                     if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
-                        transformBoundsToAspectRatio(normalBounds, mAspectRatio);
+                        transformBoundsToAspectRatio(normalBounds, mAspectRatio,
+                                false /* useCurrentMinEdgeSize */);
                     }
                     final Rect animatingBounds = mTmpAnimatingBoundsRect;
                     final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID);
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index 0c628ac..989e8f2 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 
 import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
@@ -36,7 +35,8 @@
  */
 public class PinnedStackWindowController extends StackWindowController {
 
-    private Rect mTmpBoundsRect = new Rect();
+    private Rect mTmpFromBounds = new Rect();
+    private Rect mTmpToBounds = new Rect();
 
     public PinnedStackWindowController(int stackId, PinnedStackWindowListener listener,
             int displayId, boolean onTop, Rect outBounds) {
@@ -44,16 +44,16 @@
     }
 
     /**
-     * @param useExistingStackBounds Apply {@param aspectRatio} to the existing target stack bounds
-     *                               if possible
+     * @return the {@param currentStackBounds} transformed to the give {@param aspectRatio}.  If
+     *         {@param currentStackBounds} is null, then the {@param aspectRatio} is applied to the
+     *         default bounds.
      */
-    public Rect getPictureInPictureBounds(float aspectRatio, boolean useExistingStackBounds) {
+    public Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
         synchronized (mWindowMap) {
             if (!mService.mSupportsPictureInPicture || mContainer == null) {
                 return null;
             }
 
-            final Rect stackBounds;
             final DisplayContent displayContent = mContainer.getDisplayContent();
             if (displayContent == null) {
                 return null;
@@ -61,18 +61,14 @@
 
             final PinnedStackController pinnedStackController =
                     displayContent.getPinnedStackController();
-            if (useExistingStackBounds) {
-                // If the stack exists, then use its final bounds to calculate the new aspect ratio
-                // bounds
-                stackBounds = new Rect();
-                mContainer.getAnimationOrCurrentBounds(stackBounds);
-            } else {
-                // Otherwise, just calculate the aspect ratio bounds from the default bounds
+            if (stackBounds == null) {
+                // Calculate the aspect ratio bounds from the default bounds
                 stackBounds = pinnedStackController.getDefaultBounds();
             }
 
             if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
-                return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio);
+                return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
+                        true /* useCurrentMinEdgeSize */);
             } else {
                 return stackBounds;
             }
@@ -104,10 +100,10 @@
                 }
                 schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
 
-                mService.getStackBounds(FULLSCREEN_WORKSPACE_STACK_ID, mTmpBoundsRect);
-                if (!mTmpBoundsRect.isEmpty()) {
+                mService.getStackBounds(FULLSCREEN_WORKSPACE_STACK_ID, mTmpToBounds);
+                if (!mTmpToBounds.isEmpty()) {
                     // If there is a fullscreen bounds, use that
-                    toBounds = new Rect(mTmpBoundsRect);
+                    toBounds = new Rect(mTmpToBounds);
                 } else {
                     // Otherwise, use the display bounds
                     toBounds = new Rect();
@@ -142,16 +138,15 @@
                 return;
             }
 
-            final Rect toBounds = getPictureInPictureBounds(aspectRatio,
-                    true /* useExistingStackBounds */);
-            final Rect targetBounds = new Rect();
-            mContainer.getAnimationOrCurrentBounds(targetBounds);
             final PinnedStackController pinnedStackController =
                     mContainer.getDisplayContent().getPinnedStackController();
 
             if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) {
-                if (!toBounds.equals(targetBounds)) {
-                    animateResizePinnedStack(toBounds, null /* sourceHintBounds */,
+                mContainer.getAnimationOrCurrentBounds(mTmpFromBounds);
+                mTmpToBounds.set(mTmpFromBounds);
+                getPictureInPictureBounds(aspectRatio, mTmpToBounds);
+                if (!mTmpToBounds.equals(mTmpFromBounds)) {
+                    animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
                             -1 /* duration */, false /* fromFullscreen */);
                 }
                 pinnedStackController.setAspectRatio(
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 9cfa542..bac1216 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -235,8 +235,7 @@
                     if (mStackId == ActivityManager.StackId.PINNED_STACK_ID) {
                         mStack = new PinnedActivityStack(this, recents, mOnTop) {
                             @Override
-                            Rect getPictureInPictureBounds(float aspectRatio,
-                                    boolean useExistingStackBounds) {
+                            Rect getDefaultPictureInPictureBounds(float aspectRatio) {
                                 return new Rect(50, 50, 100, 100);
                             }
                         };