Move rotation bounds calculation into SysUI

Also included in this CL
- Cleanup all bounds calculation in PinnedStackController
- Move PipSnapAlgorithm to SysUI

Bug: 139016833
Bug: 139016576
Bug: 145133340
Test: atest PinnedStackTests
Test: atest MultiDisplayActivityLaunchTest
Test: atest MultiDisplaySystemDecorationTests
Change-Id: Ifa0621a1cb69e76498e020aef7d8fa815df4ce48
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index f1d152b..00edb3a 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -45,4 +45,17 @@
      * {@param animationDuration} suggests the animation duration transitioning to PiP window.
      */
     void startAnimation(in Rect destinationBounds, in Rect sourceRectHint, int animationDuration);
+
+    /**
+     * Notifies the controller to reset on bounds animation, if there is any.
+     * This could happen when screen rotation is happening and we need to notify the WM to reset
+     * any running bounds animation on the pinned stack.
+     * {@param bounds} here is the final destination bounds.
+     */
+    void resetBoundsAnimation(in Rect bounds);
+
+    /**
+     * Reports the current default and movement bounds to controller.
+     */
+    void reportBounds(in Rect defaultBounds, in Rect movementBounds);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
index 75e260e..d1d9b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
@@ -20,11 +20,13 @@
 import android.content.res.Configuration;
 
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.io.PrintWriter;
 
 public interface BasePipManager {
-    void initialize(Context context, BroadcastDispatcher broadcastDispatcher);
+    void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+            DisplayWindowController displayWindowController);
     void showPictureInPictureMenu();
     default void expandPip() {}
     default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index f10274a..8e34a90 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -16,8 +16,14 @@
 
 package com.android.systemui.pip;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
 
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -32,10 +38,9 @@
 import android.view.Gravity;
 import android.view.IPinnedStackController;
 import android.view.IWindowManager;
+import android.view.WindowContainerTransaction;
 import android.view.WindowManagerGlobal;
 
-import com.android.internal.policy.PipSnapAlgorithm;
-
 import java.io.PrintWriter;
 
 /**
@@ -154,6 +159,7 @@
      */
     public void onMinimizedStateChanged(boolean minimized) {
         mIsMinimized = minimized;
+        mSnapAlgorithm.setMinimized(minimized);
     }
 
     /**
@@ -199,6 +205,7 @@
         mReentrySnapFraction = INVALID_SNAP_FRACTION;
         mReentrySize = null;
         mLastPipComponentName = null;
+        mLastDestinationBounds.setEmpty();
     }
 
     public Rect getLastDestinationBounds() {
@@ -235,8 +242,9 @@
      */
     public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
         final Rect destinationBounds;
+        final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
         if (bounds == null) {
-            destinationBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
+            destinationBounds = new Rect(defaultBounds);
         } else {
             destinationBounds = new Rect(bounds);
         }
@@ -253,12 +261,85 @@
             mPinnedStackController.startAnimation(destinationBounds, sourceRectHint,
                     -1 /* animationDuration */);
             mLastDestinationBounds.set(destinationBounds);
