PiP pinch-to-resize: add double-tap to max/min size.

Per spec, max size would be the biggest possible bounds within the
movement bounds (displayWidth - 2 * insetWidth), and min size would be
40% of the width.

This also fixes the issue of portrait PiP not resizing correctly due to
wrong math being done in the resize algorithm.

Bug: 166478885
Test: Double-tap on PiP
Change-Id: I2e239d23a0e2519c0b482005614a1faddb1f808a
This commit is contained in:
Ben Lin
2021-01-14 18:10:37 -08:00
parent 60a993de14
commit dd1d40ef0d
3 changed files with 88 additions and 18 deletions

View File

@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Size;
import android.view.DisplayInfo;
@@ -59,6 +60,8 @@ public final class PipBoundsState {
private final @NonNull Rect mExpandedBounds = new Rect();
private final @NonNull Rect mNormalMovementBounds = new Rect();
private final @NonNull Rect mExpandedMovementBounds = new Rect();
private final Point mMaxSize = new Point();
private final Point mMinSize = new Point();
private final @NonNull Context mContext;
private float mAspectRatio;
private int mStashedState = STASH_TYPE_NONE;
@@ -151,6 +154,24 @@ public final class PipBoundsState {
mExpandedMovementBounds.set(bounds);
}
/** Sets the max possible size for resize. */
public void setMaxSize(int width, int height) {
mMaxSize.set(width, height);
}
/** Sets the min possible size for resize. */
public void setMinSize(int width, int height) {
mMinSize.set(width, height);
}
public Point getMaxSize() {
return mMaxSize;
}
public Point getMinSize() {
return mMinSize;
}
/** Returns the expanded movement bounds. */
@NonNull
public Rect getExpandedMovementBounds() {

View File

@@ -85,21 +85,21 @@ public class PipPinchResizingAlgorithm {
} else {
// Assuming that the width is our target we calculate the height.
width1 = Math.max(minVisibleWidth, Math.min(maxSize.x, width));
height1 = Math.round((float) width1 * aspect);
height1 = Math.round((float) width1 / aspect);
if (height1 < minVisibleHeight) {
// If the resulting height is too small we adjust to the minimal size.
height1 = minVisibleHeight;
width1 = Math.max(minVisibleWidth,
Math.min(maxSize.x, Math.round((float) height1 / aspect)));
Math.min(maxSize.x, Math.round((float) height1 * aspect)));
}
// Assuming that the height is our target we calculate the width.
height2 = Math.max(minVisibleHeight, Math.min(maxSize.y, height));
width2 = Math.round((float) height2 / aspect);
width2 = Math.round((float) height2 * aspect);
if (width2 < minVisibleWidth) {
// If the resulting width is too small we adjust to the minimal size.
width2 = minVisibleWidth;
height2 = Math.max(minVisibleHeight,
Math.min(maxSize.y, Math.round((float) width2 * aspect)));
Math.min(maxSize.y, Math.round((float) width2 / aspect)));
}
}

View File

