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:
Ats Jenk
2022-10-10 19:47:23 +00:00
committed by Automerger Merge Worker
3 changed files with 164 additions and 23 deletions

View File

@@ -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);
}
/**

View File

@@ -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);
}
}
}
}

View File

@@ -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;