+            mPinnedStackController.reportBounds(defaultBounds,
+                    getMovementBounds(defaultBounds));
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to start PiP animation from SysUI", e);
         }
     }
 
     /**
+     * Updates the display info, calculating and returning the new stack and movement bounds in the
+     * new orientation of the device if necessary.
+     *
+     * @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
+     */
+    public boolean onDisplayRotationChanged(Rect outBounds, int displayId, int fromRotation,
+            int toRotation, WindowContainerTransaction t) {
+        // Bail early if the event is not sent to current {@link #mDisplayInfo}
+        if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
+            return false;
+        }
+
+        // Bail early if the pinned stack is staled.
+        final ActivityManager.StackInfo pinnedStackInfo;
+        try {
+            pinnedStackInfo = ActivityTaskManager.getService()
+                    .getStackInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+            if (pinnedStackInfo == null) return false;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get StackInfo for pinned stack", e);
+            return false;
+        }
+
+        // Calculate the snap fraction of the current stack along the old movement bounds
+        final Rect postChangeStackBounds = new Rect(mLastDestinationBounds);
+        final float snapFraction = getSnapFraction(postChangeStackBounds);
+
+        // Populate the new {@link #mDisplayInfo}.
+        // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
+        // therefore, the width/height may require a swap first.
+        // Moving forward, we should get the new dimensions after rotation from DisplayLayout.
+        mDisplayInfo.rotation = toRotation;
+        updateDisplayInfoIfNeeded();
+
+        // Calculate the stack bounds in the new orientation based on same fraction along the
+        // rotated movement bounds.
+        final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
+                false /* adjustForIme */);
+        mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
+                snapFraction);
+        if (mIsMinimized) {
+            applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
+        }
+
+        try {
+            outBounds.set(postChangeStackBounds);
+            mLastDestinationBounds.set(outBounds);
+            mPinnedStackController.resetBoundsAnimation(outBounds);
+            mPinnedStackController.reportBounds(outBounds, getMovementBounds(outBounds));
+            t.setBounds(pinnedStackInfo.stackToken, outBounds);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to resize PiP on display rotation", e);
+        }
+        return true;
+    }
+
+    private void updateDisplayInfoIfNeeded() {
+        final boolean updateNeeded;
+        if ((mDisplayInfo.rotation == ROTATION_0) || (mDisplayInfo.rotation == ROTATION_180)) {
+            updateNeeded = (mDisplayInfo.logicalWidth > mDisplayInfo.logicalHeight);
+        } else {
+            updateNeeded = (mDisplayInfo.logicalWidth < mDisplayInfo.logicalHeight);
+        }
+        if (updateNeeded) {
+            final int newLogicalHeight = mDisplayInfo.logicalWidth;
+            mDisplayInfo.logicalWidth = mDisplayInfo.logicalHeight;
+            mDisplayInfo.logicalHeight = newLogicalHeight;
+        }
+    }
+
+    /**
      * @return whether the given {@param aspectRatio} is valid.
      */
     private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
similarity index 99%
rename from core/java/com/android/internal/policy/PipSnapAlgorithm.java
rename to packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
index e3623c5..f3e707c 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.policy;
+package com.android.systemui.pip;
 
 import android.content.Context;
 import android.content.res.Configuration;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
index 583ce67..29de90b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
@@ -28,6 +28,7 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -44,15 +45,17 @@
     private final CommandQueue mCommandQueue;
     private BasePipManager mPipManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
-
+    private final DisplayWindowController mDisplayWindowController;
     private boolean mSupportsPip;
 
     @Inject
     public PipUI(Context context, CommandQueue commandQueue,
-            BroadcastDispatcher broadcastDispatcher) {
+            BroadcastDispatcher broadcastDispatcher,
+            DisplayWindowController displayWindowController) {
         super(context);
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
+        mDisplayWindowController = displayWindowController;
     }
 
     @Override
@@ -72,7 +75,7 @@
         mPipManager = pm.hasSystemFeature(FEATURE_LEANBACK_ONLY)
                 ? com.android.systemui.pip.tv.PipManager.getInstance()
                 : com.android.systemui.pip.phone.PipManager.getInstance();
-        mPipManager.initialize(mContext, mBroadcastDispatcher);
+        mPipManager.initialize(mContext, mBroadcastDispatcher, mDisplayWindowController);
 
         mCommandQueue.addCallback(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index a4707cf..0a89017 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -34,6 +34,7 @@
 import android.util.Pair;
 import android.view.DisplayInfo;
 import android.view.IPinnedStackController;
+import android.view.WindowContainerTransaction;
 
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
@@ -45,6 +46,7 @@
 import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.io.PrintWriter;
 
@@ -75,9 +77,22 @@
     private PipAppOpsListener mAppOpsListener;
 
     /**
+     * Handler for display rotation changes.
+     */
+    private final DisplayWindowController.OnDisplayWindowRotationController mRotationController = (
+            int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
+        final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds,
+                displayId, fromRotation, toRotation, t);
+        if (changed) {
+            updateMovementBounds(mTmpNormalBounds, false /* fromImeAdjustment */,
+                    false /* fromShelfAdjustment */);
+        }
+    };
+
+    /**
      * Handler for system task stack changes.
      */