@@ -359,9 +359,13 @@ public class PipTouchHandler {
mPipBoundsState.getExpandedBounds(), insetBounds, expandedMovementBounds,
bottomOffset);
mPipResizeGestureHandler.updateMinSize(normalBounds.width(), normalBounds.height());
mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getExpandedBounds().width(),
mPipBoundsState.getExpandedBounds().height());
if (mPipResizeGestureHandler.isUsingPinchToZoom()) {
updatePinchResizeSizeConstraints(insetBounds, normalBounds, aspectRatio);
} else {
mPipResizeGestureHandler.updateMinSize(normalBounds.width(), normalBounds.height());
mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getExpandedBounds().width(),
mPipBoundsState.getExpandedBounds().height());
}
// The extra offset does not really affect the movement bounds, but are applied based on the
// current state (ime showing, or shelf offset) when we need to actually shift
@@ -430,6 +434,30 @@ public class PipTouchHandler {
}
}
private void updatePinchResizeSizeConstraints(Rect insetBounds, Rect normalBounds,
float aspectRatio) {
final int shorterLength = Math.min(mPipBoundsState.getDisplayBounds().width(),
mPipBoundsState.getDisplayBounds().height());
final int padding = insetBounds.left;
final int minWidth, minHeight, maxWidth, maxHeight;
if (aspectRatio > 1f) {
minWidth = (int) Math.min(normalBounds.width(), shorterLength * 0.4);
minHeight = (int) (minWidth / aspectRatio);
maxWidth = (int) Math.max(normalBounds.width(), shorterLength - 2 * padding);
maxHeight = (int) (maxWidth / aspectRatio);
} else {
minHeight = (int) Math.min(normalBounds.height(), shorterLength * 0.4);
minWidth = (int) (minHeight * aspectRatio);
maxHeight = (int) Math.max(normalBounds.height(), shorterLength - 2 * padding);
maxWidth = (int) (maxHeight * aspectRatio);
}
mPipResizeGestureHandler.updateMinSize(minWidth, minHeight);
mPipResizeGestureHandler.updateMaxSize(maxWidth, maxHeight);
mPipBoundsState.setMaxSize(maxWidth, maxHeight);
mPipBoundsState.setMinSize(minWidth, minHeight);
}
/**
* TODO Add appropriate description
*/
@@ -640,13 +668,36 @@ public class PipTouchHandler {
}
}
private void animateToExpandedState(Runnable callback) {
Rect expandedBounds = new Rect(mPipBoundsState.getExpandedBounds());
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
mPipBoundsState.getMovementBounds(), mPipBoundsState.getExpandedMovementBounds(),
private void animateToMaximizedState(Runnable callback) {
Rect maxMovementBounds = new Rect();
Rect maxBounds = new Rect(0, 0, mPipBoundsState.getMaxSize().x,
mPipBoundsState.getMaxSize().y);
mPipBoundsAlgorithm.getMovementBounds(maxBounds, mInsetBounds, maxMovementBounds,
mIsImeShowing ? mImeHeight : 0);
mSavedSnapFraction = mMotionHelper.animateToExpandedState(maxBounds,
mPipBoundsState.getMovementBounds(), maxMovementBounds,
callback);
}
private void animateToMinimizedState() {
animateToUnexpandedState(new Rect(0, 0, mPipBoundsState.getMinSize().x,
mPipBoundsState.getMinSize().y));
}
private void animateToExpandedState(Runnable callback) {
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
final Rect currentBounds = mPipBoundsState.getBounds();
final Rect expandedBounds = mPipBoundsState.getExpandedBounds();
Rect finalExpandedBounds = new Rect(expandedBounds.width() > expandedBounds.width()
&& expandedBounds.height() > expandedBounds.height()
? currentBounds : expandedBounds);
Rect restoredMovementBounds = new Rect();
mPipBoundsAlgorithm.getMovementBounds(finalExpandedBounds,
mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
mSavedSnapFraction = mMotionHelper.animateToExpandedState(finalExpandedBounds,
mPipBoundsState.getMovementBounds(), restoredMovementBounds, callback);
}
private void animateToUnexpandedState(Rect restoreBounds) {
Rect restoredMovementBounds = new Rect();
mPipBoundsAlgorithm.getMovementBounds(restoreBounds,
@@ -789,17 +840,15 @@ public class PipTouchHandler {
// If using pinch to zoom, double-tap functions as resizing between max/min size
if (mPipResizeGestureHandler.isUsingPinchToZoom()) {
final boolean toExpand = mPipBoundsState.getBounds().width()
< mPipBoundsState.getExpandedBounds().width()
< mPipBoundsState.getMaxSize().x
&& mPipBoundsState.getBounds().height()
< mPipBoundsState.getExpandedBounds().height();
mPipResizeGestureHandler.setUserResizeBounds(toExpand
? mPipBoundsState.getExpandedBounds()
: mPipBoundsState.getNormalBounds());
< mPipBoundsState.getMaxSize().y;
if (toExpand) {
animateToExpandedState(null);
animateToMaximizedState(null);
} else {
animateToUnexpandedState(mPipBoundsState.getNormalBounds());
animateToMinimizedState();
}
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
} else {
// Expand to fullscreen if this is a double tap
// the PiP should be frozen until the transition ends