summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/DragEvent.java2
-rw-r--r--core/java/android/view/View.java12
-rw-r--r--core/java/android/view/ViewGroup.java113
-rw-r--r--core/java/android/view/ViewRootImpl.java41
4 files changed, 60 insertions, 108 deletions
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index b0f15b5f2329..e0a6fac1891f 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -134,6 +134,7 @@ public class DragEvent implements Parcelable {
Object mLocalState;
boolean mDragResult;
+ boolean mEventHandlerWasCalled;
private DragEvent mNext;
private RuntimeException mRecycledLocation;
@@ -435,6 +436,7 @@ public class DragEvent implements Parcelable {
mClipData = null;
mClipDescription = null;
mLocalState = null;
+ mEventHandlerWasCalled = false;
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 908658feb29c..1d972eafa379 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,7 +40,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Interpolator;
import android.graphics.LinearGradient;
@@ -20874,6 +20873,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* </p>
*/
public boolean dispatchDragEvent(DragEvent event) {
+ event.mEventHandlerWasCalled = true;
+ if (event.mAction == DragEvent.ACTION_DRAG_LOCATION ||
+ event.mAction == DragEvent.ACTION_DROP) {
+ // About to deliver an event with coordinates to this view. Notify that now this view
+ // has drag focus. This will send exit/enter events as needed.
+ getViewRootImpl().setDragFocus(this, event);
+ }
+ return callDragEventHandler(event);
+ }
+
+ final boolean callDragEventHandler(DragEvent event) {
ListenerInfo li = mListenerInfo;
//noinspection SimplifiableIfStatement
if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 6933efc15b68..987db0ac58ed 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -153,9 +153,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
Transformation mInvalidationTransformation;
- // View currently under an ongoing drag. Can be null, a child or this window.
- private View mCurrentDragView;
-
// Metadata about the ongoing drag
private DragEvent mCurrentDragStartEvent;
private boolean mIsInterestedInDrag;
@@ -1362,16 +1359,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final float tx = event.mX;
final float ty = event.mY;
- ViewRootImpl root = getViewRootImpl();
-
// Dispatch down the view hierarchy
final PointF localPoint = getLocalPoint();
switch (event.mAction) {
case DragEvent.ACTION_DRAG_STARTED: {
- // clear state to recalculate which views we drag over
- mCurrentDragView = null;
-
// Set up our tracking of drag-started notifications
mCurrentDragStartEvent = DragEvent.obtain(event);
if (mChildrenInterestedInDrag == null) {
@@ -1434,60 +1426,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
} break;
- case DragEvent.ACTION_DRAG_LOCATION: {
+ case DragEvent.ACTION_DRAG_LOCATION:
+ case DragEvent.ACTION_DROP: {
// Find the [possibly new] drag target
View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
if (target == null && mIsInterestedInDrag) {
target = this;
}
- // If we've changed apparent drag target, tell the view root which view
- // we're over now [for purposes of the eventual drag-recipient-changed
- // notifications to the framework] and tell the new target that the drag
- // has entered its bounds. The root will see setDragFocus() calls all
- // the way down to the final leaf view that is handling the LOCATION event
- // before reporting the new potential recipient to the framework.
- if (mCurrentDragView != target) {
- root.setDragFocus(target);
-
- final int action = event.mAction;
- // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
- event.mX = 0;
- event.mY = 0;
-
- // If we've dragged off of a child view or this window, send it the EXITED message
- if (mCurrentDragView != null) {
- final View view = mCurrentDragView;
- event.mAction = DragEvent.ACTION_DRAG_EXITED;
- if (view != this) {
- view.dispatchDragEvent(event);
- view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
- view.refreshDrawableState();
- } else {
- super.dispatchDragEvent(event);
- }
- }
-
- mCurrentDragView = target;
-
- // If we've dragged over a new child view, send it the ENTERED message, otherwise
- // send it to this window.
- if (target != null) {
- event.mAction = DragEvent.ACTION_DRAG_ENTERED;
- if (target != this) {
- target.dispatchDragEvent(event);
- target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
- target.refreshDrawableState();
- } else {
- super.dispatchDragEvent(event);
- }
- }
- event.mAction = action; // restore the event's original state
- event.mX = tx;
- event.mY = ty;
- }
-
- // Dispatch the actual drag location notice, localized into its coordinates
+ // Dispatch the actual drag notice, localized into the target coordinates.
if (target != null) {
if (target != this) {
event.mX = localPoint.x;
@@ -1497,55 +1444,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
event.mX = tx;
event.mY = ty;
- } else {
- retval = super.dispatchDragEvent(event);
- }
- }
- } break;
- /* Entered / exited dispatch
- *
- * DRAG_ENTERED is not dispatched downwards from ViewGroup. The reason for this is
- * that we're about to get the corresponding LOCATION event, which we will use to
- * determine which of our children is the new target; at that point we will
- * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
- * If no suitable child is detected, dispatch to this window.
- *
- * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
- * drag has left this ViewGroup, we know by definition that every contained subview
- * is also no longer under the drag point.
- */
-
- case DragEvent.ACTION_DRAG_EXITED: {
- if (mCurrentDragView != null) {
- final View view = mCurrentDragView;
- if (view != this) {
- view.dispatchDragEvent(event);
- view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
- view.refreshDrawableState();
+ if (!event.mEventHandlerWasCalled && mIsInterestedInDrag) {
+ // The child didn't invoke any event handler, but this view is interested in
+ // drag, so the event goes to this view.
+ retval = super.dispatchDragEvent(event);
+ }
} else {
- super.dispatchDragEvent(event);
- }
-
- mCurrentDragView = null;
- }
- } break;
-
- case DragEvent.ACTION_DROP: {
- if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
- View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
- if (target != null) {
- if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target);
- event.mX = localPoint.x;
- event.mY = localPoint.y;
- retval = target.dispatchDragEvent(event);
- event.mX = tx;
- event.mY = ty;
- } else if (mIsInterestedInDrag) {
- retval = super.dispatchDragEvent(event);
- } else {
- if (ViewDebug.DEBUG_DRAG) {
- Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view");
+ retval = super.dispatchDragEvent(event);
}
}
} break;
@@ -1592,6 +1498,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
mCurrentDragStartEvent.mX = tx;
mCurrentDragStartEvent.mY = ty;
+ mCurrentDragStartEvent.mEventHandlerWasCalled = false;
if (canAccept) {
mChildrenInterestedInDrag.add(child);
if (!child.canAcceptDrag()) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1d541f6c0c4c..8abaa14810e1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5523,9 +5523,8 @@ public final class ViewRootImpl implements ViewParent,
if (what == DragEvent.ACTION_DRAG_EXITED) {
// A direct EXITED event means that the window manager knows we've just crossed
// a window boundary, so the current drag target within this one must have
- // just been exited. Send it the usual notifications and then we're done
- // for now.
- mView.dispatchDragEvent(event);
+ // just been exited. Send the EXITED notification to the current drag view, if any.
+ setDragFocus(null, event);
} else {
// For events with a [screen] location, translate into window coordinates
if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
@@ -5548,6 +5547,12 @@ public final class ViewRootImpl implements ViewParent,
// Now dispatch the drag/drop event
boolean result = mView.dispatchDragEvent(event);
+ if (what == DragEvent.ACTION_DRAG_LOCATION && !event.mEventHandlerWasCalled) {
+ // If the LOCATION event wasn't delivered to any handler, no view now has a drag
+ // focus.
+ setDragFocus(null, event);
+ }
+
// If we changed apparent drag target, tell the OS about it
if (prevDragView != mCurrentDragView) {
try {
@@ -5575,6 +5580,7 @@ public final class ViewRootImpl implements ViewParent,
// When the drag operation ends, reset drag-related state
if (what == DragEvent.ACTION_DRAG_ENDED) {
+ mCurrentDragView = null;
setLocalDragState(null);
mAttachInfo.mDragToken = null;
if (mAttachInfo.mDragSurface != null) {
@@ -5634,9 +5640,36 @@ public final class ViewRootImpl implements ViewParent,
return mLastTouchSource;
}
- public void setDragFocus(View newDragTarget) {
+ public void setDragFocus(View newDragTarget, DragEvent event) {
if (mCurrentDragView != newDragTarget) {
+ // Send EXITED and ENTERED notifications to the old and new drag focus views.
+
+ final float tx = event.mX;
+ final float ty = event.mY;
+ final int action = event.mAction;
+ // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
+ event.mX = 0;
+ event.mY = 0;
+
+ if (mCurrentDragView != null) {
+ event.mAction = DragEvent.ACTION_DRAG_EXITED;
+ mCurrentDragView.callDragEventHandler(event);
+ mCurrentDragView.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
+ mCurrentDragView.refreshDrawableState();
+ }
+
mCurrentDragView = newDragTarget;
+
+ if (newDragTarget != null) {
+ event.mAction = DragEvent.ACTION_DRAG_ENTERED;
+ newDragTarget.callDragEventHandler(event);
+ newDragTarget.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
+ newDragTarget.refreshDrawableState();
+ }
+
+ event.mAction = action;
+ event.mX = tx;
+ event.mY = ty;
}
}