diff options
4 files changed, 127 insertions, 19 deletions
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 30124a5363a4..616d447247de 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 @@ -745,6 +745,15 @@ public class PipController implements PipTransitionController.PipTransitionCallb // Directly move PiP to its final destination bounds without animation. mPipTaskOrganizer.scheduleFinishResizePip(postChangeBounds); } + + // if the pip window size is beyond allowed bounds user resize to normal bounds + if (mPipBoundsState.getBounds().width() < mPipBoundsState.getMinSize().x + || mPipBoundsState.getBounds().width() > mPipBoundsState.getMaxSize().x + || mPipBoundsState.getBounds().height() < mPipBoundsState.getMinSize().y + || mPipBoundsState.getBounds().height() > mPipBoundsState.getMaxSize().y) { + mTouchHandler.userResizeTo(mPipBoundsState.getNormalBounds(), snapFraction); + } + } else { updateDisplayLayout.run(); } 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 89d85e4b292d..41ff0b35a035 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 @@ -96,6 +96,7 @@ public class PipResizeGestureHandler { private final Rect mDisplayBounds = new Rect(); private final Function<Rect, Rect> mMovementBoundsSupplier; private final Runnable mUpdateMovementBoundsRunnable; + private final Consumer<Rect> mUpdateResizeBoundsCallback; private int mDelta; private float mTouchSlop; @@ -137,6 +138,13 @@ public class PipResizeGestureHandler { mPhonePipMenuController = menuActivityController; mPipUiEventLogger = pipUiEventLogger; mPinchResizingAlgorithm = new PipPinchResizingAlgorithm(); + + mUpdateResizeBoundsCallback = (rect) -> { + mUserResizeBounds.set(rect); + mMotionHelper.synchronizePinnedStackBounds(); + mUpdateMovementBoundsRunnable.run(); + resetState(); + }; } public void init() { @@ -508,15 +516,50 @@ public class PipResizeGestureHandler { } } + private void snapToMovementBoundsEdge(Rect bounds, Rect movementBounds) { + final int leftEdge = bounds.left; + + + final int fromLeft = Math.abs(leftEdge - movementBounds.left); + final int fromRight = Math.abs(movementBounds.right - leftEdge); + + // The PIP will be snapped to either the right or left edge, so calculate which one + // is closest to the current position. + final int newLeft = fromLeft < fromRight + ? movementBounds.left : movementBounds.right; + + bounds.offsetTo(newLeft, mLastResizeBounds.top); + } + + /** + * Resizes the pip window and updates user-resized bounds. + * + * @param bounds target bounds to resize to + * @param snapFraction snap fraction to apply after resizing + */ + void userResizeTo(Rect bounds, float snapFraction) { + Rect finalBounds = new Rect(bounds); + + // get the current movement bounds + final Rect movementBounds = mPipBoundsAlgorithm.getMovementBounds(finalBounds); + + // snap the target bounds to the either left or right edge, by choosing the closer one + snapToMovementBoundsEdge(finalBounds, movementBounds); + + // apply the requested snap fraction onto the target bounds + mPipBoundsAlgorithm.applySnapFraction(finalBounds, snapFraction); + + // resize from current bounds to target bounds without animation + mPipTaskOrganizer.scheduleUserResizePip(mPipBoundsState.getBounds(), finalBounds, null); + // set the flag that pip has been resized + mPipBoundsState.setHasUserResizedPip(true); + + // finish the resize operation and update the state of the bounds + mPipTaskOrganizer.scheduleFinishResizePip(finalBounds, mUpdateResizeBoundsCallback); + } + private void finishResize() { if (!mLastResizeBounds.isEmpty()) { - final Consumer<Rect> callback = (rect) -> { - mUserResizeBounds.set(mLastResizeBounds); - mMotionHelper.synchronizePinnedStackBounds(); - mUpdateMovementBoundsRunnable.run(); - resetState(); - }; - // Pinch-to-resize needs to re-calculate snap fraction and animate to the snapped // position correctly. Drag-resize does not need to move, so just finalize resize. if (mOngoingPinchToResize) { @@ -526,24 +569,23 @@ public class PipResizeGestureHandler { || mLastResizeBounds.height() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.y) { resizeRectAboutCenter(mLastResizeBounds, mMaxSize.x, mMaxSize.y); } - final int leftEdge = mLastResizeBounds.left; - final Rect movementBounds = - mPipBoundsAlgorithm.getMovementBounds(mLastResizeBounds); - final int fromLeft = Math.abs(leftEdge - movementBounds.left); - final int fromRight = Math.abs(movementBounds.right - leftEdge); - // The PIP will be snapped to either the right or left edge, so calculate which one - // is closest to the current position. - final int newLeft = fromLeft < fromRight - ? movementBounds.left : movementBounds.right; - mLastResizeBounds.offsetTo(newLeft, mLastResizeBounds.top); + + // get the current movement bounds + final Rect movementBounds = mPipBoundsAlgorithm + .getMovementBounds(mLastResizeBounds); + + // snap mLastResizeBounds to the correct edge based on movement bounds + snapToMovementBoundsEdge(mLastResizeBounds, movementBounds); + final float snapFraction = mPipBoundsAlgorithm.getSnapFraction( mLastResizeBounds, movementBounds); mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction); mPipTaskOrganizer.scheduleAnimateResizePip(startBounds, mLastResizeBounds, - PINCH_RESIZE_SNAP_DURATION, mAngle, callback); + PINCH_RESIZE_SNAP_DURATION, mAngle, mUpdateResizeBoundsCallback); } else { mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds, - PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE, callback); + PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE, + mUpdateResizeBoundsCallback); } final float magnetRadiusPercent = (float) mLastResizeBounds.width() / mMinSize.x / 2.f; mPipDismissTargetHandler 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 1f3f31e025a0..975d4bba276e 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 @@ -825,6 +825,16 @@ public class PipTouchHandler { } /** + * Resizes the pip window and updates user resized bounds + * + * @param bounds target bounds to resize to + * @param snapFraction snap fraction to apply after resizing + */ + void userResizeTo(Rect bounds, float snapFraction) { + mPipResizeGestureHandler.userResizeTo(bounds, snapFraction); + } + + /** * Gesture controlling normal movement of the PIP. */ private class DefaultPipTouchGesture extends PipTouchGesture { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java index dba037db72eb..3bd2ae76ebfd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java @@ -16,6 +16,7 @@ package com.android.wm.shell.pip.phone; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -55,6 +56,7 @@ import org.mockito.MockitoAnnotations; @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) public class PipResizeGestureHandlerTest extends ShellTestCase { + private static final float DEFAULT_SNAP_FRACTION = 2.0f; private static final int STEP_SIZE = 40; private final MotionEvent.PointerProperties[] mPp = new MotionEvent.PointerProperties[2]; @@ -196,6 +198,51 @@ public class PipResizeGestureHandlerTest extends ShellTestCase { < mPipBoundsState.getBounds().width()); } + @Test + public void testUserResizeTo() { + // resizing the bounds to normal bounds at first + mPipResizeGestureHandler.userResizeTo(mPipBoundsState.getNormalBounds(), + DEFAULT_SNAP_FRACTION); + + assertPipBoundsUserResizedTo(mPipBoundsState.getNormalBounds()); + + verify(mPipTaskOrganizer, times(1)) + .scheduleUserResizePip(any(), any(), any()); + + verify(mPipTaskOrganizer, times(1)) + .scheduleFinishResizePip(any(), any()); + + // bounds with max size + final Rect maxBounds = new Rect(0, 0, mPipBoundsState.getMaxSize().x, + mPipBoundsState.getMaxSize().y); + + // resizing the bounds to maximum bounds the second time + mPipResizeGestureHandler.userResizeTo(maxBounds, DEFAULT_SNAP_FRACTION); + + assertPipBoundsUserResizedTo(maxBounds); + + // another call to scheduleUserResizePip() and scheduleFinishResizePip() makes + // the total number of invocations 2 for each method + verify(mPipTaskOrganizer, times(2)) + .scheduleUserResizePip(any(), any(), any()); + + verify(mPipTaskOrganizer, times(2)) + .scheduleFinishResizePip(any(), any()); + } + + private void assertPipBoundsUserResizedTo(Rect bounds) { + // check user-resized bounds + assertEquals(mPipResizeGestureHandler.getUserResizeBounds().width(), bounds.width()); + assertEquals(mPipResizeGestureHandler.getUserResizeBounds().height(), bounds.height()); + + // check if the bounds are the same + assertEquals(mPipBoundsState.getBounds().width(), bounds.width()); + assertEquals(mPipBoundsState.getBounds().height(), bounds.height()); + + // a flag should be set to indicate pip has been resized by the user + assertTrue(mPipBoundsState.hasUserResizedPip()); + } + private MotionEvent obtainMotionEvent(int action, int topLeft, int bottomRight) { final MotionEvent.PointerCoords[] pc = new MotionEvent.PointerCoords[2]; for (int i = 0; i < 2; i++) { |