diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index b6f0f6a134543..70908337dfd38 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -35,6 +35,7 @@ import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; +import com.android.server.input.InputWindowHandle; /** * Managing drag and drop operations initiated by View#startDragAndDrop. @@ -54,7 +55,7 @@ class DragDropController { * The variable is cleared by {@code #onDragStateClosedLocked} which is invoked by DragState * itself, thus the variable can be null after calling DragState's methods. */ - DragState mDragState; + private DragState mDragState; private WindowManagerService mService; private final Handler mHandler; @@ -63,11 +64,19 @@ class DragDropController { return mDragState != null; } + InputWindowHandle getInputWindowHandleLocked() { + return mDragState.getInputWindowHandle(); + } + DragDropController(WindowManagerService service, Looper looper) { mService = service; mHandler = new DragHandler(service, looper); } + void sendDragStartedIfNeededLocked(WindowState window) { + mDragState.sendDragStartedIfNeededLocked(window); + } + IBinder prepareDrag(SurfaceSession session, int callerPid, int callerUid, IWindow window, int flags, int width, int height, Surface outSurface) { if (DEBUG_DRAG) { @@ -257,6 +266,30 @@ class DragDropController { } } + /** + * Handles motion events. + * @param keepHandling Whether if the drag operation is continuing or this is the last motion + * event. + * @param newX X coordinate value in dp in the screen coordinate + * @param newY Y coordinate value in dp in the screen coordinate + */ + void handleMotionEvent(boolean keepHandling, float newX, float newY) { + synchronized (mService.mWindowMap) { + if (!dragDropActiveLocked()) { + // The drag has ended but the clean-up message has not been processed by + // window manager. Drop events that occur after this until window manager + // has a chance to clean-up the input handle. + return; + } + + if (keepHandling) { + mDragState.notifyMoveLocked(newX, newY); + } else { + mDragState.notifyDropLocked(newX, newY); + } + } + } + void dragRecipientEntered(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder()); diff --git a/services/core/java/com/android/server/wm/DragInputEventReceiver.java b/services/core/java/com/android/server/wm/DragInputEventReceiver.java index b4bbc9055631d..bee2bacf83d2e 100644 --- a/services/core/java/com/android/server/wm/DragInputEventReceiver.java +++ b/services/core/java/com/android/server/wm/DragInputEventReceiver.java @@ -37,7 +37,6 @@ import android.view.MotionEvent; * Input receiver for drag and drop */ class DragInputEventReceiver extends InputEventReceiver { - private final WindowManagerService mService; private final DragDropController mDragDropController; // Set, if stylus button was down at the start of the drag. @@ -48,100 +47,63 @@ class DragInputEventReceiver extends InputEventReceiver { // are still being dispatched. private boolean mMuteInput = false; - public DragInputEventReceiver(InputChannel inputChannel, Looper looper, - DragDropController controller, WindowManagerService service) { + DragInputEventReceiver(InputChannel inputChannel, Looper looper, + DragDropController controller) { super(inputChannel, looper); mDragDropController = controller; - mService = service; } @Override public void onInputEvent(InputEvent event, int displayId) { boolean handled = false; try { - synchronized (mService.mWindowMap) { - if (!mDragDropController.dragDropActiveLocked()) { - // The drag has ended but the clean-up message has not been processed by - // window manager. Drop events that occur after this until window manager - // has a chance to clean-up the input handle. - handled = true; - return; - } - if (!(event instanceof MotionEvent) - || (event.getSource() & SOURCE_CLASS_POINTER) == 0 - || mMuteInput) { - return; - } - final MotionEvent motionEvent = (MotionEvent) event; - boolean endDrag = false; - final float newX = motionEvent.getRawX(); - final float newY = motionEvent.getRawY(); - final boolean isStylusButtonDown = - (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0; - - if (mIsStartEvent) { - if (isStylusButtonDown) { - // First event and the button was down, check for the button being - // lifted in the future, if that happens we'll drop the item. - mStylusButtonDownAtStart = true; - } - mIsStartEvent = false; - } - - switch (motionEvent.getAction()) { - case ACTION_DOWN: { - if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer"); - } - break; - - case ACTION_MOVE: { - if (mStylusButtonDownAtStart && !isStylusButtonDown) { - if (DEBUG_DRAG) { - Slog.d(TAG_WM, "Button no longer pressed; dropping at " - + newX + "," + newY); - } - mMuteInput = true; - endDrag = mDragDropController.mDragState - .notifyDropLocked(newX, newY); - } else { - // move the surface and tell the involved window(s) where we are - mDragDropController.mDragState.notifyMoveLocked(newX, newY); - } - } - break; - - case ACTION_UP: { - if (DEBUG_DRAG) { - Slog.d(TAG_WM, "Got UP on move channel; dropping at " - + newX + "," + newY); - } - mMuteInput = true; - endDrag = mDragDropController.mDragState - .notifyDropLocked(newX, newY); - } - break; - - case ACTION_CANCEL: { - if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!"); - mMuteInput = true; - endDrag = true; - } - break; - } - - if (endDrag) { - if (DEBUG_DRAG) - Slog.d(TAG_WM, "Drag ended; tearing down state"); - // tell all the windows that the drag has ended - // endDragLocked will post back to looper to dispose the receiver - // since we still need the receiver for the last finishInputEvent. - mDragDropController.mDragState.endDragLocked(); - mStylusButtonDownAtStart = false; - mIsStartEvent = true; - } - - handled = true; + if (!(event instanceof MotionEvent) + || (event.getSource() & SOURCE_CLASS_POINTER) == 0 + || mMuteInput) { + return; } + final MotionEvent motionEvent = (MotionEvent) event; + final float newX = motionEvent.getRawX(); + final float newY = motionEvent.getRawY(); + final boolean isStylusButtonDown = + (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0; + + if (mIsStartEvent) { + // First event and the button was down, check for the button being + // lifted in the future, if that happens we'll drop the item. + mStylusButtonDownAtStart = isStylusButtonDown; + mIsStartEvent = false; + } + + switch (motionEvent.getAction()) { + case ACTION_DOWN: + if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer"); + return; + case ACTION_MOVE: + if (mStylusButtonDownAtStart && !isStylusButtonDown) { + if (DEBUG_DRAG) { + Slog.d(TAG_WM, "Button no longer pressed; dropping at " + newX + "," + + newY); + } + mMuteInput = true; + } + break; + case ACTION_UP: + if (DEBUG_DRAG) { + Slog.d(TAG_WM, "Got UP on move channel; dropping at " + newX + "," + newY); + } + mMuteInput = true; + break; + case ACTION_CANCEL: + if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!"); + mMuteInput = true; + break; + default: + return; + } + + mDragDropController.handleMotionEvent(!mMuteInput /* keepHandling */, newX, newY); + handled = true; } catch (Exception e) { Slog.e(TAG_WM, "Exception caught by drag handleMotion", e); } finally { diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index da0394b6e294d..0727107cd4528 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -214,7 +214,7 @@ class DragState { mClientChannel = channels[1]; mService.mInputManager.registerInputChannel(mServerChannel, null); mInputEventReceiver = new DragInputEventReceiver(mClientChannel, - mService.mH.getLooper(), mDragDropController, mService); + mService.mH.getLooper(), mDragDropController); mDragApplicationHandle = new InputApplicationHandle(null); mDragApplicationHandle.name = "drag"; @@ -508,34 +508,33 @@ class DragState { mTargetWindow = touchedWin; } - // Find the drop target and tell it about the data. Returns 'true' if we can immediately - // dispatch the global drag-ended message, 'false' if we need to wait for a - // result from the recipient. - boolean notifyDropLocked(float x, float y) { + /** + * Finds the drop target and tells it about the data. If the drop event is not sent to the + * target, invokes {@code endDragLocked} immediately. + */ + void notifyDropLocked(float x, float y) { if (mAnimator != null) { - return false; + return; } mCurrentX = x; mCurrentY = y; - WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y); + final WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y); if (!isWindowNotified(touchedWin)) { // "drop" outside a valid window -- no recipient to apply a // timeout to, and we can send the drag-ended message immediately. mDragResult = false; - return true; + endDragLocked(); + return; } - if (DEBUG_DRAG) { - Slog.d(TAG_WM, "sending DROP to " + touchedWin); - } + if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin); final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid()); - DragAndDropPermissionsHandler dragAndDropPermissions = null; - if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && - (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) { + final DragAndDropPermissionsHandler dragAndDropPermissions; + if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) { dragAndDropPermissions = new DragAndDropPermissionsHandler( mData, mUid, @@ -543,13 +542,15 @@ class DragState { mFlags & DRAG_FLAGS_URI_PERMISSIONS, mSourceUserId, targetUserId); + } else { + dragAndDropPermissions = null; } if (mSourceUserId != targetUserId){ mData.fixUris(mSourceUserId); } final int myPid = Process.myPid(); final IBinder token = touchedWin.mClient.asBinder(); - DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y, + final DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y, null, null, mData, dragAndDropPermissions, false); try { touchedWin.mClient.dispatchDragEvent(evt); @@ -558,14 +559,13 @@ class DragState { mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token); } catch (RemoteException e) { Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin); - return true; + endDragLocked(); } finally { if (myPid != touchedWin.mSession.mPid) { evt.recycle(); } } mToken = token; - return false; } private static DragEvent obtainDragEvent(WindowState win, int action, diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index d23369efd2971..a4080cacf4305 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -373,7 +373,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { Log.d(TAG_WM, "Inserting drag window"); } final InputWindowHandle dragWindowHandle = - mService.mDragDropController.mDragState.getInputWindowHandle(); + mService.mDragDropController.getInputWindowHandleLocked(); if (dragWindowHandle != null) { addInputWindowHandle(dragWindowHandle); } else { @@ -690,7 +690,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { // If there's a drag in progress and 'child' is a potential drop target, // make sure it's been told about the drag if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) { - mService.mDragDropController.mDragState.sendDragStartedIfNeededLocked(w); + mService.mDragDropController.sendDragStartedIfNeededLocked(w); } addInputWindowHandle( diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c982d1576d466..ac2977c58f794 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7054,7 +7054,7 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized (mWindowMap) { - if (mDragDropController.mDragState != null) { + if (mDragDropController.dragDropActiveLocked()) { // Drag cursor overrides the app cursor. return; }