Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +12 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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( Loading Loading @@ -153,8 +155,11 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL 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); } /** Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +150 −15 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading @@ -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, Loading Loading @@ -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); Loading @@ -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(), Loading Loading @@ -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) { Loading Loading @@ -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: { 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); mCallback.onDragResizeStart( calculateCtrlType(e.getX(0), e.getY(0)), e.getRawX(0), e.getRawY(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: { 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(boolean isTouch, float x, float y) { if (isTouch) { return calculateCornersCtrlType(x, y); } return calculateResizeHandlesCtrlType(x, y); } @TaskPositioner.CtrlType private int calculateCtrlType(float x, float y) { private int calculateResizeHandlesCtrlType(float x, float y) { int ctrlType = 0; if (x < mResizeHandleThickness) { ctrlType |= TaskPositioner.CTRL_TYPE_LEFT; Loading @@ -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) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +12 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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( Loading Loading @@ -153,8 +155,11 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL 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); } /** Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +150 −15 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading @@ -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, Loading Loading @@ -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); Loading @@ -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(), Loading Loading @@ -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) { Loading Loading @@ -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: { 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); mCallback.onDragResizeStart( calculateCtrlType(e.getX(0), e.getY(0)), e.getRawX(0), e.getRawY(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: { 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(boolean isTouch, float x, float y) { if (isTouch) { return calculateCornersCtrlType(x, y); } return calculateResizeHandlesCtrlType(x, y); } @TaskPositioner.CtrlType private int calculateCtrlType(float x, float y) { private int calculateResizeHandlesCtrlType(float x, float y) { int ctrlType = 0; if (x < mResizeHandleThickness) { ctrlType |= TaskPositioner.CTRL_TYPE_LEFT; Loading @@ -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) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading