summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2010-11-30 17:14:08 -0800
committerChristopher Tate <ctate@google.com>2010-12-01 14:45:06 -0800
commit407b4e91fe7627545b8110e683953353236b4543 (patch)
tree4235966903b57ba0faf502fc3a91e4f81aeef67b
parent4da12f07b5c1ecd7cea7f44081a744523936bd41 (diff)
downloadframeworks_base-407b4e91fe7627545b8110e683953353236b4543.zip
frameworks_base-407b4e91fe7627545b8110e683953353236b4543.tar.gz
frameworks_base-407b4e91fe7627545b8110e683953353236b4543.tar.bz2
API CHANGE: drags can now carry an originator-only object payload
When calling startDrag(), the app can now supply an Object to be passed along in every DragEvent that the app winds up receiving itself. This object is *not* passed to any other applications; it's strictly app- local. The purpose is to allow state tracking/management to be done directly through the drag mechanism rather than requiring out-of-band code. An example of the utility here might be TextEdit widgets. A drag that starts in one TextEdit but ends in a different one should be treated as a copy/paste operation, where the originating TextEdit is not altered. However, a drag that starts and ends in the *same* TextEdit is a 'move' operation within that TextEdit; the text is removed from its original position and inserted at the drop point. To support this easily, the drag/drop code in TextEdit can now pass a pointer to the originating view as the local state object. Then, the drop recipient could tell whether the drag started within the same TextEdit without needing to implement any other out-of-band state tracking. This CL (and its accompanying CLs in a few other packages where the startDrag() API is being used) adds the new local-state parameter to the API, but does not actually change the behavior of any existing clients. Change-Id: Icba73b2ab4a650b7a94485a19633065b0ef9058c
-rw-r--r--api/current.xml13
-rw-r--r--core/java/android/view/DragEvent.java17
-rw-r--r--core/java/android/view/View.java23
-rw-r--r--core/java/android/view/ViewRoot.java14
-rw-r--r--core/java/android/widget/TextView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java2
-rw-r--r--services/java/com/android/server/WindowManagerService.java10
7 files changed, 68 insertions, 13 deletions
diff --git a/api/current.xml b/api/current.xml
index 9fc6e3e..31626b9 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -194856,6 +194856,17 @@
visibility="public"
>
</method>
+<method name="getLocalState"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getResult"
return="boolean"
abstract="false"
@@ -208857,6 +208868,8 @@
</parameter>
<parameter name="myWindowOnly" type="boolean">
</parameter>
+<parameter name="myLocalState" type="java.lang.Object">
+</parameter>
</method>
<method name="unscheduleDrawable"
return="void"
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 07e87d6..6634f00 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;
+ Object mLocalState;
boolean mDragResult;
private DragEvent mNext;
@@ -139,11 +140,11 @@ public static final int ACTION_DRAG_EXITED = 6;
}
static DragEvent obtain() {
- return DragEvent.obtain(0, 0f, 0f, null, null, false);
+ return DragEvent.obtain(0, 0f, 0f, null, null, null, false);
}
/** @hide */
- public static DragEvent obtain(int action, float x, float y,
+ public static DragEvent obtain(int action, float x, float y, Object localState,
ClipDescription description, ClipData data, boolean result) {
final DragEvent ev;
synchronized (gRecyclerLock) {
@@ -167,7 +168,7 @@ public static final int ACTION_DRAG_EXITED = 6;
/** @hide */
public static DragEvent obtain(DragEvent source) {
- return obtain(source.mAction, source.mX, source.mY,
+ return obtain(source.mAction, source.mX, source.mY, source.mLocalState,
source.mClipDescription, source.mClipData, source.mDragResult);
}
@@ -218,6 +219,15 @@ public static final int ACTION_DRAG_EXITED = 6;
}
/**
+ * Provides the local state object passed as the {@code myLocalState} parameter to
+ * View.startDrag(). The object will always be null here if the application receiving
+ * the DragEvent is not the one that started the drag.
+ */
+ public Object getLocalState() {
+ return mLocalState;
+ }
+
+ /**
* Provides an indication of whether the drag operation concluded successfully.
* This method is only available on ACTION_DRAG_ENDED events.
* @return {@code true} if the drag operation ended with an accepted drop; {@code false}
@@ -249,6 +259,7 @@ public static final int ACTION_DRAG_EXITED = 6;
mClipData = null;
mClipDescription = null;
+ mLocalState = null;
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f135fcc..ea237e3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10081,9 +10081,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* onProvideThumbnailMetrics() and onDrawThumbnail() methods happen, then the drag
* operation is handed over to the OS.
* !!! TODO: real docs
+ *
+ * @param data !!! TODO
+ * @param thumbBuilder !!! TODO
+ * @param myWindowOnly When {@code true}, indicates that the drag operation should be
+ * restricted to the calling application. In this case only the calling application
+ * will see any DragEvents related to this drag operation.
+ * @param myLocalState An arbitrary object that will be passed as part of every DragEvent
+ * delivered to the calling application during the course of the current drag operation.
+ * This object is private to the application that called startDrag(), and is not
+ * visible to other applications. It provides a lightweight way for the application to
+ * propagate information from the initiator to the recipient of a drag within its own
+ * application; for example, to help disambiguate between 'copy' and 'move' semantics.
+ * @return {@code true} if the drag operation was initiated successfully; {@code false} if
+ * an error prevented the drag from taking place.
*/
public final boolean startDrag(ClipData data, DragThumbnailBuilder thumbBuilder,
- boolean myWindowOnly) {
+ boolean myWindowOnly, Object myLocalState) {
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "startDrag: data=" + data + " local=" + myWindowOnly);
}
@@ -10117,8 +10131,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
surface.unlockCanvasAndPost(canvas);
}
+ final ViewRoot root = getViewRoot();
+
+ // Cache the local state object for delivery with DragEvents
+ root.setLocalDragState(myLocalState);
+
// repurpose 'thumbSize' for the last touch point
- getViewRoot().getLastTouchPoint(thumbSize);
+ root.getLastTouchPoint(thumbSize);
okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token,
(float) thumbSize.x, (float) thumbSize.y,
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 77083a9..17d413a 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -228,6 +228,7 @@ public final class ViewRoot extends Handler implements ViewParent,
/* Drag/drop */
ClipDescription mDragDescription;
View mCurrentDragView;
+ Object mLocalDragState;
final PointF mDragPoint = new PointF();
final PointF mLastTouchPoint = new PointF();
@@ -2680,6 +2681,10 @@ public final class ViewRoot extends Handler implements ViewParent,
}
/* drag/drop */
+ void setLocalDragState(Object obj) {
+ mLocalDragState = obj;
+ }
+
private void handleDragEvent(DragEvent event) {
// From the root, only drag start/end/location are dispatched. entered/exited
// are determined and dispatched by the viewgroup hierarchy, who then report
@@ -2738,7 +2743,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
- // Report the drop result if necessary
+ // Report the drop result when we're done
if (what == DragEvent.ACTION_DROP) {
try {
Log.i(TAG, "Reporting drop result: " + result);
@@ -2747,6 +2752,12 @@ public final class ViewRoot extends Handler implements ViewParent,
Log.e(TAG, "Unable to report drop result");
}
}
+
+ // When the drag operation ends, release any local state object
+ // that may have been in use
+ if (what == DragEvent.ACTION_DRAG_ENDED) {
+ setLocalDragState(null);
+ }
}
}
event.recycle();
@@ -3063,6 +3074,7 @@ public final class ViewRoot extends Handler implements ViewParent,
} else {
what = DISPATCH_DRAG_EVENT;
}
+ event.mLocalState = mLocalDragState; // only present when this app called startDrag()
Message msg = obtainMessage(what, event);
sendMessage(msg);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b4512cf..43434d3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7818,7 +7818,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int end = getSelectionEnd();
CharSequence selectedText = mTransformed.subSequence(start, end);
ClipData data = ClipData.newPlainText(null, null, selectedText);
- startDrag(data, getTextThumbnailBuilder(selectedText), false);
+ startDrag(data, getTextThumbnailBuilder(selectedText), false, null);
mDragSourcePositions = packRangeInLong(start, end);
stopSelectionActionMode();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index d1e61a9..4d0835f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -169,7 +169,7 @@ public class ShirtPocket extends FrameLayout {
thumb = new DragThumbnailBuilder(mWindow.findViewById(R.id.preview));
}
- v.startDrag(clip, thumb, false);
+ v.startDrag(clip, thumb, false, null);
// TODO: only discard the clipping if it was accepted
stash(null);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 27ec1af..d7a6a0e 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -619,7 +619,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, false);
+ null, desc, null, false);
try {
newWin.mClient.dispatchDragEvent(event);
// track each window that we've notified that the drag is starting
@@ -659,7 +659,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.d(TAG, "broadcasting DRAG_ENDED");
}
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
- 0, 0, null, null, mDragResult);
+ 0, 0, null, null, null, mDragResult);
for (WindowState ws: mNotifiedWindows) {
try {
ws.mClient.dispatchDragEvent(evt);
@@ -711,7 +711,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, false);
+ null, null, null, false);
mTargetWindow.mClient.dispatchDragEvent(evt);
if (myPid != mTargetWindow.mSession.mPid) {
evt.recycle();
@@ -723,7 +723,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, false);
+ null, null, null, false);
touchedWin.mClient.dispatchDragEvent(evt);
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
@@ -754,7 +754,7 @@ public class WindowManagerService extends IWindowManager.Stub
final IBinder token = touchedWin.mClient.asBinder();
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP,
x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
- null, mData, false);
+ null, null, mData, false);
try {
touchedWin.mClient.dispatchDragEvent(evt);