-    TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+    private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
             mTouchHandler.onActivityPinned();
@@ -214,7 +229,8 @@
     /**
      * Initializes {@link PipManager}.
      */
-    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher) {
+    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+            DisplayWindowController displayWindowController) {
         mContext = context;
         mActivityManager = ActivityManager.getService();
         mActivityTaskManager = ActivityTaskManager.getService();
@@ -235,6 +251,7 @@
                 mMenuController, mInputConsumerController, mPipBoundsHandler);
         mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
                 mTouchHandler.getMotionHelper());
+        displayWindowController.addRotationController(mRotationController);
 
         // If SystemUI restart, and it already existed a pinned stack,
         // register the pip input consumer to ensure touch can send to it.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index fa60477..6afa0bf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -46,7 +46,7 @@
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
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 2e90a3e..054f573 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -46,9 +46,9 @@
 import android.view.accessibility.AccessibilityWindowInfo;
 
 import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.internal.policy.PipSnapAlgorithm;
 import com.android.systemui.R;
 import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 195fca8..696db68 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -55,6 +55,7 @@
 import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.wm.DisplayWindowController;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -228,7 +229,8 @@
     /**
      * Initializes {@link PipManager}.
      */
-    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher) {
+    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+            DisplayWindowController displayWindowController) {
         if (mInitialized) {
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
index ae82115..aa56ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
@@ -101,10 +101,11 @@
                             }
                             DisplayRecord record = new DisplayRecord();
                             record.mDisplayId = displayId;
-                            Display display = getDisplay(displayId);
-                            record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
-                                    : mContext.createDisplayContext(display);
-                            record.mDisplayLayout = new DisplayLayout(record.mContext, display);
+                            // TODO(b/146566787): disabled for MultiDisplayActivityLaunchTests
+                            // Display display = getDisplay(displayId);
+                            // record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+                            //         : mContext.createDisplayContext(display);
+                            // record.mDisplayLayout = new DisplayLayout(record.mContext, display);
                             mDisplays.put(displayId, record);
                             for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                                 mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
@@ -123,13 +124,14 @@
                                         + " display.");
                                 return;
                             }
-                            Display display = getDisplay(displayId);
-                            Context perDisplayContext = mContext;
-                            if (displayId != Display.DEFAULT_DISPLAY) {
-                                perDisplayContext = mContext.createDisplayContext(display);
-                            }
-                            dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
-                            dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
+                            // TODO(b/146566787): disabled for MultiDisplaySystemDecorationTests
+                            // Display display = getDisplay(displayId);
+                            // Context perDisplayContext = mContext;
+                            // if (displayId != Display.DEFAULT_DISPLAY) {
+                            //     perDisplayContext = mContext.createDisplayContext(display);
+                            // }
+                            // dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
+                            // dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
                             for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                                 mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
                                         displayId, newConfig);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 0d6e928..cae205e 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -821,10 +821,7 @@
         // Update bounds if applicable
         boolean hasNewOverrideBounds = false;
         // Use override windowing mode to prevent extra bounds changes if inheriting the mode.
