diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java index 7c69c0cf3d67a..ef2f897a52e7b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java @@ -58,8 +58,6 @@ public class PipBoundsHandler { private int mDefaultStackGravity; private int mDefaultMinSize; private Point mScreenEdgeInsets; - private int mCurrentMinSize; - private Size mOverrideMinimalSize; private boolean mIsImeShowing; private int mImeHeight; @@ -74,6 +72,7 @@ public class PipBoundsHandler { // resources as it would clobber mAspectRatio when entering PiP from fullscreen which // triggers a configuration change and the resources to be reloaded. mPipBoundsState.setAspectRatio(mDefaultAspectRatio); + mPipBoundsState.setMinEdgeSize(mDefaultMinSize); } /** @@ -87,7 +86,6 @@ public class PipBoundsHandler { com.android.internal.R.integer.config_defaultPictureInPictureGravity); mDefaultMinSize = res.getDimensionPixelSize( com.android.internal.R.dimen.default_minimal_size_pip_resizable_task); - mCurrentMinSize = mDefaultMinSize; final String screenEdgeInsetsDpString = res.getString( com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets); final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty() @@ -102,14 +100,6 @@ public class PipBoundsHandler { com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio); } - /** - * Update the Min edge size for {@link PipSnapAlgorithm} to calculate corresponding bounds - * @param minEdgeSize - */ - public void setMinEdgeSize(int minEdgeSize) { - mCurrentMinSize = minEdgeSize; - } - /** * Sets both shelf visibility and its height if applicable. * @return {@code true} if the internal shelf state is changed, {@code false} otherwise. @@ -167,16 +157,16 @@ public class PipBoundsHandler { } /** - * See {@link #getDestinationBounds(Rect, Size, boolean)} + * See {@link #getDestinationBounds(Rect, boolean)} */ - public Rect getDestinationBounds(Rect bounds, Size minimalSize) { - return getDestinationBounds(bounds, minimalSize, false /* useCurrentMinEdgeSize */); + public Rect getDestinationBounds(Rect bounds) { + return getDestinationBounds(bounds, false /* useCurrentMinEdgeSize */); } /** * @return {@link Rect} of the destination PiP window bounds. */ - public Rect getDestinationBounds(Rect bounds, Size minimalSize, boolean useCurrentMinEdgeSize) { + public Rect getDestinationBounds(Rect bounds, boolean useCurrentMinEdgeSize) { boolean isReentryBounds = false; final Rect destinationBounds; if (bounds == null) { @@ -191,7 +181,6 @@ public class PipBoundsHandler { } else { // Get actual default bounds. defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */); - mOverrideMinimalSize = minimalSize; } destinationBounds = new Rect(defaultBounds); @@ -306,67 +295,56 @@ public class PipBoundsHandler { && Float.compare(aspectRatio, mMaxAspectRatio) <= 0; } - /** - * Sets the current bound with the currently store aspect ratio. - * @param stackBounds - */ - public void transformBoundsToAspectRatio(Rect stackBounds) { - transformBoundsToAspectRatio(stackBounds, mPipBoundsState.getAspectRatio(), - true /* useCurrentMinEdgeSize */, true /* useCurrentSize */); - } - /** * Set the current bounds (or the default bounds if there are no current bounds) with the * specified aspect ratio. */ - private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio, + public void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio, boolean useCurrentMinEdgeSize, boolean useCurrentSize) { // Save the snap fraction and adjust the size based on the new aspect ratio. final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds), mPipBoundsState.getStashedState()); - final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize; + + final Size overrideMinSize = mPipBoundsState.getOverrideMinSize(); final Size size; if (useCurrentMinEdgeSize || useCurrentSize) { + // The default minimum edge size, or the override min edge size if set. + final int defaultMinEdgeSize = overrideMinSize == null ? mDefaultMinSize + : mPipBoundsState.getOverrideMinEdgeSize(); + final int minEdgeSize = useCurrentMinEdgeSize ? mPipBoundsState.getMinEdgeSize() + : defaultMinEdgeSize; + // Use the existing size but adjusted to the aspect ratio and min edge size. size = mSnapAlgorithm.getSizeForAspectRatio( new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize); } else { - final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo(); - size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize, - displayInfo.logicalWidth, displayInfo.logicalHeight); + if (overrideMinSize != null) { + // The override minimal size is set, use that as the default size making sure it's + // adjusted to the aspect ratio. + size = adjustSizeToAspectRatio(overrideMinSize, aspectRatio); + } else { + // Calculate the default size using the display size and default min edge size. + final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo(); + size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mDefaultMinSize, + displayInfo.logicalWidth, displayInfo.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()); - // apply the override minimal size if applicable, this minimal size is specified by app - if (mOverrideMinimalSize != null) { - transformBoundsToMinimalSize(stackBounds, aspectRatio, mOverrideMinimalSize); - } mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction); } - /** - * Transforms a given bounds to meet the minimal size constraints. - * This function assumes the given {@param stackBounds} qualifies {@param aspectRatio}. - */ - private void transformBoundsToMinimalSize(Rect stackBounds, float aspectRatio, - Size minimalSize) { - if (minimalSize == null) return; - final Size adjustedMinimalSize; - final float minimalSizeAspectRatio = - minimalSize.getWidth() / (float) minimalSize.getHeight(); - if (minimalSizeAspectRatio > aspectRatio) { - // minimal size is wider, fixed the width and increase the height - adjustedMinimalSize = new Size( - minimalSize.getWidth(), (int) (minimalSize.getWidth() / aspectRatio)); + /** Adjusts the given size to conform to the given aspect ratio. */ + private Size adjustSizeToAspectRatio(@NonNull Size size, float aspectRatio) { + final float sizeAspectRatio = size.getWidth() / (float) size.getHeight(); + if (sizeAspectRatio > aspectRatio) { + // Size is wider, fix the width and increase the height + return new Size(size.getWidth(), (int) (size.getWidth() / aspectRatio)); } else { - adjustedMinimalSize = new Size( - (int) (minimalSize.getHeight() * aspectRatio), minimalSize.getHeight()); + // Size is taller, fix the height and adjust the width. + return new Size((int) (size.getHeight() * aspectRatio), size.getHeight()); } - final Rect containerBounds = new Rect(stackBounds); - Gravity.apply(mDefaultStackGravity, - adjustedMinimalSize.getWidth(), adjustedMinimalSize.getHeight(), - containerBounds, stackBounds); } /** @@ -383,12 +361,20 @@ public class PipBoundsHandler { final Rect insetBounds = new Rect(); getInsetBounds(insetBounds); final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo(); - size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio, - mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight); - Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds, - 0, Math.max(mIsImeShowing ? mImeHeight : 0, - mIsShelfShowing ? mShelfHeight : 0), - defaultBounds); + final Size defaultSize; + final Size overrideMinSize = mPipBoundsState.getOverrideMinSize(); + if (overrideMinSize != null) { + // The override minimal size is set, use that as the default size making sure it's + // adjusted to the aspect ratio. + defaultSize = adjustSizeToAspectRatio(overrideMinSize, mDefaultAspectRatio); + } else { + // Calculate the default size using the display size and default min edge size. + defaultSize = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio, + mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight); + } + Gravity.apply(mDefaultStackGravity, defaultSize.getWidth(), defaultSize.getHeight(), + insetBounds, 0, Math.max(mIsImeShowing ? mImeHeight : 0, + mIsShelfShowing ? mShelfHeight : 0), defaultBounds); } return defaultBounds; } @@ -443,6 +429,10 @@ public class PipBoundsHandler { mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction); } + public int getDefaultMinSize() { + return mDefaultMinSize; + } + /** * @return the pixels for a given dp value. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java index 57867d0b08488..8d229d3774a28 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java @@ -61,8 +61,14 @@ public final class PipBoundsState { private ComponentName mLastPipComponentName; private final DisplayInfo mDisplayInfo = new DisplayInfo(); private final DisplayLayout mDisplayLayout = new DisplayLayout(); + /** The current minimum edge size of PIP. */ + private int mMinEdgeSize; + /** The preferred minimum (and default) size specified by apps. */ + private Size mOverrideMinSize; private final @NonNull AnimatingBoundsState mAnimatingBoundsState = new AnimatingBoundsState(); + private Runnable mOnMinimalSizeChangeCallback; + public PipBoundsState(Context context) { mContext = context; reloadResources(); @@ -203,10 +209,49 @@ public final class PipBoundsState { mPipReentryState = null; } + /** Set the PIP minimum edge size. */ + public void setMinEdgeSize(int minEdgeSize) { + mMinEdgeSize = minEdgeSize; + } + + /** Returns the PIP's current minimum edge size. */ + public int getMinEdgeSize() { + return mMinEdgeSize; + } + + /** + * Sets the preferred size of PIP as specified by the activity in PIP mode. + */ + public void setOverrideMinSize(Size overrideMinSize) { + final boolean changed = !Objects.equals(overrideMinSize, mOverrideMinSize); + mOverrideMinSize = overrideMinSize; + if (changed && mOnMinimalSizeChangeCallback != null) { + mOnMinimalSizeChangeCallback.run(); + } + } + + /** Returns the preferred minimal size specified by the activity in PIP. */ + public Size getOverrideMinSize() { + return mOverrideMinSize; + } + + /** Returns the minimum edge size of the override minimum size, or 0 if not set. */ + public int getOverrideMinEdgeSize() { + if (mOverrideMinSize == null) return 0; + return Math.min(mOverrideMinSize.getWidth(), mOverrideMinSize.getHeight()); + } + public AnimatingBoundsState getAnimatingBoundsState() { return mAnimatingBoundsState; } + /** + * Registers a callback when the minimal size of PIP that is set by the app changes. + */ + public void setOnMinimalSizeChangeCallback(Runnable onMinimalSizeChangeCallback) { + mOnMinimalSizeChangeCallback = onMinimalSizeChangeCallback; + } + /** Source of truth for the current animation bounds of PIP. */ public static class AnimatingBoundsState { /** The bounds used when PIP is being dragged or animated. */ @@ -298,6 +343,8 @@ public final class PipBoundsState { pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout); pw.println(innerPrefix + "mStashedState=" + mStashedState); pw.println(innerPrefix + "mStashOffset=" + mStashOffset); + pw.println(innerPrefix + "mMinEdgeSize=" + mMinEdgeSize); + pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize); if (mPipReentryState == null) { pw.println(innerPrefix + "mPipReentryState=null"); } else { 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 b2f4b55003003..1222c060bd988 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 @@ -339,10 +339,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, PictureInPictureParams pictureInPictureParams) { mShouldIgnoreEnteringPipTransition = true; sendOnPipTransitionStarted(componentName, TRANSITION_DIRECTION_TO_PIP); - mPipBoundsState.setLastPipComponentName(componentName); - mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(pictureInPictureParams)); - return mPipBoundsHandler.getDestinationBounds(null /* bounds */, - getMinimalSize(activityInfo)); + setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo); + return mPipBoundsHandler.getDestinationBounds(null /* bounds */); } /** @@ -356,6 +354,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } } + private void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params, + ActivityInfo activityInfo) { + mPipBoundsState.setLastPipComponentName(componentName); + mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(params)); + mPipBoundsState.setOverrideMinSize(getMinimalSize(activityInfo)); + } + /** * Expands PiP to the previous bounds, this is done in two phases using * {@link WindowContainerTransaction} @@ -483,7 +488,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mLeash = leash; mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); mPictureInPictureParams = mTaskInfo.pictureInPictureParams; - mPipBoundsState.setLastPipComponentName(mTaskInfo.topActivity); + setBoundsStateForEntry(mTaskInfo.topActivity, mPictureInPictureParams, + mTaskInfo.topActivityInfo); mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo); mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER); @@ -520,9 +526,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return; } - mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(mPictureInPictureParams)); - final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(null /* bounds */, - getMinimalSize(mTaskInfo.topActivityInfo)); + final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(null /* bounds */); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); @@ -675,6 +679,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken"); mPipBoundsState.setLastPipComponentName(info.topActivity); + mPipBoundsState.setOverrideMinSize(getMinimalSize(info.topActivityInfo)); final PictureInPictureParams newParams = info.pictureInPictureParams; if (newParams == null || !applyPictureInPictureParams(newParams)) { Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams); @@ -682,8 +687,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } // Aspect ratio changed, re-calculate destination bounds. final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - mPipBoundsState.getBounds(), getMinimalSize(info.topActivityInfo), - true /* userCurrentMinEdgeSize */); + mPipBoundsState.getBounds(), true /* useCurrentMinEdgeSize */); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration, null /* updateBoundsCallback */); @@ -698,7 +702,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, public void onFixedRotationFinished(int displayId) { if (mShouldDeferEnteringPip && mState.isInPip()) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo)); + null /* bounds */); // schedule a regular animation to ensure all the callbacks are still being sent enterPipWithAlphaAnimation(destinationBounds, 0 /* durationMs */); } @@ -773,8 +777,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return; } - final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(null /* bounds */, - getMinimalSize(mTaskInfo.topActivityInfo)); + final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(null /* bounds */); if (newDestinationBounds.equals(currentDestinationBounds)) return; if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) { animator.updateEndValue(newDestinationBounds); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 6e1fc83a87fb7..c4da7974dadb8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -242,9 +242,16 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac displayController.getDisplay(displayId).getDisplayInfo(newDisplayInfo); mPipBoundsState.setDisplayInfo(newDisplayInfo); updateMovementBounds(null /* toBounds */, false /* fromRotation */, - false /* fromImeAdjustment */, false /* fromShelfAdustment */, + false /* fromImeAdjustment */, false /* fromShelfAdjustment */, null /* wct */); }); + mPipBoundsState.setOnMinimalSizeChangeCallback( + () -> { + // The minimal size drives the normal bounds, so they need to be recalculated. + updateMovementBounds(null /* toBounds */, false /* fromRotation */, + false /* fromImeAdjustment */, false /* fromShelfAdjustment */, + null /* wct */); + }); mMediaController = pipMediaController; mMenuController = pipMenuActivityController; mTouchHandler = pipTouchHandler; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java index f3d8c7b0f5982..124683e2ff375 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java @@ -451,7 +451,9 @@ public class PipResizeGestureHandler { mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x, mMinSize.y, mMaxSize, true, mLastDownBounds.width() > mLastDownBounds.height())); - mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds); + mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds, + mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */, + true /* useCurrentSize */); mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds, null); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java index 9ba46723081f9..281d3ce74f672 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java @@ -848,8 +848,9 @@ public class PipTouchHandler { mMotionHelper.setCurrentMovementBounds(mMovementBounds); boolean isMenuExpanded = mMenuState == MENU_STATE_FULL; - mPipBoundsHandler.setMinEdgeSize( - isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0); + mPipBoundsState.setMinEdgeSize( + isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize + : mPipBoundsHandler.getDefaultMinSize()); } private Rect getMovementBounds(Rect curBounds) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java index a3eaac4a31d99..28bfa46308efc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java @@ -124,7 +124,7 @@ public class PipBoundsHandlerTest extends ShellTestCase { for (float aspectRatio : aspectRatios) { mPipBoundsState.setAspectRatio(aspectRatio); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds matches the given aspect ratio", @@ -141,7 +141,7 @@ public class PipBoundsHandlerTest extends ShellTestCase { for (float aspectRatio : invalidAspectRatios) { mPipBoundsState.setAspectRatio(aspectRatio); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds fallbacks to default aspect ratio", @@ -157,8 +157,7 @@ public class PipBoundsHandlerTest extends ShellTestCase { currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left; mPipBoundsState.setAspectRatio(aspectRatio); - final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(currentBounds, - EMPTY_MINIMAL_SIZE); + final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(currentBounds); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); @@ -182,8 +181,9 @@ public class PipBoundsHandlerTest extends ShellTestCase { final float aspectRatio = aspectRatios[i]; final Size minimalSize = minimalSizes[i]; mPipBoundsState.setAspectRatio(aspectRatio); + mPipBoundsState.setOverrideMinSize(minimalSize); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, minimalSize); + EMPTY_CURRENT_BOUNDS); assertTrue("Destination bounds is no smaller than minimal requirement", (destinationBounds.width() == minimalSize.getWidth() && destinationBounds.height() >= minimalSize.getHeight()) @@ -204,8 +204,9 @@ public class PipBoundsHandlerTest extends ShellTestCase { final Size minSize = new Size(currentBounds.width() / 2, currentBounds.height() / 2); mPipBoundsState.setAspectRatio(aspectRatio); + mPipBoundsState.setOverrideMinSize(minSize); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - currentBounds, minSize); + currentBounds, true /* useCurrentMinEdgeSize */); assertTrue("Destination bounds ignores minimal size", destinationBounds.width() > minSize.getWidth() @@ -216,13 +217,13 @@ public class PipBoundsHandlerTest extends ShellTestCase { public void getDestinationBounds_reentryStateExists_restoreLastSize() { mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO); final Rect reentryBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); reentryBounds.scale(1.25f); final float reentrySnapFraction = mPipBoundsHandler.getSnapFraction(reentryBounds); mPipBoundsState.saveReentryState(reentryBounds, reentrySnapFraction); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); assertEquals(reentryBounds.width(), destinationBounds.width()); assertEquals(reentryBounds.height(), destinationBounds.height()); @@ -232,14 +233,14 @@ public class PipBoundsHandlerTest extends ShellTestCase { public void getDestinationBounds_reentryStateExists_restoreLastPosition() { mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO); final Rect reentryBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); reentryBounds.offset(0, -100); final float reentrySnapFraction = mPipBoundsHandler.getSnapFraction(reentryBounds); mPipBoundsState.saveReentryState(reentryBounds, reentrySnapFraction); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); assertBoundsInclusionWithMargin("restoreLastPosition", reentryBounds, destinationBounds); } @@ -249,11 +250,11 @@ public class PipBoundsHandlerTest extends ShellTestCase { final int shelfHeight = 100; mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO); final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); mPipBoundsHandler.setShelfHeight(true, shelfHeight); final Rect newPosition = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); oldPosition.offset(0, -shelfHeight); assertBoundsInclusionWithMargin("offsetBounds by shelf", oldPosition, newPosition); @@ -264,11 +265,11 @@ public class PipBoundsHandlerTest extends ShellTestCase { final int imeHeight = 100; mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO); final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight); final Rect newPosition = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); oldPosition.offset(0, -imeHeight); assertBoundsInclusionWithMargin("offsetBounds by IME", oldPosition, newPosition); @@ -278,12 +279,12 @@ public class PipBoundsHandlerTest extends ShellTestCase { public void getDestinationBounds_noReentryState_useDefaultBounds() { mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO); final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); mPipBoundsState.clearReentryState(); final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( - EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + EMPTY_CURRENT_BOUNDS); assertBoundsInclusionWithMargin("useDefaultBounds", defaultBounds, actualBounds); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java index f4143f6ee3e0a..ea6092a8f7741 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java @@ -30,12 +30,14 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.PictureInPictureParams; import android.content.ComponentName; +import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.RemoteException; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Rational; +import android.util.Size; import android.view.DisplayInfo; import android.window.WindowContainerToken; @@ -113,6 +115,15 @@ public class PipTaskOrganizerTest extends ShellTestCase { assertEquals(mComponent1, mPipBoundsState.getLastPipComponentName()); } + @Test + public void startSwipePipToHome_updatesOverrideMinSize() { + final Size minSize = new Size(100, 80); + + mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, createActivityInfo(minSize), null); + + assertEquals(minSize, mPipBoundsState.getOverrideMinSize()); + } + @Test public void onTaskAppeared_updatesAspectRatio() { final Rational aspectRatio = new Rational(2, 1); @@ -131,6 +142,17 @@ public class PipTaskOrganizerTest extends ShellTestCase { assertEquals(mComponent1, mPipBoundsState.getLastPipComponentName()); } + @Test + public void onTaskAppeared_updatesOverrideMinSize() { + final Size minSize = new Size(100, 80); + + mSpiedPipTaskOrganizer.onTaskAppeared( + createTaskInfo(mComponent1, createPipParams(null), minSize), + null /* leash */); + + assertEquals(minSize, mPipBoundsState.getOverrideMinSize()); + } + @Test public void onTaskInfoChanged_updatesAspectRatioIfChanged() { final Rational startAspectRatio = new Rational(2, 1); @@ -155,11 +177,23 @@ public class PipTaskOrganizerTest extends ShellTestCase { assertEquals(mComponent2, mPipBoundsState.getLastPipComponentName()); } + @Test + public void onTaskInfoChanged_updatesOverrideMinSize() { + mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1, + createPipParams(null)), null /* leash */); + + final Size minSize = new Size(100, 80); + mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2, + createPipParams(null), minSize)); + + assertEquals(minSize, mPipBoundsState.getOverrideMinSize()); + } + private void preparePipTaskOrg() { final DisplayInfo info = new DisplayInfo(); mPipBoundsState.setDisplayInfo(info); - when(mMockPipBoundsHandler.getDestinationBounds(any(), any())).thenReturn(new Rect()); - when(mMockPipBoundsHandler.getDestinationBounds(any(), any(), anyBoolean())) + when(mMockPipBoundsHandler.getDestinationBounds(any())).thenReturn(new Rect()); + when(mMockPipBoundsHandler.getDestinationBounds(any(), anyBoolean())) .thenReturn(new Rect()); mPipBoundsState.setDisplayInfo(info); mSpiedPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA); @@ -169,13 +203,28 @@ public class PipTaskOrganizerTest extends ShellTestCase { private static ActivityManager.RunningTaskInfo createTaskInfo( ComponentName componentName, PictureInPictureParams params) { + return createTaskInfo(componentName, params, null /* minSize */); + } + + private static ActivityManager.RunningTaskInfo createTaskInfo( + ComponentName componentName, PictureInPictureParams params, Size minSize) { final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); info.token = mock(WindowContainerToken.class); info.pictureInPictureParams = params; info.topActivity = componentName; + if (minSize != null) { + info.topActivityInfo = createActivityInfo(minSize); + } return info; } + private static ActivityInfo createActivityInfo(Size minSize) { + final ActivityInfo activityInfo = new ActivityInfo(); + activityInfo.windowLayout = new ActivityInfo.WindowLayout( + 0, 0, 0, 0, 0, minSize.getWidth(), minSize.getHeight()); + return activityInfo; + } + private static PictureInPictureParams createPipParams(Rational aspectRatio) { return new PictureInPictureParams.Builder() .setAspectRatio(aspectRatio)