Merge "Resize tasks from corners when in touch mode" into tm-qpr-dev am: 78b3719017
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20116051 Change-Id: I4535d45f3c5e86832149e265aaa118f46f11c0b8 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import android.os.Handler;
|
||||
import android.view.Choreographer;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import com.android.wm.shell.R;
|
||||
@@ -55,6 +56,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
||||
// Height of button (32dp) + 2 * margin (5dp each)
|
||||
private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42;
|
||||
private static final int RESIZE_HANDLE_IN_DIP = 30;
|
||||
private static final int RESIZE_CORNER_IN_DIP = 44;
|
||||
|
||||
private static final Rect EMPTY_OUTSET = new Rect();
|
||||
private static final Rect RESIZE_HANDLE_OUTSET = new Rect(
|
||||
@@ -145,16 +147,19 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
||||
if (oldDecorationSurface != mDecorationContainerSurface || mDragResizeListener == null) {
|
||||
closeDragResizeListener();
|
||||
mDragResizeListener = new DragResizeInputListener(
|
||||
mContext,
|
||||
mHandler,
|
||||
mChoreographer,
|
||||
mDisplay.getDisplayId(),
|
||||
mDecorationContainerSurface,
|
||||
mDragResizeCallback);
|
||||
mContext,
|
||||
mHandler,
|
||||
mChoreographer,
|
||||
mDisplay.getDisplayId(),
|
||||
mDecorationContainerSurface,
|
||||
mDragResizeCallback);
|
||||
}
|
||||
|
||||
int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop();
|
||||
|
||||
mDragResizeListener.setGeometry(
|
||||
mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP));
|
||||
mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP),
|
||||
(int) (mResult.mDensity * RESIZE_CORNER_IN_DIP), touchSlop);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package com.android.wm.shell.windowdecor;
|
||||
|
||||
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.hardware.input.InputManager;
|
||||
@@ -42,8 +44,11 @@ import com.android.internal.view.BaseIWindow;
|
||||
|
||||
/**
|
||||
* An input event listener registered to InputDispatcher to receive input events on task edges and
|
||||
* convert them to drag resize requests.
|
||||
* and corners. Converts them to drag resize requests.
|
||||
* Task edges are for resizing with a mouse.
|
||||
* Task corners are for resizing with touch input.
|
||||
*/
|
||||
// TODO(b/251270585): investigate how to pass taps in corners to the tasks
|
||||
class DragResizeInputListener implements AutoCloseable {
|
||||
private static final String TAG = "DragResizeInputListener";
|
||||
|
||||
@@ -63,8 +68,15 @@ class DragResizeInputListener implements AutoCloseable {
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private int mResizeHandleThickness;
|
||||
private int mCornerSize;
|
||||
|
||||
private Rect mLeftTopCornerBounds;
|
||||
private Rect mRightTopCornerBounds;
|
||||
private Rect mLeftBottomCornerBounds;
|
||||
private Rect mRightBottomCornerBounds;
|
||||
|
||||
private int mDragPointerId = -1;
|
||||
private int mTouchSlop;
|
||||
|
||||
DragResizeInputListener(
|
||||
Context context,
|
||||
@@ -118,16 +130,23 @@ class DragResizeInputListener implements AutoCloseable {
|
||||
* @param height The height of the drag resize handler in pixels, including resize handle
|
||||
* thickness. That is task height + 2 * resize handle thickness.
|
||||
* @param resizeHandleThickness The thickness of the resize handle in pixels.
|
||||
* @param cornerSize The size of the resize handle centered in each corner.
|
||||
* @param touchSlop The distance in pixels user has to drag with touch for it to register as
|
||||
* a resize action.
|
||||
*/
|
||||
void setGeometry(int width, int height, int resizeHandleThickness) {
|
||||
void setGeometry(int width, int height, int resizeHandleThickness, int cornerSize,
|
||||
int touchSlop) {
|
||||
if (mWidth == width && mHeight == height
|
||||
&& mResizeHandleThickness == resizeHandleThickness) {
|
||||
&& mResizeHandleThickness == resizeHandleThickness
|
||||
&& mCornerSize == cornerSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mResizeHandleThickness = resizeHandleThickness;
|
||||
mCornerSize = cornerSize;
|
||||
mTouchSlop = touchSlop;
|
||||
|
||||
Region touchRegion = new Region();
|
||||
final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness);
|
||||
@@ -146,6 +165,40 @@ class DragResizeInputListener implements AutoCloseable {
|
||||
mWidth, mHeight);
|
||||
touchRegion.union(bottomInputBounds);
|
||||
|
||||
// Set up touch areas in each corner.
|
||||
int cornerRadius = mCornerSize / 2;
|
||||
mLeftTopCornerBounds = new Rect(
|
||||
mResizeHandleThickness - cornerRadius,
|
||||
mResizeHandleThickness - cornerRadius,
|
||||
mResizeHandleThickness + cornerRadius,
|
||||
mResizeHandleThickness + cornerRadius
|
||||
);
|
||||
touchRegion.union(mLeftTopCornerBounds);
|
||||
|
||||
mRightTopCornerBounds = new Rect(
|
||||
mWidth - mResizeHandleThickness - cornerRadius,
|
||||
mResizeHandleThickness - cornerRadius,
|
||||
mWidth - mResizeHandleThickness + cornerRadius,
|
||||
mResizeHandleThickness + cornerRadius
|
||||
);
|
||||
touchRegion.union(mRightTopCornerBounds);
|
||||
|
||||
mLeftBottomCornerBounds = new Rect(
|
||||
mResizeHandleThickness - cornerRadius,
|
||||
mHeight - mResizeHandleThickness - cornerRadius,
|
||||
mResizeHandleThickness + cornerRadius,
|
||||
mHeight - mResizeHandleThickness + cornerRadius
|
||||
);
|
||||
touchRegion.union(mLeftBottomCornerBounds);
|
||||
|
||||
mRightBottomCornerBounds = new Rect(
|
||||
mWidth - mResizeHandleThickness - cornerRadius,
|
||||
mHeight - mResizeHandleThickness - cornerRadius,
|
||||
mWidth - mResizeHandleThickness + cornerRadius,
|
||||
mHeight - mResizeHandleThickness + cornerRadius
|
||||
);
|
||||
touchRegion.union(mRightBottomCornerBounds);
|
||||
|
||||
try {
|
||||
mWindowSession.updateInputChannel(
|
||||
mInputChannel.getToken(),
|
||||
@@ -173,6 +226,9 @@ class DragResizeInputListener implements AutoCloseable {
|
||||
private final Choreographer mChoreographer;
|
||||
private final Runnable mConsumeBatchEventRunnable;
|
||||
private boolean mConsumeBatchEventScheduled;
|
||||
private boolean mShouldHandleEvents;
|
||||
private boolean mDragging;
|
||||
private final PointF mActionDownPoint = new PointF();
|
||||
|
||||
private TaskResizeInputEventReceiver(
|
||||
InputChannel inputChannel, Handler handler, Choreographer choreographer) {
|
||||
@@ -216,41 +272,101 @@ class DragResizeInputListener implements AutoCloseable {
|
||||
}
|
||||
|
||||
MotionEvent e = (MotionEvent) inputEvent;
|
||||
boolean result = false;
|
||||
// Check if this is a touch event vs mouse event.
|
||||
// Touch events are tracked in four corners. Other events are tracked in resize edges.
|
||||
boolean isTouch = (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
|
||||
|
||||
switch (e.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
mDragPointerId = e.getPointerId(0);
|
||||
mCallback.onDragResizeStart(
|
||||
calculateCtrlType(e.getX(0), e.getY(0)), e.getRawX(0), e.getRawY(0));
|
||||
float x = e.getX(0);
|
||||
float y = e.getY(0);
|
||||
if (isTouch) {
|
||||
mShouldHandleEvents = isInCornerBounds(x, y);
|
||||
} else {
|
||||
mShouldHandleEvents = isInResizeHandleBounds(x, y);
|
||||
}
|
||||
if (mShouldHandleEvents) {
|
||||
mDragPointerId = e.getPointerId(0);
|
||||
float rawX = e.getRawX(0);
|
||||
float rawY = e.getRawY(0);
|
||||
mActionDownPoint.set(rawX, rawY);
|
||||
int ctrlType = calculateCtrlType(isTouch, x, y);
|
||||
mCallback.onDragResizeStart(ctrlType, rawX, rawY);
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
if (!mShouldHandleEvents) {
|
||||
break;
|
||||
}
|
||||
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
|
||||
mCallback.onDragResizeMove(
|
||||
e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
|
||||
float rawX = e.getRawX(dragPointerIndex);
|
||||
float rawY = e.getRawY(dragPointerIndex);
|
||||
if (isTouch) {
|
||||
// Check for touch slop for touch events
|
||||
float dx = rawX - mActionDownPoint.x;
|
||||
float dy = rawY - mActionDownPoint.y;
|
||||
if (!mDragging && Math.hypot(dx, dy) > mTouchSlop) {
|
||||
mDragging = true;
|
||||
}
|
||||
} else {
|
||||
// For all other types allow immediate dragging.
|
||||
mDragging = true;
|
||||
}
|
||||
if (mDragging) {
|
||||
mCallback.onDragResizeMove(rawX, rawY);
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL: {
|
||||
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
|
||||
mCallback.onDragResizeEnd(
|
||||
e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
|
||||
if (mDragging) {
|
||||
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
|
||||
mCallback.onDragResizeEnd(
|
||||
e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
|
||||
}
|
||||
mDragging = false;
|
||||
mShouldHandleEvents = false;
|
||||
mActionDownPoint.set(0, 0);
|
||||
mDragPointerId = -1;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_HOVER_ENTER:
|
||||
case MotionEvent.ACTION_HOVER_MOVE: {
|
||||
updateCursorType(e.getXCursorPosition(), e.getYCursorPosition());
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_HOVER_EXIT:
|
||||
mInputManager.setPointerIconType(PointerIcon.TYPE_DEFAULT);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isInCornerBounds(float xf, float yf) {
|
||||
return calculateCornersCtrlType(xf, yf) != 0;
|
||||
}
|
||||
|
||||
private boolean isInResizeHandleBounds(float x, float y) {
|
||||
return calculateResizeHandlesCtrlType(x, y) != 0;
|
||||
}
|
||||
|
||||
@TaskPositioner.CtrlType
|
||||
private int calculateCtrlType(float x, float y) {
|
||||
private int calculateCtrlType(boolean isTouch, float x, float y) {
|
||||
if (isTouch) {
|
||||
return calculateCornersCtrlType(x, y);
|
||||
}
|
||||
return calculateResizeHandlesCtrlType(x, y);
|
||||
}
|
||||
|
||||
@TaskPositioner.CtrlType
|
||||
private int calculateResizeHandlesCtrlType(float x, float y) {
|
||||
int ctrlType = 0;
|
||||
if (x < mResizeHandleThickness) {
|
||||
ctrlType |= TaskPositioner.CTRL_TYPE_LEFT;
|
||||
@@ -267,8 +383,27 @@ class DragResizeInputListener implements AutoCloseable {
|
||||
return ctrlType;
|
||||
}
|
||||
|
||||
@TaskPositioner.CtrlType
|
||||
private int calculateCornersCtrlType(float x, float y) {
|
||||
int xi = (int) x;
|
||||
int yi = (int) y;
|
||||
if (mLeftTopCornerBounds.contains(xi, yi)) {
|
||||
return TaskPositioner.CTRL_TYPE_LEFT | TaskPositioner.CTRL_TYPE_TOP;
|
||||
}
|
||||
if (mLeftBottomCornerBounds.contains(xi, yi)) {
|
||||
return TaskPositioner.CTRL_TYPE_LEFT | TaskPositioner.CTRL_TYPE_BOTTOM;
|
||||
}
|
||||
if (mRightTopCornerBounds.contains(xi, yi)) {
|
||||
return TaskPositioner.CTRL_TYPE_RIGHT | TaskPositioner.CTRL_TYPE_TOP;
|
||||
}
|
||||
if (mRightBottomCornerBounds.contains(xi, yi)) {
|
||||
return TaskPositioner.CTRL_TYPE_RIGHT | TaskPositioner.CTRL_TYPE_BOTTOM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void updateCursorType(float x, float y) {
|
||||
@TaskPositioner.CtrlType int ctrlType = calculateCtrlType(x, y);
|
||||
@TaskPositioner.CtrlType int ctrlType = calculateResizeHandlesCtrlType(x, y);
|
||||
|
||||
int cursorType = PointerIcon.TYPE_DEFAULT;
|
||||
switch (ctrlType) {
|
||||
@@ -292,4 +427,4 @@ class DragResizeInputListener implements AutoCloseable {
|
||||
mInputManager.setPointerIconType(cursorType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,10 @@ import com.android.wm.shell.ShellTaskOrganizer;
|
||||
|
||||
class TaskPositioner implements DragResizeCallback {
|
||||
|
||||
@IntDef({CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
|
||||
@IntDef({CTRL_TYPE_UNDEFINED, CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
|
||||
@interface CtrlType {}
|
||||
|
||||
static final int CTRL_TYPE_UNDEFINED = 0;
|
||||
static final int CTRL_TYPE_LEFT = 1;
|
||||
static final int CTRL_TYPE_RIGHT = 2;
|
||||
static final int CTRL_TYPE_TOP = 4;
|
||||
|
||||
Reference in New Issue
Block a user