Do not lose window grab when approaching the edge of the screen
Currently when a freeform window is being dragged and the pointer gets
too close to the screen (stack) edge, the dragging completes. This was
done in ag/770762 to to prevent a freeform window from being dragged
fully under a docked stack.
This CL provides a different solution to this problem: while dragging a window
make sure that a big enough portion of its caption bar is still visible.
Bug: 26055288
Change-Id: I5873bb1203a0e91ae1436b3e87220affb77194ff
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index b5bde403..0ab316c 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -419,44 +419,54 @@
return false;
}
- // This is a moving operation.
+ // This is a moving or scrolling operation.
mTask.mStack.getDimBounds(mTmpRect);
- // If this is a non-resizeable task put into side-by-side mode, we are
- // handling a two-finger scrolling action. No need to shrink the bounds.
- if (!mTask.isDockedInEffect()) {
- mTmpRect.inset(mMinVisibleWidth, mMinVisibleHeight);
- }
-
boolean dragEnded = false;
- final int nX = (int) x;
- final int nY = (int) y;
+ int nX = (int) x;
+ int nY = (int) y;
if (!mTmpRect.contains(nX, nY)) {
- // We end the moving operation if position is outside the stack bounds.
- // In this case we need to clamp the position to stack bounds and calculate
- // the final window drag bounds.
- x = Math.min(Math.max(x, mTmpRect.left), mTmpRect.right);
- y = Math.min(Math.max(y, mTmpRect.top), mTmpRect.bottom);
- dragEnded = true;
+ if (mTask.isDockedInEffect()) {
+ // We end the scrolling operation if position is outside the stack bounds.
+ dragEnded = true;
+ } else {
+ // For a moving operation we allow the pointer to go out of the stack bounds, but
+ // use the clamped pointer position for the drag bounds computation.
+ nX = Math.min(Math.max(nX, mTmpRect.left), mTmpRect.right);
+ nY = Math.min(Math.max(nY, mTmpRect.top), mTmpRect.bottom);
+ }
}
- updateWindowDragBounds(nX, nY);
+ updateWindowDragBounds(nX, nY, mTmpRect);
updateDimLayerVisibility(nX);
return dragEnded;
}
- private void updateWindowDragBounds(int x, int y) {
+ private void updateWindowDragBounds(int x, int y, Rect stackBounds) {
+ final int offsetX = Math.round(x - mStartDragX);
+ final int offsetY = Math.round(y - mStartDragY);
mWindowDragBounds.set(mWindowOriginalBounds);
if (mTask.isDockedInEffect()) {
// Offset the bounds without clamp, the bounds will be shifted later
// by window manager before applying the scrolling.
if (mService.mCurConfiguration.orientation == ORIENTATION_LANDSCAPE) {
- mWindowDragBounds.offset(Math.round(x - mStartDragX), 0);
+ mWindowDragBounds.offset(offsetX, 0);
} else {
- mWindowDragBounds.offset(0, Math.round(y - mStartDragY));
+ mWindowDragBounds.offset(0, offsetY);
}
} else {
- mWindowDragBounds.offset(Math.round(x - mStartDragX), Math.round(y - mStartDragY));
+ // Horizontally, at least mMinVisibleWidth pixels of the window should remain visible.
+ final int maxLeft = stackBounds.right - mMinVisibleWidth;
+ final int minLeft = stackBounds.left + mMinVisibleWidth - mWindowOriginalBounds.width();
+
+ // Vertically, the top mMinVisibleHeight of the window should remain visible.
+ // (This assumes that the window caption bar is at the top of the window).
+ final int minTop = stackBounds.top;
+ final int maxTop = stackBounds.bottom - mMinVisibleHeight;
+
+ mWindowDragBounds.offsetTo(
+ Math.min(Math.max(mWindowOriginalBounds.left + offsetX, minLeft), maxLeft),
+ Math.min(Math.max(mWindowOriginalBounds.top + offsetY, minTop), maxTop));
}
if (DEBUG_TASK_POSITIONING) Slog.d(TAG,
"updateWindowDragBounds: " + mWindowDragBounds);