-        if (overrideWindowingMode == WINDOWING_MODE_PINNED) {
-            // Pinned calculation already includes rotation
-            hasNewOverrideBounds = calculatePinnedBoundsForConfigChange(newBounds);
-        } else if (!matchParentBounds()) {
+        if ((overrideWindowingMode != WINDOWING_MODE_PINNED) && !matchParentBounds()) {
             // If the parent (display) has rotated, rotate our bounds to best-fit where their
             // bounds were on the pre-rotated display.
             final int newRotation = getWindowConfiguration().getRotation();
@@ -882,9 +879,6 @@
                         null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
                         null /* tempOtherTaskBounds */, null /* tempOtherTaskInsetBounds */,
                         PRESERVE_WINDOWS, true /* deferResume */);
-            } else {
-                resize(new Rect(newBounds), null /* tempTaskBounds */,
-                        null /* tempTaskInsetBounds */, PRESERVE_WINDOWS, true /* deferResume */);
             }
         }
         if (prevIsAlwaysOnTop != isAlwaysOnTop()) {
@@ -4102,45 +4096,27 @@
     }
 
     /**
-     * Updates the passed-in {@code inOutBounds} based on the current state of the
-     * pinned controller. This gets run *after* the override configuration is updated, so it's
-     * safe to rely on the controller's state in here (though eventually this dependence should
-     * be removed).
+     * Reset the current animation running on {@link #mBoundsAnimationTarget}.
      *
-     * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
-     * update pinned controller state.
-     *
-     * @param inOutBounds the bounds to update (both input and output).
-     * @return true if bounds were updated to some non-empty value.
+     * @param destinationBounds the final destination bounds
      */
-    boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) {
-        boolean animating = false;
-        if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
-            animating = true;
-            getFinalAnimationBounds(mTmpRect2);
-        } else {
-            mTmpRect2.set(inOutBounds);
-        }
-        boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
-                mTmpRect2, mTmpRect3);
-        if (updated) {
-            inOutBounds.set(mTmpRect3);
+    void resetCurrentBoundsAnimation(Rect destinationBounds) {
+        boolean animating = (mBoundsAnimatingRequested || mBoundsAnimating)
+                && !mBoundsAnimationTarget.isEmpty();
 
-            // The final boundary is updated while there is an existing boundary animation. Let's
-            // cancel this animation to prevent the obsolete animation overwritten updated bounds.
-            if (animating && !inOutBounds.equals(mBoundsAnimationTarget)) {
-                final DisplayContent displayContent = getDisplayContent();
-                displayContent.mBoundsAnimationController.getHandler().post(() ->
-                        displayContent.mBoundsAnimationController.cancel(this));
-            }
-            // Once we've set the bounds based on the rotation of the old bounds in the new
-            // orientation, clear the animation target bounds since they are obsolete, and
-            // cancel any currently running animations
-            mBoundsAnimationTarget.setEmpty();
-            mBoundsAnimationSourceHintBounds.setEmpty();
-            mCancelCurrentBoundsAnimation = true;
+        // The final boundary is updated while there is an existing boundary animation. Let's
+        // cancel this animation to prevent the obsolete animation overwritten updated bounds.
+        if (animating && !destinationBounds.equals(mBoundsAnimationTarget)) {
+            final BoundsAnimationController controller =
+                    getDisplayContent().mBoundsAnimationController;
+            controller.getHandler().post(() -> controller.cancel(this));
         }
-        return updated;
+        // Once we've set the bounds based on the rotation of the old bounds in the new
+        // orientation, clear the animation target bounds since they are obsolete, and
+        // cancel any currently running animations
+        mBoundsAnimationTarget.setEmpty();
+        mBoundsAnimationSourceHintBounds.setEmpty();
+        mCancelCurrentBoundsAnimation = true;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f0bc412..fbd25b7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3302,6 +3302,23 @@
         Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
         c.setTo(change.getConfiguration(), configMask, windowMask);
         container.onRequestedOverrideConfigurationChanged(c);
+        // TODO(b/145675353): remove the following once we could apply new bounds to the
+        // pinned stack together with its children.
+        resizePinnedStackIfNeeded(container, configMask, windowMask, c);
+    }
+
+    private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
+            int windowMask, Configuration config) {
+        if ((container instanceof ActivityStack)
+                && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0)
+                && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) {
+            final ActivityStack stack = (ActivityStack) container;
+            if (stack.inPinnedWindowingMode()) {
+                stack.resize(config.windowConfiguration.getBounds(),
+                        null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                        PRESERVE_WINDOWS, true /* deferResume */);
+            }
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 5dc88b3..9b464c2 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -185,6 +185,10 @@
             resume();
         };
 
