From a71febe2aaa2796cde538aa21c3e2ff006e7d3f3 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 22 May 2017 11:14:22 -0700 Subject: [PATCH] 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 --- .../android/view/IPinnedStackController.aidl | 8 ++++ .../systemui/pip/phone/PipTouchHandler.java | 8 +++- .../server/am/ActivityStackSupervisor.java | 4 +- .../server/am/PinnedActivityStack.java | 4 +- .../server/wm/PinnedStackController.java | 40 ++++++++++-------- .../wm/PinnedStackWindowController.java | 41 ++++++++----------- .../android/server/am/ActivityTestsBase.java | 3 +- 7 files changed, 60 insertions(+), 48 deletions(-) diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl index dbeb747adfba1..d2dcb568ef6cd 100644 --- a/core/java/android/view/IPinnedStackController.aidl +++ b/core/java/android/view/IPinnedStackController.aidl @@ -29,6 +29,14 @@ interface IPinnedStackController { */ 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. */ 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 c35fdd5c57810..854696ee313d9 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 @@ public class PipTouchHandler { * 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 e180aefcd11a2..e828d38ef249f 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 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // 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 702bf92c65f8f..2010c24000e83 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 @@ class PinnedActivityStack extends ActivityStack 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 fc4ec2889523a..9a9e29a7eb888 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 @@ class PinnedStackController { 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(); @@ -123,6 +122,13 @@ class PinnedStackController { }); } + @Override + public void setMinEdgeSize(int minEdgeSize) { + mHandler.post(() -> { + mCurrentMinSize = Math.max(mDefaultMinSize, minEdgeSize); + }); + } + @Override public int getDisplayRotation() { synchronized (mService.mWindowMap) { @@ -160,10 +166,12 @@ class PinnedStackController { */ 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 @@ class PinnedStackController { * 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()); @@ -227,16 +239,6 @@ class PinnedStackController { return stackBounds; } - /** - * @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. */ @@ -246,7 +248,8 @@ class PinnedStackController { 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 @@ class PinnedStackController { 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 0c628acba92c1..989e8f23693a6 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 @@ import java.util.List; */ 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 @@ public class PinnedStackWindowController extends StackWindowController { } /** - * @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 @@ public class PinnedStackWindowController extends StackWindowController { 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 @@ public class PinnedStackWindowController extends StackWindowController { } 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 @@ public class PinnedStackWindowController extends StackWindowController { 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 9cfa542da9d12..bac121695ed97 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 @@ public class ActivityTestsBase { 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); } };