diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java index 1e2a53ba97e46..62d506f781579 100644 --- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java @@ -41,8 +41,12 @@ public class PipSnapAlgorithm { // Allows snapping to anywhere along the edge of the screen private static final int SNAP_MODE_EDGE = 2; + // The friction multiplier to control how slippery the PIP is when flung private static final float SCROLL_FRICTION_MULTIPLIER = 8f; + // The fraction of the stack width to show when minimized + private static final float MINIMIZED_VISIBLE_FRACTION = 0.25f; + private final Context mContext; private final ArrayList mSnapGravities = new ArrayList<>(); @@ -121,6 +125,18 @@ public class PipSnapAlgorithm { return newBounds; } + /** + * Applies the offset to the {@param stackBounds} to adjust it to a minimized state. + */ + public void applyMinimizedOffset(Rect stackBounds, Rect movementBounds, Point displaySize) { + int visibleWidth = (int) (MINIMIZED_VISIBLE_FRACTION * stackBounds.width()); + if (stackBounds.left <= movementBounds.centerX()) { + stackBounds.offsetTo(-stackBounds.width() + visibleWidth, stackBounds.top); + } else { + stackBounds.offsetTo(displaySize.x - visibleWidth, stackBounds.top); + } + } + /** * @return returns a fraction that describes where along the {@param movementBounds} the * {@param stackBounds} are. If the {@param stackBounds} are not currently on the diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 7005afe5b5f6a..996fd55f69bda 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2492,11 +2492,11 @@ - 10x10 + 8x8 - 216x135 + 192x120 diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index b24d19958f18e..c6dde4623ef39 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -71,8 +71,6 @@ public class PipTouchHandler implements TunerService.Tunable { private static final int EXPAND_STACK_DURATION = 225; private static final int MINIMIZE_STACK_MAX_DURATION = 200; - // The fraction of the stack width to show when minimized - private static final float MINIMIZED_VISIBLE_FRACTION = 0.25f; // The fraction of the stack width that the user has to drag offscreen to minimize the PIP private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.15f; // The fraction of the stack width that the user has to move when flinging to dismiss the PIP @@ -396,6 +394,8 @@ public class PipTouchHandler implements TunerService.Tunable { * Flings the minimized PIP to the closest minimized snap target. */ private void flingToMinimizedSnapTarget(float velocityY) { + // We currently only allow flinging the minimized stack up and down, so just lock the + // movement bounds to the current stack bounds horizontally Rect movementBounds = new Rect(mPinnedStackBounds.left, mBoundedPinnedStackBounds.top, mPinnedStackBounds.left, mBoundedPinnedStackBounds.bottom); Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mPinnedStackBounds, @@ -414,16 +414,11 @@ public class PipTouchHandler implements TunerService.Tunable { * Animates the PIP to the minimized state, slightly offscreen. */ private void animateToClosestMinimizedTarget() { - Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds, - mPinnedStackBounds); Point displaySize = new Point(); mContext.getDisplay().getRealSize(displaySize); - int visibleWidth = (int) (MINIMIZED_VISIBLE_FRACTION * mPinnedStackBounds.width()); - if (mPinnedStackBounds.left < 0) { - toBounds.offsetTo(-toBounds.width() + visibleWidth, toBounds.top); - } else if (mPinnedStackBounds.right > displaySize.x) { - toBounds.offsetTo(displaySize.x - visibleWidth, toBounds.top); - } + Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds, + mPinnedStackBounds); + mSnapAlgorithm.applyMinimizedOffset(toBounds, mBoundedPinnedStackBounds, displaySize); mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds, toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, mUpdatePinnedStackBoundsListener); @@ -635,7 +630,7 @@ public class PipTouchHandler implements TunerService.Tunable { setMinimizedState(false); } - if (isDraggingOffscreen) { + if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) { // Move the pinned stack, but ignore the vertical movement float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x; mTmpBounds.set(mPinnedStackBounds); @@ -685,7 +680,7 @@ public class PipTouchHandler implements TunerService.Tunable { setMinimizedState(false); } - if (isDraggingOffscreen) { + if (touchState.allowDraggingOffscreen() && isDraggingOffscreen) { // Move the pinned stack, but ignore the vertical movement float left = mPinnedStackBounds.left + touchState.getLastTouchDelta().x; mTmpBounds.set(mPinnedStackBounds); @@ -769,6 +764,12 @@ public class PipTouchHandler implements TunerService.Tunable { private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() { @Override boolean onMove(PipTouchState touchState) { + if (touchState.startedDragging()) { + // For now, once the user has started a drag that the other gestures have not + // intercepted, disallow those gestures from intercepting again to drag offscreen + touchState.setDisallowDraggingOffscreen(); + } + if (touchState.isDragging()) { // Move the pinned stack freely PointF lastDelta = touchState.getLastTouchDelta(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java index 80af5a6c02680..17d9864e4d25c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java @@ -40,6 +40,7 @@ public class PipTouchState { private final PointF mVelocity = new PointF(); private boolean mIsDragging = false; private boolean mStartedDragging = false; + private boolean mAllowDraggingOffscreen = false; private int mActivePointerId; public PipTouchState(ViewConfiguration viewConfig) { @@ -59,6 +60,7 @@ public class PipTouchState { mDownTouch.set(mLastTouch); mIsDragging = false; mStartedDragging = false; + mAllowDraggingOffscreen = true; break; } case MotionEvent.ACTION_MOVE: { @@ -159,6 +161,20 @@ public class PipTouchState { return mStartedDragging; } + /** + * Disallows dragging offscreen for the duration of the current gesture. + */ + public void setDisallowDraggingOffscreen() { + mAllowDraggingOffscreen = false; + } + + /** + * @return whether dragging offscreen is allowed during this gesture. + */ + public boolean allowDraggingOffscreen() { + return mAllowDraggingOffscreen; + } + private void initOrResetVelocityTracker() { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index c711b39aabaf9..01a50b7ef340d 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -256,6 +256,12 @@ class PinnedStackController { false /* adjustForIme */); mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, snapFraction); + if (mIsMinimized) { + final Point displaySize = new Point(mDisplayInfo.logicalWidth, + mDisplayInfo.logicalHeight); + mSnapAlgorithm.applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds, + displaySize); + } } return postChangeStackBounds; } @@ -285,7 +291,12 @@ class PinnedStackController { final Rect toBounds = new Rect(stackBounds); if (adjustedForIme) { // IME visible - toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top)); + if (stackBounds.top == prevMovementBounds.bottom) { + // If the PIP is resting on top of the IME, then adjust it with the hiding IME + toBounds.offsetTo(toBounds.left, movementBounds.bottom); + } else { + toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top)); + } } else { // IME hidden if (stackBounds.top == prevMovementBounds.bottom) {