+        // If this animator is explicitly cancelled when it's in paused state, we should not
+        // attempt to resume the animation. Use this flag to avoid such behavior.
+        private boolean mIsCancelled;
+
         BoundsAnimator(BoundsAnimationTarget target, @AnimationType int animationType, Rect from,
                 Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState,
                 @SchedulePipModeChangedState int prevShedulePipModeChangedState,
@@ -221,6 +225,7 @@
             if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
                     + " mPrevSchedulePipModeChangedState=" + mPrevSchedulePipModeChangedState
                     + " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState);
+            mIsCancelled = false;
             mFinishAnimationAfterTransition = false;
             mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth,
                     mFrom.top + mFrozenTaskHeight);
@@ -293,7 +298,7 @@
         public void resume() {
             if (DEBUG) Slog.d(TAG, "resume:");
             mHandler.removeCallbacks(mResumeRunnable);
-            super.resume();
+            if (!mIsCancelled) super.resume();
         }
 
         @Override
@@ -376,6 +381,7 @@
 
         @Override
         public void onAnimationCancel(Animator animation) {
+            mIsCancelled = true;
             // Always skip the final resize when the animation is canceled
             mSkipFinalResize = true;
             mMoveToFullscreen = false;
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index a8e7aea..b4f75e5 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -16,38 +16,29 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
 
 import static com.android.server.wm.PinnedStackControllerProto.DEFAULT_BOUNDS;
 import static com.android.server.wm.PinnedStackControllerProto.MOVEMENT_BOUNDS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-import android.annotation.NonNull;
 import android.app.RemoteAction;
 import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.Size;
 import android.util.Slog;
-import android.util.TypedValue;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayInfo;
-import android.view.Gravity;
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
 
-import com.android.internal.policy.PipSnapAlgorithm;
-import com.android.internal.util.Preconditions;
 import com.android.server.UiThread;
 
 import java.io.PrintWriter;
@@ -74,7 +65,6 @@
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
 
-    private static final float INVALID_SNAP_FRACTION = -1f;
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
     private final Handler mHandler = UiThread.getHandler();
@@ -84,7 +74,6 @@
             new PinnedStackListenerDeathHandler();
 
     private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
-    private final PipSnapAlgorithm mSnapAlgorithm;
 
     // States that affect how the PIP can be manipulated
     private boolean mIsMinimized;
@@ -97,13 +86,9 @@
 
     // Used to calculate stack bounds across rotations
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
-    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;
 
     // The aspect ratio bounds of the PIP.
     private float mMinAspectRatio;
@@ -111,10 +96,11 @@
 
     // Temp vars for calculation
     private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
-    private final Rect mTmpInsets = new Rect();
-    private final Rect mTmpRect = new Rect();
-    private final Point mTmpDisplaySize = new Point();
 
+    // TODO(b/141200935): remove this when we have default/movement bounds tests in SysUI.
+    // Keep record of the default and movement bounds
+    private final Rect mLastReportedDefaultBounds = new Rect();
+    private final Rect mLastReportedMovementBounds = new Rect();
 
     /**
      * The callback object passed to listeners for them to notify the controller of state changes.
@@ -125,7 +111,6 @@
         public void setIsMinimized(final boolean isMinimized) {
             mHandler.post(() -> {
                 mIsMinimized = isMinimized;
-                mSnapAlgorithm.setMinimized(isMinimized);
             });
         }
 
@@ -145,6 +130,27 @@
                         sourceRectHint, animationDuration, true /* fromFullscreen */);
             }
         }
