Implement View.cancelDrag
View.cancelDrag cancels a drag operation initiated by
View.startDrag.
It has to be called on a View in the same window (under the
same ViewRootImpl) that the view which started the drag.
Bug: 24415683
Change-Id: Iae5ff3534b6c747ae174f170fdd01ff4d3b1c312
diff --git a/api/current.txt b/api/current.txt
index e7627f7..429b117 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36238,6 +36238,7 @@
method public boolean canResolveTextDirection();
method public boolean canScrollHorizontally(int);
method public boolean canScrollVertically(int);
+ method public final void cancelDrag();
method public void cancelLongPress();
method public final void cancelPendingInputEvents();
method public boolean checkInputConnectionProxy(android.view.View);
diff --git a/api/system-current.txt b/api/system-current.txt
index 203df90..6d53b3f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -38559,6 +38559,7 @@
method public boolean canResolveTextDirection();
method public boolean canScrollHorizontally(int);
method public boolean canScrollVertically(int);
+ method public final void cancelDrag();
method public void cancelLongPress();
method public final void cancelPendingInputEvents();
method public boolean checkInputConnectionProxy(android.view.View);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 3fc70cc..f81b5d0 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -186,6 +186,11 @@
void reportDropResult(IWindow window, boolean consumed);
/**
+ * Cancel a drag operation.
+ */
+ void cancelDrag(IBinder dragToken);
+
+ /**
* Tell the OS that we've just dragged into a View that is willing to accept the drop
*/
void dragRecipientEntered(IWindow window);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index de4d439..30408c6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -19905,11 +19905,11 @@
}
Surface surface = new Surface();
try {
- IBinder token = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow,
+ mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow,
flags, shadowSize.x, shadowSize.y, surface);
- if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" + token
- + " surface=" + surface);
- if (token != null) {
+ if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token="
+ + mAttachInfo.mDragToken + " surface=" + surface);
+ if (mAttachInfo.mDragToken != null) {
Canvas canvas = surface.lockCanvas(null);
try {
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
@@ -19926,7 +19926,7 @@
// repurpose 'shadowSize' for the last touch point
root.getLastTouchPoint(shadowSize);
- okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token,
+ okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken,
shadowSize.x, shadowSize.y,
shadowTouchPoint.x, shadowTouchPoint.y, data);
if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
@@ -19943,6 +19943,22 @@
return okay;
}
+ public final void cancelDrag() {
+ if (ViewDebug.DEBUG_DRAG) {
+ Log.d(VIEW_LOG_TAG, "cancelDrag");
+ }
+ if (mAttachInfo.mDragToken != null) {
+ try {
+ mAttachInfo.mSession.cancelDrag(mAttachInfo.mDragToken);
+ } catch (Exception e) {
+ Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e);
+ }
+ mAttachInfo.mDragToken = null;
+ } else {
+ Log.e(VIEW_LOG_TAG, "No active drag to cancel");
+ }
+ }
+
/**
* Starts a move from {startX, startY}, the amount of the movement will be the offset
* between {startX, startY} and the new cursor positon.
@@ -22221,6 +22237,11 @@
View mViewRequestingLayout;
/**
+ * Used to track the identity of the current drag operation.
+ */
+ IBinder mDragToken;
+
+ /**
* Creates a new set of attachment information with the specified
* events handler and thread.
*
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cd9dd97..f1d9f1ab 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5307,10 +5307,10 @@
}
}
- // When the drag operation ends, release any local state object
- // that may have been in use
+ // When the drag operation ends, reset drag-related state
if (what == DragEvent.ACTION_DRAG_ENDED) {
setLocalDragState(null);
+ mAttachInfo.mDragToken = null;
}
}
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 1caeca0..b85a6923 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -401,6 +401,32 @@
}
}
+ public void cancelDrag(IBinder dragToken) {
+ if (WindowManagerService.DEBUG_DRAG) {
+ Slog.d(WindowManagerService.TAG, "cancel drag");
+ }
+
+ synchronized (mService.mWindowMap) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (mService.mDragState == null) {
+ Slog.w(WindowManagerService.TAG, "cancelDrag() without prepareDrag()");
+ throw new IllegalStateException("cancelDrag() without prepareDrag()");
+ }
+
+ if (mService.mDragState.mToken != dragToken) {
+ Slog.w(WindowManagerService.TAG, "cancelDrag() does not match prepareDrag()");
+ throw new IllegalStateException("cancelDrag() does not match prepareDrag()");
+ }
+
+ mService.mDragState.mDragResult = false;
+ mService.mDragState.endDragLw();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
public void dragRecipientEntered(IWindow window) {
if (WindowManagerService.DEBUG_DRAG) {
Slog.d(WindowManagerService.TAG, "Drag into new candidate view @ " + window.asBinder());