diff options
4 files changed, 167 insertions, 92 deletions
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java index 51804b0ad57f..45b7b0183fd8 100644 --- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java @@ -53,7 +53,14 @@ public class PipSnapAlgorithm { public PipSnapAlgorithm(Context context) { mContext = context; - mOrientation = context.getResources().getConfiguration().orientation; + onConfigurationChanged(); + } + + /** + * Updates the snap algorithm when the configuration changes. + */ + public void onConfigurationChanged() { + mOrientation = mContext.getResources().getConfiguration().orientation; calculateSnapTargets(); } @@ -90,19 +97,7 @@ public class PipSnapAlgorithm { final Rect newBounds = new Rect(stackBounds); if (mSnapMode == SNAP_MODE_EDGE) { // Find the closest edge to the given stack bounds and snap to it - final int fromLeft = stackBounds.left - movementBounds.left; - final int fromTop = stackBounds.top - movementBounds.top; - final int fromRight = movementBounds.right - stackBounds.left; - final int fromBottom = movementBounds.bottom - stackBounds.top; - if (fromLeft <= fromTop && fromLeft <= fromRight && fromLeft <= fromBottom) { - newBounds.offset(-fromLeft, 0); - } else if (fromTop <= fromLeft && fromTop <= fromRight && fromTop <= fromBottom) { - newBounds.offset(0, -fromTop); - } else if (fromRight < fromLeft && fromRight < fromTop && fromRight < fromBottom) { - newBounds.offset(fromRight, 0); - } else { - newBounds.offset(0, fromBottom); - } + snapRectToClosestEdge(stackBounds, movementBounds, newBounds); } else { // Find the closest snap point final Rect tmpBounds = new Rect(); @@ -119,6 +114,68 @@ public class PipSnapAlgorithm { } /** + * @return returns a fraction that describes where along the {@param movementBounds} the + * {@param stackBounds} are. If the {@param stackBounds} are not currently on the + * {@param movementBounds} exactly, then they will be snapped to the movement bounds. + * + * The fraction is defined in a clockwise fashion against the {@param movementBounds}: + * + * 0 1 + * 4 +---+ 1 + * | | + * 3 +---+ 2 + * 3 2 + */ + public float getSnapFraction(Rect stackBounds, Rect movementBounds) { + final Rect tmpBounds = new Rect(); + snapRectToClosestEdge(stackBounds, movementBounds, tmpBounds); + final float widthFraction = (float) (tmpBounds.left - movementBounds.left) / + movementBounds.width(); + final float heightFraction = (float) (tmpBounds.top - movementBounds.top) / + movementBounds.height(); + if (tmpBounds.top == movementBounds.top) { + return widthFraction; + } else if (tmpBounds.left == movementBounds.right) { + return 1f + heightFraction; + } else if (tmpBounds.top == movementBounds.bottom) { + return 2f + (1f - widthFraction); + } else { + return 3f + (1f - heightFraction); + } + } + + /** + * Moves the {@param stackBounds} along the {@param movementBounds} to the given snap fraction. + * See {@link #getSnapFraction(Rect, Rect)}. + * + * The fraction is define in a clockwise fashion against the {@param movementBounds}: + * + * 0 1 + * 4 +---+ 1 + * | | + * 3 +---+ 2 + * 3 2 + */ + public void applySnapFraction(Rect stackBounds, Rect movementBounds, float snapFraction) { + if (snapFraction < 1f) { + int offset = movementBounds.left + (int) (snapFraction * movementBounds.width()); + stackBounds.offsetTo(offset, movementBounds.top); + } else if (snapFraction < 2f) { + snapFraction -= 1f; + int offset = movementBounds.top + (int) (snapFraction * movementBounds.height()); + stackBounds.offsetTo(movementBounds.right, offset); + } else if (snapFraction < 3f) { + snapFraction -= 2f; + int offset = movementBounds.left + (int) ((1f - snapFraction) * movementBounds.width()); + stackBounds.offsetTo(offset, movementBounds.bottom); + } else { + snapFraction -= 3f; + int offset = movementBounds.top + (int) ((1f - snapFraction) * movementBounds.height()); + stackBounds.offsetTo(movementBounds.left, offset); + } + } + + /** * @return the closest point in {@param points} to the given {@param x} and {@param y}. */ private Point findClosestPoint(int x, int y, Point[] points) { @@ -135,6 +192,27 @@ public class PipSnapAlgorithm { } /** + * Snaps the {@param stackBounds} to the closest edge of the {@param movementBounds} and writes + * the new bounds out to {@param boundsOut}. + */ + private void snapRectToClosestEdge(Rect stackBounds, Rect movementBounds, Rect boundsOut) { + final int fromLeft = Math.abs(stackBounds.left - movementBounds.left); + final int fromTop = Math.abs(stackBounds.top - movementBounds.top); + final int fromRight = Math.abs(movementBounds.right - stackBounds.left); + final int fromBottom = Math.abs(movementBounds.bottom - stackBounds.top); + boundsOut.set(stackBounds); + if (fromLeft <= fromTop && fromLeft <= fromRight && fromLeft <= fromBottom) { + boundsOut.offsetTo(movementBounds.left, stackBounds.top); + } else if (fromTop <= fromLeft && fromTop <= fromRight && fromTop <= fromBottom) { + boundsOut.offsetTo(stackBounds.left, movementBounds.top); + } else if (fromRight < fromLeft && fromRight < fromTop && fromRight < fromBottom) { + boundsOut.offsetTo(movementBounds.right, stackBounds.top); + } else { + boundsOut.offsetTo(stackBounds.left, movementBounds.bottom); + } + } + + /** * @return the distance between point {@param p} and the given {@param x} and {@param y}. */ private float distanceToPoint(Point p, int x, int y) { 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 7f2d415dddc1..e32022abdf38 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -76,7 +76,7 @@ public class PipTouchHandler implements TunerService.Tunable { private final PipInputEventReceiver mInputEventReceiver; private PipDismissViewController mDismissViewController; - private PipSnapAlgorithm mSnapAlgorithm; + private final PipSnapAlgorithm mSnapAlgorithm; private PipMotionHelper mMotionHelper; private boolean mEnableSwipeToDismiss = true; @@ -163,6 +163,7 @@ public class PipTouchHandler implements TunerService.Tunable { if (mEnableDragToDismiss) { mDismissViewController = new PipDismissViewController(context); } + mSnapAlgorithm = new PipSnapAlgorithm(mContext); mFlingAnimationUtils = new FlingAnimationUtils(context, 2f); mMotionHelper = new PipMotionHelper(BackgroundThread.getHandler()); @@ -187,7 +188,8 @@ public class PipTouchHandler implements TunerService.Tunable { } public void onConfigurationChanged() { - updateBoundedPinnedStackBounds(); + mSnapAlgorithm.onConfigurationChanged(); + updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */); } private void handleTouchEvent(MotionEvent ev) { @@ -203,7 +205,7 @@ public class PipTouchHandler implements TunerService.Tunable { mPinnedStackBoundsAnimator.cancel(); } - updateBoundedPinnedStackBounds(); + updateBoundedPinnedStackBounds(true /* updatePinnedStackBounds */); initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); mActivePointerId = ev.getPointerId(0); @@ -299,6 +301,10 @@ public class PipTouchHandler implements TunerService.Tunable { float velocityY = mVelocityTracker.getYVelocity(); float velocity = PointF.length(velocityX, velocityY); + // Update the movement bounds again if the state has changed since the user started + // dragging (ie. when the IME shows) + updateBoundedPinnedStackBounds(false /* updatePinnedStackBounds */); + if (mIsSwipingToDismiss) { if (Math.abs(velocityX) > mFlingAnimationUtils.getMinVelocityPxPerSecond()) { flingToDismiss(velocityX); @@ -462,14 +468,15 @@ public class PipTouchHandler implements TunerService.Tunable { /** * Updates the movement bounds of the pinned stack. */ - private void updateBoundedPinnedStackBounds() { + private void updateBoundedPinnedStackBounds(boolean updatePinnedStackBounds) { try { StackInfo info = mActivityManager.getStackInfo(PINNED_STACK_ID); if (info != null) { - mPinnedStackBounds.set(info.bounds); + if (updatePinnedStackBounds) { + mPinnedStackBounds.set(info.bounds); + } mBoundedPinnedStackBounds.set(mWindowManager.getPictureInPictureMovementBounds( info.displayId)); - mSnapAlgorithm = new PipSnapAlgorithm(mContext); } } catch (RemoteException e) { Log.e(TAG, "Could not fetch PIP movement bounds.", e); diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index a488d52144a0..e9e47846728f 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -34,7 +34,7 @@ import android.util.Log; import android.util.Size; import android.util.Slog; import android.util.TypedValue; -import android.view.Display; +import android.view.DisplayInfo; import android.view.Gravity; import android.view.IPinnedStackController; import android.view.IPinnedStackListener; @@ -68,9 +68,11 @@ class PinnedStackController { private boolean mInInteractiveMode; private boolean mIsImeShowing; private int mImeHeight; - private final Rect mPreImeShowingBounds = new Rect(); private ValueAnimator mBoundsAnimator = null; + // Used to calculate stack bounds across rotations + private final DisplayInfo mDisplayInfo = new DisplayInfo(); + // The size and position information that describes where the pinned stack will go by default. private int mDefaultStackGravity; private Size mDefaultStackSize; @@ -93,7 +95,6 @@ class PinnedStackController { mBoundsAnimator.cancel(); } mInInteractiveMode = inInteractiveMode; - mPreImeShowingBounds.setEmpty(); }); } } @@ -116,6 +117,7 @@ class PinnedStackController { mDisplayContent = displayContent; mSnapAlgorithm = new PipSnapAlgorithm(service.mContext); mMotionHelper = new PipMotionHelper(BackgroundThread.getHandler()); + mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo()); reloadResources(); } @@ -159,12 +161,8 @@ class PinnedStackController { * @return the default bounds to show the PIP when there is no active PIP. */ Rect getDefaultBounds() { - final Display display = mDisplayContent.getDisplay(); final Rect insetBounds = new Rect(); - final Point displaySize = new Point(); - display.getRealSize(displaySize); - mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mTmpInsets); - getInsetBounds(displaySize, mTmpInsets, insetBounds); + getInsetBounds(insetBounds); final Rect defaultBounds = new Rect(); Gravity.apply(mDefaultStackGravity, mDefaultStackSize.getWidth(), @@ -177,12 +175,16 @@ class PinnedStackController { * controller. */ Rect getMovementBounds(Rect stackBounds) { - final Display display = mDisplayContent.getDisplay(); + return getMovementBounds(stackBounds, true /* adjustForIme */); + } + + /** + * @return the movement bounds for the given {@param stackBounds} and the current state of the + * controller. + */ + Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) { final Rect movementBounds = new Rect(); - final Point displaySize = new Point(); - display.getRealSize(displaySize); - mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mTmpInsets); - getInsetBounds(displaySize, mTmpInsets, movementBounds); + getInsetBounds(movementBounds); // Adjust the right/bottom to ensure the stack bounds never goes offscreen movementBounds.right = Math.max(movementBounds.left, movementBounds.right - @@ -190,30 +192,34 @@ class PinnedStackController { movementBounds.bottom = Math.max(movementBounds.top, movementBounds.bottom - stackBounds.height()); - // Adjust the top if the ime is open - if (mIsImeShowing) { - movementBounds.bottom -= mImeHeight; + // Apply the movement bounds adjustments based on the current state + if (adjustForIme) { + if (mIsImeShowing) { + movementBounds.bottom -= mImeHeight; + } } - return movementBounds; } /** - * @return the PIP bounds given it's bounds pre-rotation, and post-rotation (with as applied - * by the display content, which currently transposes the dimensions but keeps each stack in - * the same physical space on the device). + * @return the repositioned PIP bounds given it's pre-change bounds, and the new display info. */ - Rect getPostRotationBounds(Rect preRotationStackBounds, Rect postRotationStackBounds) { - // Keep the pinned stack in the same aspect ratio as in the old orientation, but - // move it into the position in the rotated space, and snap to the closest space - // in the new orientation. - final Rect movementBounds = getMovementBounds(preRotationStackBounds); - final int stackWidth = preRotationStackBounds.width(); - final int stackHeight = preRotationStackBounds.height(); - final int left = postRotationStackBounds.centerX() - (stackWidth / 2); - final int top = postRotationStackBounds.centerY() - (stackHeight / 2); - final Rect postRotBounds = new Rect(left, top, left + stackWidth, top + stackHeight); - return mSnapAlgorithm.findClosestSnapBounds(movementBounds, postRotBounds); + Rect onDisplayChanged(Rect preChangeStackBounds, DisplayInfo displayInfo) { + final Rect postChangeStackBounds = new Rect(preChangeStackBounds); + if (!mDisplayInfo.equals(displayInfo)) { + // Calculate the snap fraction of the current stack along the old movement bounds, and + // then update the stack bounds to the same fraction along the rotated movement bounds. + final Rect preChangeMovementBounds = getMovementBounds(preChangeStackBounds); + final float snapFraction = mSnapAlgorithm.getSnapFraction(preChangeStackBounds, + preChangeMovementBounds); + mDisplayInfo.copyFrom(displayInfo); + + final Rect postChangeMovementBounds = getMovementBounds(preChangeStackBounds, + false /* adjustForIme */); + mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, + snapFraction); + } + return postChangeStackBounds; } /** @@ -228,7 +234,6 @@ class PinnedStackController { final Rect stackBounds = new Rect(); mService.getStackBounds(PINNED_STACK_ID, stackBounds); final Rect prevMovementBounds = getMovementBounds(stackBounds); - final boolean wasAdjustedForIme = mIsImeShowing; mIsImeShowing = adjustedForIme; mImeHeight = imeHeight; if (mInInteractiveMode) { @@ -238,31 +243,17 @@ class PinnedStackController { } else { // Otherwise, we can move the PIP to a sane location to ensure that it does not block // the user from interacting with the IME - Rect toBounds; - if (!wasAdjustedForIme && adjustedForIme) { - // If we are showing the IME, then store the previous bounds - mPreImeShowingBounds.set(stackBounds); - toBounds = adjustBoundsInMovementBounds(stackBounds); - } else if (wasAdjustedForIme && !adjustedForIme) { - if (!mPreImeShowingBounds.isEmpty()) { - // If we are hiding the IME and the user is not interacting with the PIP, restore - // the previous bounds - toBounds = mPreImeShowingBounds; - } else { - if (stackBounds.top == prevMovementBounds.bottom) { - // If the PIP is resting on top of the IME, then adjust it with the hiding - // of the IME - final Rect movementBounds = getMovementBounds(stackBounds); - toBounds = new Rect(stackBounds); - toBounds.offsetTo(toBounds.left, movementBounds.bottom); - } else { - // Otherwise, leave the PIP in place - toBounds = stackBounds; - } - } + final Rect movementBounds = getMovementBounds(stackBounds); + final Rect toBounds = new Rect(stackBounds); + if (adjustedForIme) { + // IME visible + toBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top)); } else { - // Otherwise, the IME bounds have changed so we need to adjust the PIP bounds also - toBounds = adjustBoundsInMovementBounds(stackBounds); + // IME hidden + 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); + } } if (!toBounds.equals(stackBounds)) { if (mBoundsAnimator != null) { @@ -275,16 +266,6 @@ class PinnedStackController { } /** - * @return the adjusted {@param stackBounds} such that they are in the movement bounds. - */ - private Rect adjustBoundsInMovementBounds(Rect stackBounds) { - final Rect movementBounds = getMovementBounds(stackBounds); - final Rect adjustedBounds = new Rect(stackBounds); - adjustedBounds.offset(0, Math.min(0, movementBounds.bottom - stackBounds.top)); - return adjustedBounds; - } - - /** * Sends a broadcast that the PIP movement bounds have changed. */ private void notifyBoundsChanged(boolean adjustedForIme) { @@ -300,10 +281,12 @@ class PinnedStackController { /** * @return the bounds on the screen that the PIP can be visible in. */ - private void getInsetBounds(Point displaySize, Rect insets, Rect outRect) { - outRect.set(insets.left + mScreenEdgeInsets.x, insets.top + mScreenEdgeInsets.y, - displaySize.x - insets.right - mScreenEdgeInsets.x, - displaySize.y - insets.bottom - mScreenEdgeInsets.y); + private void getInsetBounds(Rect outRect) { + mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth, + mDisplayInfo.logicalHeight, mTmpInsets); + outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y, + mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x, + mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y); } /** diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index fff29812548f..60ba025667f6 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -387,8 +387,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); switch (mStackId) { case PINNED_STACK_ID: - mTmpRect2 = mDisplayContent.getPinnedStackController().getPostRotationBounds( - mBounds, mTmpRect2); + mTmpRect2 = mDisplayContent.getPinnedStackController().onDisplayChanged(mBounds, + getDisplayInfo()); break; case DOCKED_STACK_ID: repositionDockedStackAfterRotation(mTmpRect2); @@ -627,6 +627,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(), "animation background stackId=" + mStackId); + final Rect oldBounds = new Rect(mBounds); Rect bounds = null; final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID); if (mStackId == DOCKED_STACK_ID @@ -651,6 +652,12 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye updateDisplayInfo(bounds); + // Update the pinned stack controller after the display info is updated + if (mStackId == PINNED_STACK_ID) { + mDisplayContent.getPinnedStackController().onDisplayChanged(oldBounds, + getDisplayInfo()); + } + super.onDisplayChanged(dc); } |