Merge "For pre-N apps, keep entered all parents of an drag-entered child." into nyc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
0ef6986379
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
return 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 result;
|
||||
}
|
||||
|
||||
boolean canAcceptDrag() {
|
||||
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user