Loading core/java/android/view/View.java +27 −2 Original line number Diff line number Diff line Loading @@ -20858,6 +20858,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. boolean dispatchDragEnterExitInPreN(DragEvent event) { return callDragEventHandler(event); } /** * Detects if this View is enabled and has a drag event listener. * If both are true, then it calls the drag event listener with the Loading Loading @@ -20886,13 +20891,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } final boolean callDragEventHandler(DragEvent event) { final boolean result; ListenerInfo li = mListenerInfo; //noinspection SimplifiableIfStatement if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnDragListener.onDrag(this, event)) { return true; result = true; } else { result = onDragEvent(event); } switch (event.mAction) { case DragEvent.ACTION_DRAG_ENTERED: { mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; refreshDrawableState(); } break; case DragEvent.ACTION_DRAG_EXITED: { mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; refreshDrawableState(); } break; case DragEvent.ACTION_DRAG_ENDED: { mPrivateFlags2 &= ~View.DRAG_MASK; refreshDrawableState(); } break; } return onDragEvent(event); return result; } boolean canAcceptDrag() { core/java/android/view/ViewGroup.java +51 −2 Original line number Diff line number Diff line Loading @@ -153,6 +153,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ Transformation mInvalidationTransformation; // Current frontmost child that can accept drag and lies under the drag location. // Used only to generate ENTER/EXIT events for pre-Nougat aps. private View mCurrentDragChild; // Metadata about the ongoing drag private DragEvent mCurrentDragStartEvent; private boolean mIsInterestedInDrag; Loading Loading @@ -1352,6 +1356,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mLocalPoint; } @Override boolean dispatchDragEnterExitInPreN(DragEvent event) { if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) { // The drag exited a sub-tree of views; notify of the exit all descendants that are in // entered state. // We don't need this recursive delivery for ENTERED events because they get generated // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own // recursion. mCurrentDragChild.dispatchDragEnterExitInPreN(event); mCurrentDragChild = null; } return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event); } // TODO: Write real docs @Override public boolean dispatchDragEvent(DragEvent event) { Loading @@ -1364,6 +1382,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager switch (event.mAction) { case DragEvent.ACTION_DRAG_STARTED: { // Clear the state to recalculate which views we drag over. mCurrentDragChild = null; // Set up our tracking of drag-started notifications mCurrentDragStartEvent = DragEvent.obtain(event); if (mChildrenInterestedInDrag == null) { Loading Loading @@ -1408,8 +1429,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (child.dispatchDragEvent(event)) { retval = true; } child.mPrivateFlags2 &= ~View.DRAG_MASK; child.refreshDrawableState(); } childrenInterestedInDrag.clear(); } Loading @@ -1430,6 +1449,36 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager case DragEvent.ACTION_DROP: { // Find the [possibly new] drag target View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint); if (target != mCurrentDragChild) { if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { // For pre-Nougat apps, make sure that the whole hierarchy of views that contain // the drag location is kept in the state between ENTERED and EXITED events. // (Starting with N, only the innermost view will be in that state). 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 (mCurrentDragChild != null) { event.mAction = DragEvent.ACTION_DRAG_EXITED; mCurrentDragChild.dispatchDragEnterExitInPreN(event); } if (target != null) { event.mAction = DragEvent.ACTION_DRAG_ENTERED; target.dispatchDragEnterExitInPreN(event); } event.mAction = action; event.mX = tx; event.mY = ty; } mCurrentDragChild = target; } if (target == null && mIsInterestedInDrag) { target = this; } Loading core/java/android/view/ViewRootImpl.java +6 −7 Original line number Diff line number Diff line Loading @@ -5524,6 +5524,9 @@ public final class ViewRootImpl implements ViewParent, // 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 the EXITED notification to the current drag view, if any. if (mTargetSdkVersion < Build.VERSION_CODES.N) { mView.dispatchDragEnterExitInPreN(event); } setDragFocus(null, event); } else { // For events with a [screen] location, translate into window coordinates Loading Loading @@ -5641,7 +5644,7 @@ public final class ViewRootImpl implements ViewParent, } public void setDragFocus(View newDragTarget, DragEvent event) { if (mCurrentDragView != newDragTarget) { if (mCurrentDragView != newDragTarget && mTargetSdkVersion >= Build.VERSION_CODES.N) { // Send EXITED and ENTERED notifications to the old and new drag focus views. final float tx = event.mX; Loading @@ -5654,23 +5657,19 @@ public final class ViewRootImpl implements ViewParent, 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; } mCurrentDragView = newDragTarget; } private AudioManager getAudioManager() { Loading Loading
core/java/android/view/View.java +27 −2 Original line number Diff line number Diff line Loading @@ -20858,6 +20858,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. boolean dispatchDragEnterExitInPreN(DragEvent event) { return callDragEventHandler(event); } /** * Detects if this View is enabled and has a drag event listener. * If both are true, then it calls the drag event listener with the Loading Loading @@ -20886,13 +20891,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } final boolean callDragEventHandler(DragEvent event) { final boolean result; ListenerInfo li = mListenerInfo; //noinspection SimplifiableIfStatement if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnDragListener.onDrag(this, event)) { return true; result = true; } else { result = onDragEvent(event); } switch (event.mAction) { case DragEvent.ACTION_DRAG_ENTERED: { mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; refreshDrawableState(); } break; case DragEvent.ACTION_DRAG_EXITED: { mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; refreshDrawableState(); } break; case DragEvent.ACTION_DRAG_ENDED: { mPrivateFlags2 &= ~View.DRAG_MASK; refreshDrawableState(); } break; } return onDragEvent(event); return result; } boolean canAcceptDrag() {
core/java/android/view/ViewGroup.java +51 −2 Original line number Diff line number Diff line Loading @@ -153,6 +153,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ Transformation mInvalidationTransformation; // Current frontmost child that can accept drag and lies under the drag location. // Used only to generate ENTER/EXIT events for pre-Nougat aps. private View mCurrentDragChild; // Metadata about the ongoing drag private DragEvent mCurrentDragStartEvent; private boolean mIsInterestedInDrag; Loading Loading @@ -1352,6 +1356,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mLocalPoint; } @Override boolean dispatchDragEnterExitInPreN(DragEvent event) { if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) { // The drag exited a sub-tree of views; notify of the exit all descendants that are in // entered state. // We don't need this recursive delivery for ENTERED events because they get generated // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own // recursion. mCurrentDragChild.dispatchDragEnterExitInPreN(event); mCurrentDragChild = null; } return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event); } // TODO: Write real docs @Override public boolean dispatchDragEvent(DragEvent event) { Loading @@ -1364,6 +1382,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager switch (event.mAction) { case DragEvent.ACTION_DRAG_STARTED: { // Clear the state to recalculate which views we drag over. mCurrentDragChild = null; // Set up our tracking of drag-started notifications mCurrentDragStartEvent = DragEvent.obtain(event); if (mChildrenInterestedInDrag == null) { Loading Loading @@ -1408,8 +1429,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (child.dispatchDragEvent(event)) { retval = true; } child.mPrivateFlags2 &= ~View.DRAG_MASK; child.refreshDrawableState(); } childrenInterestedInDrag.clear(); } Loading @@ -1430,6 +1449,36 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager case DragEvent.ACTION_DROP: { // Find the [possibly new] drag target View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint); if (target != mCurrentDragChild) { if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { // For pre-Nougat apps, make sure that the whole hierarchy of views that contain // the drag location is kept in the state between ENTERED and EXITED events. // (Starting with N, only the innermost view will be in that state). 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 (mCurrentDragChild != null) { event.mAction = DragEvent.ACTION_DRAG_EXITED; mCurrentDragChild.dispatchDragEnterExitInPreN(event); } if (target != null) { event.mAction = DragEvent.ACTION_DRAG_ENTERED; target.dispatchDragEnterExitInPreN(event); } event.mAction = action; event.mX = tx; event.mY = ty; } mCurrentDragChild = target; } if (target == null && mIsInterestedInDrag) { target = this; } Loading
core/java/android/view/ViewRootImpl.java +6 −7 Original line number Diff line number Diff line Loading @@ -5524,6 +5524,9 @@ public final class ViewRootImpl implements ViewParent, // 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 the EXITED notification to the current drag view, if any. if (mTargetSdkVersion < Build.VERSION_CODES.N) { mView.dispatchDragEnterExitInPreN(event); } setDragFocus(null, event); } else { // For events with a [screen] location, translate into window coordinates Loading Loading @@ -5641,7 +5644,7 @@ public final class ViewRootImpl implements ViewParent, } public void setDragFocus(View newDragTarget, DragEvent event) { if (mCurrentDragView != newDragTarget) { if (mCurrentDragView != newDragTarget && mTargetSdkVersion >= Build.VERSION_CODES.N) { // Send EXITED and ENTERED notifications to the old and new drag focus views. final float tx = event.mX; Loading @@ -5654,23 +5657,19 @@ public final class ViewRootImpl implements ViewParent, 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; } mCurrentDragView = newDragTarget; } private AudioManager getAudioManager() { Loading