Merge "User-resize pip to normal bounds when (un)folding" into tm-qpr-dev

This commit is contained in:
Ikram Gabiyev
2022-10-13 21:03:24 +00:00
committed by Android (Google) Code Review
4 changed files with 127 additions and 19 deletions

View File

@@ -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();
}

View File

@@ -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

View File

@@ -824,6 +824,16 @@ public class PipTouchHandler {
return mPipResizeGestureHandler.getUserResizeBounds();
}
/**
* 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.
*/

View File

@@ -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++) {