diff options
| -rw-r--r-- | core/java/android/view/DragEvent.java | 2 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 12 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 113 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 41 |
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; } } |