From dd1d40ef0d62b10e0774123ba5e0f3b27708fa50 Mon Sep 17 00:00:00 2001 From: Ben Lin Date: Thu, 14 Jan 2021 18:10:37 -0800 Subject: [PATCH] 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 --- .../android/wm/shell/pip/PipBoundsState.java | 21 +++++ .../pip/phone/PipPinchResizingAlgorithm.java | 8 +- .../wm/shell/pip/phone/PipTouchHandler.java | 77 +++++++++++++++---- 3 files changed, 88 insertions(+), 18 deletions(-) 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 d0d9b2623ab51..9595b5a3b0a9c 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 @@ -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() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java index 28cbe35745a93..721f621764da5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java @@ -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))); } } 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 6b6bf5e4a7761..6a26eab730b4a 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 @@ -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