Merge "Resize tasks from corners when in touch mode" into tm-qpr-dev
This commit is contained in:
@@ -28,6 +28,7 @@ import android.os.Handler;
|
|||||||
import android.view.Choreographer;
|
import android.view.Choreographer;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
import android.window.WindowContainerTransaction;
|
import android.window.WindowContainerTransaction;
|
||||||
|
|
||||||
import com.android.wm.shell.R;
|
import com.android.wm.shell.R;
|
||||||
@@ -55,6 +56,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
// Height of button (32dp) + 2 * margin (5dp each)
|
// Height of button (32dp) + 2 * margin (5dp each)
|
||||||
private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42;
|
private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42;
|
||||||
private static final int RESIZE_HANDLE_IN_DIP = 30;
|
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 EMPTY_OUTSET = new Rect();
|
||||||
private static final Rect RESIZE_HANDLE_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) {
|
if (oldDecorationSurface != mDecorationContainerSurface || mDragResizeListener == null) {
|
||||||
closeDragResizeListener();
|
closeDragResizeListener();
|
||||||
mDragResizeListener = new DragResizeInputListener(
|
mDragResizeListener = new DragResizeInputListener(
|
||||||
mContext,
|
mContext,
|
||||||
mHandler,
|
mHandler,
|
||||||
mChoreographer,
|
mChoreographer,
|
||||||
mDisplay.getDisplayId(),
|
mDisplay.getDisplayId(),
|
||||||
mDecorationContainerSurface,
|
mDecorationContainerSurface,
|
||||||
mDragResizeCallback);
|
mDragResizeCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop();
|
||||||
|
|
||||||
mDragResizeListener.setGeometry(
|
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;
|
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.FLAG_NOT_FOCUSABLE;
|
||||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
import android.hardware.input.InputManager;
|
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
|
* 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 {
|
class DragResizeInputListener implements AutoCloseable {
|
||||||
private static final String TAG = "DragResizeInputListener";
|
private static final String TAG = "DragResizeInputListener";
|
||||||
|
|
||||||
@@ -63,8 +68,15 @@ class DragResizeInputListener implements AutoCloseable {
|
|||||||
private int mWidth;
|
private int mWidth;
|
||||||
private int mHeight;
|
private int mHeight;
|
||||||
private int mResizeHandleThickness;
|
private int mResizeHandleThickness;
|
||||||
|
private int mCornerSize;
|
||||||
|
|
||||||
|
private Rect mLeftTopCornerBounds;
|
||||||
|
private Rect mRightTopCornerBounds;
|
||||||
|
private Rect mLeftBottomCornerBounds;
|
||||||
|
private Rect mRightBottomCornerBounds;
|
||||||
|
|
||||||
private int mDragPointerId = -1;
|
private int mDragPointerId = -1;
|
||||||
|
private int mTouchSlop;
|
||||||
|
|
||||||
DragResizeInputListener(
|
DragResizeInputListener(
|
||||||
Context context,
|
Context context,
|
||||||
@@ -118,16 +130,23 @@ class DragResizeInputListener implements AutoCloseable {
|
|||||||
* @param height The height of the drag resize handler in pixels, including resize handle
|
* @param height The height of the drag resize handler in pixels, including resize handle
|
||||||
* thickness. That is task height + 2 * resize handle thickness.
|
* thickness. That is task height + 2 * resize handle thickness.
|
||||||
* @param resizeHandleThickness The thickness of the resize handle in pixels.
|
* @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
|
if (mWidth == width && mHeight == height
|
||||||
&& mResizeHandleThickness == resizeHandleThickness) {
|
&& mResizeHandleThickness == resizeHandleThickness
|
||||||
|
&& mCornerSize == cornerSize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mWidth = width;
|
mWidth = width;
|
||||||
mHeight = height;
|
mHeight = height;
|
||||||
mResizeHandleThickness = resizeHandleThickness;
|
mResizeHandleThickness = resizeHandleThickness;
|
||||||
|
mCornerSize = cornerSize;
|
||||||
|
mTouchSlop = touchSlop;
|
||||||
|
|
||||||
Region touchRegion = new Region();
|
Region touchRegion = new Region();
|
||||||
final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness);
|
final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness);
|
||||||
@@ -146,6 +165,40 @@ class DragResizeInputListener implements AutoCloseable {
|
|||||||
mWidth, mHeight);
|
mWidth, mHeight);
|
||||||
touchRegion.union(bottomInputBounds);
|
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 {
|
try {
|
||||||
mWindowSession.updateInputChannel(
|
mWindowSession.updateInputChannel(
|
||||||
mInputChannel.getToken(),
|
mInputChannel.getToken(),
|
||||||
@@ -173,6 +226,9 @@ class DragResizeInputListener implements AutoCloseable {
|
|||||||
private final Choreographer mChoreographer;
|
private final Choreographer mChoreographer;
|
||||||
private final Runnable mConsumeBatchEventRunnable;
|
private final Runnable mConsumeBatchEventRunnable;
|
||||||
private boolean mConsumeBatchEventScheduled;
|
private boolean mConsumeBatchEventScheduled;
|
||||||
|
private boolean mShouldHandleEvents;
|
||||||
|
private boolean mDragging;
|
||||||
|
private final PointF mActionDownPoint = new PointF();
|
||||||
|
|
||||||
private TaskResizeInputEventReceiver(
|
private TaskResizeInputEventReceiver(
|
||||||
InputChannel inputChannel, Handler handler, Choreographer choreographer) {
|
InputChannel inputChannel, Handler handler, Choreographer choreographer) {
|
||||||
@@ -216,41 +272,101 @@ class DragResizeInputListener implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent e = (MotionEvent) inputEvent;
|
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()) {
|
switch (e.getActionMasked()) {
|
||||||
case MotionEvent.ACTION_DOWN: {
|
case MotionEvent.ACTION_DOWN: {
|
||||||
mDragPointerId = e.getPointerId(0);
|
float x = e.getX(0);
|
||||||
mCallback.onDragResizeStart(
|
float y = e.getY(0);
|
||||||
calculateCtrlType(e.getX(0), e.getY(0)), e.getRawX(0), e.getRawY(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;
|
break;
|
||||||
}
|
}
|
||||||
case MotionEvent.ACTION_MOVE: {
|
case MotionEvent.ACTION_MOVE: {
|
||||||
|
if (!mShouldHandleEvents) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
|
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
|
||||||
mCallback.onDragResizeMove(
|
float rawX = e.getRawX(dragPointerIndex);
|
||||||
e.getRawX(dragPointerIndex), e.getRawY(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;
|
break;
|
||||||
}
|
}
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
case MotionEvent.ACTION_CANCEL: {
|
case MotionEvent.ACTION_CANCEL: {
|
||||||
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
|
if (mDragging) {
|
||||||
mCallback.onDragResizeEnd(
|
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
|
||||||
e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
|
mCallback.onDragResizeEnd(
|
||||||
|
e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
|
||||||
|
}
|
||||||
|
mDragging = false;
|
||||||
|
mShouldHandleEvents = false;
|
||||||
|
mActionDownPoint.set(0, 0);
|
||||||
mDragPointerId = -1;
|
mDragPointerId = -1;
|
||||||
|
result = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MotionEvent.ACTION_HOVER_ENTER:
|
case MotionEvent.ACTION_HOVER_ENTER:
|
||||||
case MotionEvent.ACTION_HOVER_MOVE: {
|
case MotionEvent.ACTION_HOVER_MOVE: {
|
||||||
updateCursorType(e.getXCursorPosition(), e.getYCursorPosition());
|
updateCursorType(e.getXCursorPosition(), e.getYCursorPosition());
|
||||||
|
result = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MotionEvent.ACTION_HOVER_EXIT:
|
case MotionEvent.ACTION_HOVER_EXIT:
|
||||||
mInputManager.setPointerIconType(PointerIcon.TYPE_DEFAULT);
|
mInputManager.setPointerIconType(PointerIcon.TYPE_DEFAULT);
|
||||||
|
result = true;
|
||||||
break;
|
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
|
@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;
|
int ctrlType = 0;
|
||||||
if (x < mResizeHandleThickness) {
|
if (x < mResizeHandleThickness) {
|
||||||
ctrlType |= TaskPositioner.CTRL_TYPE_LEFT;
|
ctrlType |= TaskPositioner.CTRL_TYPE_LEFT;
|
||||||
@@ -267,8 +383,27 @@ class DragResizeInputListener implements AutoCloseable {
|
|||||||
return ctrlType;
|
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) {
|
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;
|
int cursorType = PointerIcon.TYPE_DEFAULT;
|
||||||
switch (ctrlType) {
|
switch (ctrlType) {
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ import com.android.wm.shell.ShellTaskOrganizer;
|
|||||||
|
|
||||||
class TaskPositioner implements DragResizeCallback {
|
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 {}
|
@interface CtrlType {}
|
||||||
|
|
||||||
|
static final int CTRL_TYPE_UNDEFINED = 0;
|
||||||
static final int CTRL_TYPE_LEFT = 1;
|
static final int CTRL_TYPE_LEFT = 1;
|
||||||
static final int CTRL_TYPE_RIGHT = 2;
|
static final int CTRL_TYPE_RIGHT = 2;
|
||||||
static final int CTRL_TYPE_TOP = 4;
|
static final int CTRL_TYPE_TOP = 4;
|
||||||
|
|||||||
Reference in New Issue
Block a user