summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.xml13
-rw-r--r--core/java/android/view/DragEvent.java23
-rw-r--r--core/java/android/view/IWindowSession.aidl7
-rw-r--r--core/java/android/view/ViewRoot.java12
-rw-r--r--services/java/com/android/server/WindowManagerService.java148
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java5
6 files changed, 158 insertions, 50 deletions
diff --git a/api/current.xml b/api/current.xml
index 1055707a9984..22a105ad1208 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -190770,6 +190770,17 @@
visibility="public"
>
</method>
+<method name="getResult"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getX"
return="float"
abstract="false"
@@ -190812,6 +190823,8 @@
</parameter>
<parameter name="data" type="android.content.ClipData">
</parameter>
+<parameter name="result" type="boolean">
+</parameter>
</method>
<method name="obtain"
return="android.view.DragEvent"
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index ebf850524b35..bbac14cc5c3e 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -29,6 +29,7 @@ public class DragEvent implements Parcelable {
float mX, mY;
ClipDescription mClipDescription;
ClipData mClipData;
+ boolean mDragResult;
private DragEvent mNext;
private RuntimeException mRecycledLocation;
@@ -53,25 +54,27 @@ public class DragEvent implements Parcelable {
private DragEvent() {
}
- private void init(int action, float x, float y, ClipDescription description, ClipData data) {
+ private void init(int action, float x, float y, ClipDescription description, ClipData data,
+ boolean result) {
mAction = action;
mX = x;
mY = y;
mClipDescription = description;
mClipData = data;
+ mDragResult = result;
}
static DragEvent obtain() {
- return DragEvent.obtain(0, 0f, 0f, null, null);
+ return DragEvent.obtain(0, 0f, 0f, null, null, false);
}
public static DragEvent obtain(int action, float x, float y,
- ClipDescription description, ClipData data) {
+ ClipDescription description, ClipData data, boolean result) {
final DragEvent ev;
synchronized (gRecyclerLock) {
if (gRecyclerTop == null) {
ev = new DragEvent();
- ev.init(action, x, y, description, data);
+ ev.init(action, x, y, description, data, result);
return ev;
}
ev = gRecyclerTop;
@@ -82,14 +85,14 @@ public class DragEvent implements Parcelable {
ev.mRecycled = false;
ev.mNext = null;
- ev.init(action, x, y, description, data);
+ ev.init(action, x, y, description, data, result);
return ev;
}
public static DragEvent obtain(DragEvent source) {
return obtain(source.mAction, source.mX, source.mY,
- source.mClipDescription, source.mClipData);
+ source.mClipDescription, source.mClipData, source.mDragResult);
}
public int getAction() {
@@ -112,6 +115,10 @@ public class DragEvent implements Parcelable {
return mClipDescription;
}
+ public boolean getResult() {
+ return mDragResult;
+ }
+
/**
* Recycle the DragEvent, to be re-used by a later caller. After calling
* this function you must never touch the event again.
@@ -146,7 +153,7 @@ public class DragEvent implements Parcelable {
public String toString() {
return "DragEvent{" + Integer.toHexString(System.identityHashCode(this))
+ " action=" + mAction + " @ (" + mX + ", " + mY + ") desc=" + mClipDescription
- + " data=" + mClipData
+ + " data=" + mClipData + " result=" + mDragResult
+ "}";
}
@@ -160,6 +167,7 @@ public class DragEvent implements Parcelable {
dest.writeInt(mAction);
dest.writeFloat(mX);
dest.writeFloat(mY);
+ dest.writeInt(mDragResult ? 1 : 0);
if (mClipData == null) {
dest.writeInt(0);
} else {
@@ -181,6 +189,7 @@ public class DragEvent implements Parcelable {
event.mAction = in.readInt();
event.mX = in.readFloat();
event.mY = in.readFloat();
+ event.mDragResult = (in.readInt() != 0);
if (in.readInt() != 0) {
event.mClipData = ClipData.CREATOR.createFromParcel(in);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 79ea5b68b572..23fae426c5a0 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -130,6 +130,13 @@ interface IWindowSession {
boolean performDrag(IWindow window, IBinder dragToken, float touchX, float touchY,
float thumbCenterX, float thumbCenterY, in ClipData data);
+ /**
+ * Report the result of a drop action targeted to the given window.
+ * consumed is 'true' when the drop was accepted by a valid recipient,
+ * 'false' otherwise.
+ */
+ void reportDropResult(IWindow window, boolean consumed);
+
/**
* Tell the OS that we've just dragged into a View that is willing to accept the drop
*/
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index ae671b8bd5ec..ea688adcb91e 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -2506,7 +2506,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
final View prevDragView = mCurrentDragView;
// Now dispatch the drag/drop event
- mView.dispatchDragEvent(event);
+ boolean result = mView.dispatchDragEvent(event);
// If we changed apparent drag target, tell the OS about it
if (prevDragView != mCurrentDragView) {
@@ -2521,6 +2521,16 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
Slog.e(TAG, "Unable to note drag target change");
}
}
+
+ // Report the drop result if necessary
+ if (what == DragEvent.ACTION_DROP) {
+ try {
+ Log.i(TAG, "Reporting drop result: " + result);
+ sWindowSession.reportDropResult(mWindow, result);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to report drop result");
+ }
+ }
}
}
event.recycle();
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index af2fece2a795..60bd19b09845 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;
+ }
}
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 0553f5edd92d..eb0eba2b54fd 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -1093,6 +1093,11 @@ public final class Bridge implements ILayoutBridge {
}
@SuppressWarnings("unused")
+ public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
+ // pass for now
+ }
+
+ @SuppressWarnings("unused")
public void dragRecipientEntered(IWindow window) throws RemoteException {
// pass for now
}