From 663e9a777f785316b2591eb180bc03f1e28f6c58 Mon Sep 17 00:00:00 2001 From: Daichi Hirono Date: Fri, 10 Nov 2017 13:51:02 +0900 Subject: [PATCH] Close mDragState immediately when error Previously if we encounter an error at performDrag, it sometimes just returns and lets MSG_DRAG_START_TIMEOUT clean up the drag state. It means users cannot start another drag and drop operation before timeout. The CL fix the error handling so that it immediately cleans the drag state on errors. Bug: 69141835 Test: android.server.wm.CrossAppDragAndDropTests, manually check the drag and drop behavior on test app. Change-Id: Ibc5784a842eed77e2fa082d8f38d69acc9954e3e --- .../android/server/wm/DragDropController.java | 138 +++++++++--------- .../java/com/android/server/wm/DragState.java | 8 + 2 files changed, 79 insertions(+), 67 deletions(-) diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index 9cba533310075..91478d0d1f2ff 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -150,80 +150,84 @@ class DragDropController { Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data); } - if (!mCallback.get().prePerformDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX, - thumbCenterY, data)) { - return false; - } + final boolean callbackResult = mCallback.get().prePerformDrag(window, dragToken, + touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data); try { synchronized (mService.mWindowMap) { - if (mDragState == null) { - Slog.w(TAG_WM, "No drag prepared"); - throw new IllegalStateException("performDrag() without prepareDrag()"); - } - - if (dragToken != mDragState.mToken) { - Slog.w(TAG_WM, "Performing mismatched drag"); - throw new IllegalStateException("performDrag() does not match prepareDrag()"); - } - - final WindowState callingWin = mService.windowForClientLocked(null, window, false); - if (callingWin == null) { - Slog.w(TAG_WM, "Bad requesting window " + window); - return false; // !!! TODO: throw here? - } - - // !!! TODO: if input is not still focused on the initiating window, fail - // the drag initiation (e.g. an alarm window popped up just as the application - // called performDrag() - mHandler.removeMessages(MSG_DRAG_START_TIMEOUT, window.asBinder()); - - // !!! TODO: extract the current touch (x, y) in screen coordinates. That - // will let us eliminate the (touchX,touchY) parameters from the API. - - // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as - // the actual drag event dispatch stuff in the dragstate - - final DisplayContent displayContent = callingWin.getDisplayContent(); - if (displayContent == null) { - return false; - } - Display display = displayContent.getDisplay(); - mDragState.register(display); - if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, - mDragState.getInputChannel())) { - Slog.e(TAG_WM, "Unable to transfer touch focus"); - mDragState.closeLocked(); - return false; - } - - mDragState.mDisplayContent = displayContent; - mDragState.mData = data; - mDragState.broadcastDragStartedLocked(touchX, touchY); - mDragState.overridePointerIconLocked(touchSource); - - // remember the thumb offsets for later - mDragState.mThumbOffsetX = thumbCenterX; - mDragState.mThumbOffsetY = thumbCenterY; - - // Make the surface visible at the proper location - final SurfaceControl surfaceControl = mDragState.mSurfaceControl; - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag"); - mService.openSurfaceTransaction(); try { - surfaceControl.setPosition(touchX - thumbCenterX, - touchY - thumbCenterY); - surfaceControl.setLayer(mDragState.getDragLayerLocked()); - surfaceControl.setLayerStack(display.getLayerStack()); - surfaceControl.show(); + if (!callbackResult) { + return false; + } + + Preconditions.checkState( + mDragState != null, "performDrag() without prepareDrag()"); + Preconditions.checkState( + mDragState.mToken == dragToken, + "performDrag() does not match prepareDrag()"); + + final WindowState callingWin = mService.windowForClientLocked( + null, window, false); + if (callingWin == null) { + Slog.w(TAG_WM, "Bad requesting window " + window); + return false; // !!! TODO: throw here? + } + + // !!! TODO: if input is not still focused on the initiating window, fail + // the drag initiation (e.g. an alarm window popped up just as the application + // called performDrag() + + // !!! TODO: extract the current touch (x, y) in screen coordinates. That + // will let us eliminate the (touchX,touchY) parameters from the API. + + // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as + // the actual drag event dispatch stuff in the dragstate + + final DisplayContent displayContent = callingWin.getDisplayContent(); + if (displayContent == null) { + Slog.w(TAG_WM, "display content is null"); + return false; + } + + final Display display = displayContent.getDisplay(); + mDragState.register(display); + if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, + mDragState.getInputChannel())) { + Slog.e(TAG_WM, "Unable to transfer touch focus"); + return false; + } + + mDragState.mDisplayContent = displayContent; + mDragState.mData = data; + mDragState.broadcastDragStartedLocked(touchX, touchY); + mDragState.overridePointerIconLocked(touchSource); + // remember the thumb offsets for later + mDragState.mThumbOffsetX = thumbCenterX; + mDragState.mThumbOffsetY = thumbCenterY; + + // Make the surface visible at the proper location + final SurfaceControl surfaceControl = mDragState.mSurfaceControl; + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag"); + mService.openSurfaceTransaction(); + try { + surfaceControl.setPosition(touchX - thumbCenterX, + touchY - thumbCenterY); + surfaceControl.setLayer(mDragState.getDragLayerLocked()); + surfaceControl.setLayerStack(display.getLayerStack()); + surfaceControl.show(); + } finally { + mService.closeSurfaceTransaction("performDrag"); + if (SHOW_LIGHT_TRANSACTIONS) { + Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag"); + } + } + + mDragState.notifyLocationLocked(touchX, touchY); } finally { - mService.closeSurfaceTransaction("performDrag"); - if (SHOW_LIGHT_TRANSACTIONS) { - Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag"); + if (mDragState != null && !mDragState.isInProgress()) { + mDragState.closeLocked(); } } - - mDragState.notifyLocationLocked(touchX, touchY); } return true; // success! } finally { diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 112e62f27ea2b..b9f437af20e40 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -568,6 +568,14 @@ class DragState { mToken = token; } + /** + * Returns true if it has sent DRAG_STARTED broadcast out but has not been sent DRAG_END + * broadcast. + */ + boolean isInProgress() { + return mDragInProgress; + } + private static DragEvent obtainDragEvent(WindowState win, int action, float x, float y, Object localState, ClipDescription description, ClipData data,