Loading core/java/android/view/DragEvent.java +2 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,7 @@ public class DragEvent implements Parcelable { Object mLocalState; boolean mDragResult; boolean mEventHandlerWasCalled; private DragEvent mNext; private RuntimeException mRecycledLocation; Loading Loading @@ -439,6 +440,7 @@ public class DragEvent implements Parcelable { mClipData = null; mClipDescription = null; mLocalState = null; mEventHandlerWasCalled = false; synchronized (gRecyclerLock) { if (gRecyclerUsed < MAX_RECYCLED) { Loading core/java/android/view/View.java +11 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -20881,6 +20880,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 core/java/android/view/ViewGroup.java +10 −103 Original line number Diff line number Diff line Loading @@ -154,9 +154,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; Loading Loading @@ -1366,16 +1363,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) { Loading Loading @@ -1438,60 +1430,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; Loading @@ -1501,55 +1448,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager event.mX = tx; event.mY = ty; } else { 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); } } } 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(); } 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"); } } } break; Loading Loading @@ -1596,6 +1502,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()) { Loading core/java/android/view/ViewRootImpl.java +37 −4 Original line number Diff line number Diff line Loading @@ -5527,9 +5527,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)) { Loading @@ -5556,6 +5555,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 { Loading @@ -5582,6 +5587,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) { Loading Loading @@ -5641,9 +5647,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; } } Loading Loading
core/java/android/view/DragEvent.java +2 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,7 @@ public class DragEvent implements Parcelable { Object mLocalState; boolean mDragResult; boolean mEventHandlerWasCalled; private DragEvent mNext; private RuntimeException mRecycledLocation; Loading Loading @@ -439,6 +440,7 @@ public class DragEvent implements Parcelable { mClipData = null; mClipDescription = null; mLocalState = null; mEventHandlerWasCalled = false; synchronized (gRecyclerLock) { if (gRecyclerUsed < MAX_RECYCLED) { Loading
core/java/android/view/View.java +11 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -20881,6 +20880,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
core/java/android/view/ViewGroup.java +10 −103 Original line number Diff line number Diff line Loading @@ -154,9 +154,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; Loading Loading @@ -1366,16 +1363,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) { Loading Loading @@ -1438,60 +1430,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; Loading @@ -1501,55 +1448,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager event.mX = tx; event.mY = ty; } else { 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); } } } 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(); } 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"); } } } break; Loading Loading @@ -1596,6 +1502,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()) { Loading
core/java/android/view/ViewRootImpl.java +37 −4 Original line number Diff line number Diff line Loading @@ -5527,9 +5527,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)) { Loading @@ -5556,6 +5555,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 { Loading @@ -5582,6 +5587,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) { Loading Loading @@ -5641,9 +5647,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; } } Loading