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
This commit is contained in:
Daichi Hirono
2017-11-10 13:51:02 +09:00
parent bb28efb631
commit 663e9a777f
2 changed files with 79 additions and 67 deletions

View File

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

View File

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