summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorChris Tate <ctate@google.com>2010-10-19 15:15:08 -0700
committerChris Tate <ctate@google.com>2010-10-21 14:25:06 -0700
commitd4533f1469990582e4a2dd0898429093fe2690c0 (patch)
tree7ca94c99e6e56ad7d1007c6a1a9d62846a52d075 /services
parent82a8a2aa0acc8af59f264d41090c3b99d695c2d5 (diff)
downloadframeworks_base-d4533f1469990582e4a2dd0898429093fe2690c0.zip
frameworks_base-d4533f1469990582e4a2dd0898429093fe2690c0.tar.gz
frameworks_base-d4533f1469990582e4a2dd0898429093fe2690c0.tar.bz2
Report drag success/fail in the DRAG_ENDED message
DragEvent.getResult() returns 'true' if the drop was ultimately accepted; false otherwise. The validity of this datum is only guaranteed when the DragEvent's action verb is ACTION_DRAG_ENDED. Also fixes the drag-start timeout handling (though the offending app is not yet officially declared ANR). Implements bug 3097807 Change-Id: I6908ac628c72ff7d6193d87060d769a559a78d0e
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/WindowManagerService.java148
1 files changed, 106 insertions, 42 deletions
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index af2fece..60bd19b 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -501,6 +501,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mLocalOnly;
ClipData mData;
ClipDescription mDataDescription;
+ boolean mDragResult;
float mCurrentX, mCurrentY;
float mThumbOffsetX, mThumbOffsetY;
InputChannel mServerChannel, mClientChannel;
@@ -594,7 +595,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mDragInProgress && newWin.isPotentialDragTarget()) {
DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED,
touchX - newWin.mFrame.left, touchY - newWin.mFrame.top,
- desc, null);
+ desc, null, false);
try {
newWin.mClient.dispatchDragEvent(event);
// track each window that we've notified that the drag is starting
@@ -629,25 +630,36 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- void broadcastDragEnded() {
+ void broadcastDragEndedLw() {
if (DEBUG_DRAG) {
Slog.d(TAG, "broadcasting DRAG_ENDED");
}
- DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, 0, 0, null, null);
- synchronized (mWindowMap) {
- for (WindowState ws: mNotifiedWindows) {
- try {
- ws.mClient.dispatchDragEvent(evt);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to drag-end window " + ws);
- }
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
+ 0, 0, null, null, mDragResult);
+ for (WindowState ws: mNotifiedWindows) {
+ try {
+ ws.mClient.dispatchDragEvent(evt);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to drag-end window " + ws);
}
- mNotifiedWindows.clear();
- mDragInProgress = false;
}
+ mNotifiedWindows.clear();
+ mDragInProgress = false;
evt.recycle();
}
+ void endDragLw() {
+ mDragState.broadcastDragEndedLw();
+
+ // stop intercepting input
+ mDragState.unregister();
+ mInputMonitor.updateInputWindowsLw();
+
+ // free our resources and drop all the object references
+ mDragState.reset();
+ mDragState = null;
+ }
+
void notifyMoveLw(float x, float y) {
final int myPid = Process.myPid();
@@ -667,7 +679,7 @@ public class WindowManagerService extends IWindowManager.Stub
// force DRAG_EXITED_EVENT if appropriate
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED,
x - mTargetWindow.mFrame.left, y - mTargetWindow.mFrame.top,
- null, null);
+ null, null, false);
mTargetWindow.mClient.dispatchDragEvent(evt);
if (myPid != mTargetWindow.mSession.mPid) {
evt.recycle();
@@ -679,7 +691,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION,
x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
- null, null);
+ null, null, false);
touchedWin.mClient.dispatchDragEvent(evt);
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
@@ -691,26 +703,43 @@ public class WindowManagerService extends IWindowManager.Stub
mTargetWindow = touchedWin;
}
- // Tell the drop target about the data, and then broadcast the drag-ended notification
- void notifyDropLw(float x, float y) {
+ // Tell the drop target 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 notifyDropLw(float x, float y) {
WindowState touchedWin = getTouchedWinAtPointLw(x, y);
- if (touchedWin != null) {
- if (DEBUG_DRAG) {
- Slog.d(TAG, "sending DROP to " + touchedWin);
- }
- final int myPid = Process.myPid();
- DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP,
- x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
- null, mData);
- try {
- touchedWin.mClient.dispatchDragEvent(evt);
- } catch (RemoteException e) {
- Slog.w(TAG, "can't send drop notification to win " + touchedWin);
- }
+ if (touchedWin == null) {
+ // "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;
+ }
+
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "sending DROP to " + touchedWin);
+ }
+ final int myPid = Process.myPid();
+ final IBinder token = touchedWin.mClient.asBinder();
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP,
+ x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
+ null, mData, false);
+ try {
+ touchedWin.mClient.dispatchDragEvent(evt);
+
+ // 5 second timeout for this window to respond to the drop
+ mH.removeMessages(H.DRAG_END_TIMEOUT, token);
+ Message msg = mH.obtainMessage(H.DRAG_END_TIMEOUT, token);
+ mH.sendMessageDelayed(msg, 5000);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "can't send drop notification to win " + touchedWin);
+ return true;
+ } finally {
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
}
}
+ mToken = token;
+ return false;
}
// Find the visible, touch-deliverable window under the given point
@@ -794,9 +823,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_DRAG) Slog.d(TAG, "Got UP on move channel; dropping at "
+ newX + "," + newY);
synchronized (mWindowMap) {
- mDragState.notifyDropLw(newX, newY);
+ endDrag = mDragState.notifyDropLw(newX, newY);
}
- endDrag = true;
} break;
case MotionEvent.ACTION_CANCEL: {
@@ -808,17 +836,9 @@ public class WindowManagerService extends IWindowManager.Stub
if (endDrag) {
if (DEBUG_DRAG) Slog.d(TAG, "Drag ended; tearing down state");
// tell all the windows that the drag has ended
- mDragState.broadcastDragEnded();
-
- // stop intercepting input
- mDragState.unregister();
synchronized (mWindowMap) {
- mInputMonitor.updateInputWindowsLw();
+ mDragState.endDragLw();
}
-
- // free our resources and drop all the object references
- mDragState.reset();
- mDragState = null;
}
}
} catch (Exception e) {
@@ -6251,15 +6271,43 @@ public class WindowManagerService extends IWindowManager.Stub
return true; // success!
}
+ public void reportDropResult(IWindow window, boolean consumed) {
+ IBinder token = window.asBinder();
+ if (DEBUG_DRAG) {
+ Slog.d(TAG, "Drop result=" + consumed + " reported by " + token);
+ }
+
+ synchronized (mWindowMap) {
+ if (mDragState.mToken != token) {
+ Slog.w(TAG, "Invalid drop-result claim by " + window);
+ throw new IllegalStateException("reportDropResult() by non-recipient");
+ }
+
+ // The right window has responded, even if it's no longer around,
+ // so be sure to halt the timeout even if the later WindowState
+ // lookup fails.
+ mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder());
+
+ WindowState callingWin = windowForClientLocked(null, window, false);
+ if (callingWin == null) {
+ Slog.w(TAG, "Bad result-reporting window " + window);
+ return; // !!! TODO: throw here?
+ }
+
+ mDragState.mDragResult = consumed;
+ mDragState.endDragLw();
+ }
+ }
+
public void dragRecipientEntered(IWindow window) {
if (DEBUG_DRAG) {
- Slog.d(TAG, "Drag into new candidate view @ " + window);
+ Slog.d(TAG, "Drag into new candidate view @ " + window.asBinder());
}
}
public void dragRecipientExited(IWindow window) {
if (DEBUG_DRAG) {
- Slog.d(TAG, "Drag from old candidate view @ " + window);
+ Slog.d(TAG, "Drag from old candidate view @ " + window.asBinder());
}
}
@@ -8321,6 +8369,7 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int SEND_NEW_CONFIGURATION = 18;
public static final int REPORT_WINDOWS_CHANGE = 19;
public static final int DRAG_START_TIMEOUT = 20;
+ public static final int DRAG_END_TIMEOUT = 21;
private Session mLastReportedHold;
@@ -8671,12 +8720,27 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
// !!! TODO: ANR the app that has failed to start the drag in time
if (mDragState != null) {
+ mDragState.unregister();
+ mInputMonitor.updateInputWindowsLw();
mDragState.reset();
mDragState = null;
}
}
+ break;
}
+ case DRAG_END_TIMEOUT: {
+ IBinder win = (IBinder)msg.obj;
+ if (DEBUG_DRAG) {
+ Slog.w(TAG, "Timeout ending drag to win " + win);
+ }
+ synchronized (mWindowMap) {
+ // !!! TODO: ANR the drag-receiving app
+ mDragState.mDragResult = false;
+ mDragState.endDragLw();
+ }
+ break;
+ }
}
}
}