Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45bf9dee authored by Vadim Tryshev's avatar Vadim Tryshev Committed by android-build-merger
Browse files

Eliminating the black hole effect with location/drop events. am: 1edc6daf am: 32394cee

am: 416384e0

Change-Id: I6d9ea65abf3bcaa3150e6c0f26d2ff184efda095
parents 8cd48de4 416384e0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ public class DragEvent implements Parcelable {

    Object mLocalState;
    boolean mDragResult;
    boolean mEventHandlerWasCalled;

    private DragEvent mNext;
    private RuntimeException mRecycledLocation;
@@ -439,6 +440,7 @@ public class DragEvent implements Parcelable {
        mClipData = null;
        mClipDescription = null;
        mLocalState = null;
        mEventHandlerWasCalled = false;

        synchronized (gRecyclerLock) {
            if (gRecyclerUsed < MAX_RECYCLED) {
+11 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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
+10 −103
Original line number Diff line number Diff line
@@ -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;
@@ -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) {
@@ -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;
@@ -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;
@@ -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()) {
+37 −4
Original line number Diff line number Diff line
@@ -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)) {
@@ -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 {
@@ -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) {
@@ -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;
        }
    }