+
+        @Override
+        public void resetBoundsAnimation(Rect bounds) {
+            synchronized (mService.mGlobalLock) {
+                if (mDisplayContent.hasPinnedStack()) {
+                    final ActivityStack pinnedStack = mDisplayContent.getTopStackInWindowingMode(
+                            WINDOWING_MODE_PINNED);
+                    if (pinnedStack != null) {
+                        pinnedStack.resetCurrentBoundsAnimation(bounds);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void reportBounds(Rect defaultBounds, Rect movementBounds) {
+            synchronized (mService.mGlobalLock) {
+                mLastReportedDefaultBounds.set(defaultBounds);
+                mLastReportedMovementBounds.set(movementBounds);
+            }
+        }
     }
 
     /**
@@ -165,7 +171,6 @@
     PinnedStackController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
         mDisplayContent = displayContent;
-        mSnapAlgorithm = new PipSnapAlgorithm(service.mContext);
         mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
         reloadResources();
         // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
@@ -183,21 +188,9 @@
      */
     private void reloadResources() {
         final Resources res = mService.mContext.getResources();
-        mDefaultMinSize = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
         mDefaultAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
-        final String screenEdgeInsetsDpString = res.getString(
-                com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
-        final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
-                ? Size.parseSize(screenEdgeInsetsDpString)
-                : null;
-        mDefaultStackGravity = res.getInteger(
-                com.android.internal.R.integer.config_defaultPictureInPictureGravity);
         mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics);
-        mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
-                : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
-                        dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
         mMinAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
         mMaxAspectRatio = res.getFloat(
@@ -215,7 +208,7 @@
             notifyDisplayInfoChanged(mDisplayInfo);
             notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
             // The movement bounds notification needs to be sent before the minimized state, since
-            // SystemUI may use the bounds to retore the minimized position
+            // SystemUI may use the bounds to restore the minimized position
             notifyMovementBoundsChanged(false /* fromImeAdjustment */,
                     false /* fromShelfAdjustment */);
             notifyActionsChanged(mActions);
@@ -257,30 +250,6 @@
         }
     }
 
-    /**
-     * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
-     * will apply the default bounds to the provided snap fraction.
-     */
-    private Rect getDefaultBounds(float snapFraction) {
-        synchronized (mService.mGlobalLock) {
-            final Rect insetBounds = new Rect();
-            getInsetBounds(insetBounds);
-
-            final Rect defaultBounds = new Rect();
-            final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
-                    mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
-            if (snapFraction != INVALID_SNAP_FRACTION) {
-                defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
-                final Rect movementBounds = getMovementBounds(defaultBounds);
-                mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
-            } else {
-                Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
-                        0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
-            }
-            return defaultBounds;
-        }
-    }
-
     private void setDisplayInfo(DisplayInfo displayInfo) {
         mDisplayInfo.copyFrom(displayInfo);
         notifyDisplayInfoChanged(mDisplayInfo);
@@ -300,51 +269,6 @@
     }
 
     /**
-     * Updates the display info, calculating and returning the new stack and movement bounds in the
-     * new orientation of the device if necessary.
-     */
-    boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) {
-        synchronized (mService.mGlobalLock) {
-            final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-            if (isSameDimensionAndRotation(mDisplayInfo, displayInfo)) {
-                // No dimension/rotation change, ignore
-                outBounds.setEmpty();
-                return false;
-            } else if (targetBounds.isEmpty()) {
-                // The stack is null, we are just initializing the stack, so just store the display
-                // info and ignore
-                setDisplayInfo(displayInfo);
-                outBounds.setEmpty();
-                return false;
-            }
-
-            mTmpRect.set(targetBounds);
-            final Rect postChangeStackBounds = mTmpRect;
-
-            // Calculate the snap fraction of the current stack along the old movement bounds
-            final float snapFraction = getSnapFraction(postChangeStackBounds);
-
-            setDisplayInfo(displayInfo);
-
-            // Calculate the stack bounds in the new orientation to the same same fraction along the
-            // rotated movement bounds.
-            final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
-                    false /* adjustForIme */);
-            mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
-                    snapFraction);
-            if (mIsMinimized) {
-                applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
-            }
-
-            notifyMovementBoundsChanged(false /* fromImeAdjustment */,
-                    false /* fromShelfAdjustment */);
-
-            outBounds.set(postChangeStackBounds);
-            return true;
-        }
-    }
-
-    /**
      * Sets the Ime state and height.
      */
     void setAdjustedForIme(boolean adjustedForIme, int imeHeight) {
@@ -400,15 +324,6 @@
         notifyPrepareAnimation(sourceRectHint, aspectRatio, stackBounds);
     }
 
