From 45bee6b24c8d181eafce339dc90d11b5e1bec74e Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Mon, 19 Sep 2016 11:00:37 -0700 Subject: [PATCH] For pre-N apps, cascade LOCATION and DROP events. To restore the pre-N behavior, if a view returns false from its LOCATION or DROP event handler, the event goes to its parent. Bug: 31559942 Change-Id: I322099ae1e8a5cbbcf8814f2cd274fbae53b6848 --- core/java/android/view/View.java | 13 +++++++++++++ core/java/android/view/ViewGroup.java | 17 ++++++++++++----- core/java/android/view/ViewRootImpl.java | 4 ++-- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 37b54a87965a9..86d3f62865827 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -829,6 +829,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ protected static boolean sPreserveMarginParamsInLayoutParamConversion; + /** + * Prior to N, when drag enters into child of a view that has already received an + * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. + * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned + * false from its event handler for these events. + * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its + * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. + * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. + */ + static boolean sCascadedDragDrop; + /** * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when * calling setFlags. @@ -4065,6 +4076,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // in apps so we target check it to avoid breaking existing apps. sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N; + sCascadedDragDrop = targetSdkVersion < N; + sCompatibilityDone = true; } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 7111f28f5741b..d4b7d3bdd76aa 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1451,7 +1451,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint); if (target != mCurrentDragChild) { - if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { + if (sCascadedDragDrop) { // 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). @@ -1494,10 +1494,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager event.mX = tx; event.mY = ty; - 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); + if (mIsInterestedInDrag) { + final boolean eventWasConsumed; + if (sCascadedDragDrop) { + eventWasConsumed = retval; + } else { + eventWasConsumed = event.mEventHandlerWasCalled; + } + + if (!eventWasConsumed) { + retval = super.dispatchDragEvent(event); + } } } else { retval = super.dispatchDragEvent(event); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 0f161cdbc900e..e95fa5e6a2ee1 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5524,7 +5524,7 @@ 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) { + if (View.sCascadedDragDrop) { mView.dispatchDragEnterExitInPreN(event); } setDragFocus(null, event); @@ -5644,7 +5644,7 @@ public final class ViewRootImpl implements ViewParent, } public void setDragFocus(View newDragTarget, DragEvent event) { - if (mCurrentDragView != newDragTarget && mTargetSdkVersion >= Build.VERSION_CODES.N) { + if (mCurrentDragView != newDragTarget && !View.sCascadedDragDrop) { // Send EXITED and ENTERED notifications to the old and new drag focus views. final float tx = event.mX;