summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/policy/PipSnapAlgorithm.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java19
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java123
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java11
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);
}