-    private boolean isSameDimensionAndRotation(@NonNull DisplayInfo display1,
-            @NonNull DisplayInfo display2) {
-        Preconditions.checkNotNull(display1);
-        Preconditions.checkNotNull(display2);
-        return ((display1.rotation == display2.rotation)
-                && (display1.logicalWidth == display2.logicalWidth)
-                && (display1.logicalHeight == display2.logicalHeight));
-    }
-
     /**
      * Notifies listeners that the PIP needs to be adjusted for the IME.
      */
@@ -504,86 +419,11 @@
         }
     }
 
-    /**
-     * @return the bounds on the screen that the PIP can be visible in.
-     */
-    private void getInsetBounds(Rect outRect) {
-        synchronized (mService.mGlobalLock) {
-            mDisplayContent.getDisplayPolicy().getStableInsetsLw(mDisplayInfo.rotation,
-                    mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
-                    mDisplayInfo.displayCutout, mTmpInsets);
-            outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y,
-                    mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x,
-                    mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y);
-        }
-    }
-
-    /**
-     * @return the movement bounds for the given {@param stackBounds} and the current state of the
-     *         controller.
-     */
-    private Rect getMovementBounds(Rect stackBounds) {
-        synchronized (mService.mGlobalLock) {
-            return getMovementBounds(stackBounds, true /* adjustForIme */);
-        }
-    }
-
-    /**
-     * @return the movement bounds for the given {@param stackBounds} and the current state of the
-     *         controller.
-     */
-    private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
-        synchronized (mService.mGlobalLock) {
-            final Rect movementBounds = new Rect();
-            getInsetBounds(movementBounds);
-
-            // Apply the movement bounds adjustments based on the current state.
-            // Note that shelf offset does not affect the movement bounds here
-            // since it's been taken care of in system UI.
-            mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
-                    (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
-            return movementBounds;
-        }
-    }
-
-    /**
-     * Applies the minimized offsets to the given stack bounds.
-     */
-    private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) {
-        synchronized (mService.mGlobalLock) {
-            mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
-            mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets);
-            mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize,
-                    mStableInsets);
-        }
-    }
-
-    /**
-     * @return the default snap fraction to apply instead of the default gravity when calculating
-     *         the default stack bounds when first entering PiP.
-     */
-    private float getSnapFraction(Rect stackBounds) {
-        return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
-    }
-
-    /**
-     * @return the pixels for a given dp value.
-     */
-    private int dpToPx(float dpValue, DisplayMetrics dm) {
-        return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
-    }
-
     void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "PinnedStackController");
-        pw.print(prefix + "  defaultBounds=");
-        getDefaultBounds(INVALID_SNAP_FRACTION).printShortString(pw);
-        pw.println();
-        pw.println(prefix + "  mDefaultMinSize=" + mDefaultMinSize);
-        pw.println(prefix + "  mDefaultStackGravity=" + mDefaultStackGravity);
+        pw.println(prefix + "  mLastReportedDefaultBounds=" + mLastReportedDefaultBounds);
+        pw.println(prefix + "  mLastReportedMovementBounds=" + mLastReportedMovementBounds);
         pw.println(prefix + "  mDefaultAspectRatio=" + mDefaultAspectRatio);
-        mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
-        pw.print(prefix + "  movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
-        pw.println();
         pw.println(prefix + "  mIsImeShowing=" + mIsImeShowing);
         pw.println(prefix + "  mImeHeight=" + mImeHeight);
         pw.println(prefix + "  mIsMinimized=" + mIsMinimized);
@@ -606,9 +446,8 @@
 
     void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        getDefaultBounds(INVALID_SNAP_FRACTION).dumpDebug(proto, DEFAULT_BOUNDS);
-        mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
-        getMovementBounds(mTmpRect).dumpDebug(proto, MOVEMENT_BOUNDS);
+        mLastReportedDefaultBounds.dumpDebug(proto, DEFAULT_BOUNDS);
+        mLastReportedMovementBounds.dumpDebug(proto, MOVEMENT_BOUNDS);
         proto.end(token);
     }
 }