Merge "For pre-N apps, keep entered all parents of an drag-entered child." into nyc-mr1-dev

This commit is contained in:
TreeHugger Robot
2016-09-20 20:27:22 +00:00
committed by Android (Google) Code Review
3 changed files with 84 additions and 11 deletions

View File

@@ -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() {

View File

@@ -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;
}

View File

@@ -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() {