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

Commit 9c17fe69 authored by Chet Haase's avatar Chet Haase
Browse files

Fix touch processing for Overlay views

Previous implementation processed Overlay touch after other children in
a ViewGroup; it should be the other way around.

Also, fixed some invalidation issues.

Finally, added new behavior to automatically place View which is already
parented into the same global position, by calculating where the overlay is
on the screen relative to the previous parent of the View.

Issue #8459085 Overlay needs to handle touch correctly

Change-Id: Ic2cee12d2bc345f64ed3f4d855a5c3496967a201
parent d8b50ab6
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -18,9 +18,10 @@ package android.view;
import android.graphics.drawable.Drawable;

/**
 * An overlay is an extra layer that sits on top of a View (the "host view") which is drawn after
 * all other content in that view (including children, if the view is a ViewGroup). Interaction
 * with the overlay layer is done in terms of adding/removing views and drawables.
 * An overlay is an extra layer that sits on top of a View (the "host view")
 * which is drawn after all other content in that view (including children,
 * if the view is a ViewGroup). Interaction with the overlay layer is done in
 * terms of adding/removing views and drawables.
 *
 * @see android.view.View#getOverlay()
 */
@@ -47,10 +48,16 @@ public interface Overlay {
    void remove(Drawable drawable);

    /**
     * Adds a View to the overlay. The bounds of the added view should be relative to
     * the host view. Any view added to the overlay should be removed when it is no longer
     * needed or no longer visible. The view must not be parented elsewhere when it is added
     * to the overlay.
     * Adds a View to the overlay. The bounds of the added view should be
     * relative to the host view. Any view added to the overlay should be
     * removed when it is no longer needed or no longer visible.
     *
     * <p>If the view has a parent, the view will be removed from that parent
     * before being added to the overlay. Also, the view will be repositioned
     * such that it is in the same relative location inside the activity. For
     * example, if the view's current parent lies 100 pixels to the right
     * and 200 pixels down from the origin of the overlay's
     * host view, then the view will be offset by (100, 200).</p>
     *
     * @param view The View to be added to the overlay. The added view will be
     * drawn when the overlay is drawn.
+2 −2
Original line number Diff line number Diff line
@@ -12098,7 +12098,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        //System.out.println("Attached! " + this);
        mAttachInfo = info;
        if (mOverlay != null) {
            mOverlay.mAttachInfo = info;
            mOverlay.dispatchAttachedToWindow(info, visibility);
        }
        mWindowAttachCount++;
        // We will need to evaluate the drawable state at least once.
@@ -12169,7 +12169,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        mAttachInfo = null;
        if (mOverlay != null) {
            mOverlay.mAttachInfo = null;
            mOverlay.dispatchDetachedFromWindow();
        }
    }
+28 −25
Original line number Diff line number Diff line
@@ -1868,13 +1868,37 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                    // have become out of sync.
                    removePointersFromTouchTargets(idBitsToAssign);

                    final float x = ev.getX(actionIndex);
                    final float y = ev.getY(actionIndex);

                    if (mOverlay != null) {
                        ViewOverlay overlay = (ViewOverlay) mOverlay;
                        // Check to see whether the overlay can handle the event
                        final View child = mOverlay;
                        if (canViewReceivePointerEvents(child) &&
                                isTransformedTouchPointInView(x, y, child, null)) {
                            newTouchTarget = getTouchTarget(child);
                            if (newTouchTarget != null) {
                                newTouchTarget.pointerIdBits |= idBitsToAssign;
                            } else {
                                resetCancelNextUpFlag(child);
                                if (dispatchTransformedTouchEvent(ev, false, child,
                                        idBitsToAssign)) {
                                    mLastTouchDownTime = ev.getDownTime();
                                    mLastTouchDownX = ev.getX();
                                    mLastTouchDownY = ev.getY();
                                    newTouchTarget = addTouchTarget(child, idBitsToAssign);
                                    alreadyDispatchedToNewTouchTarget = true;
                                }
                            }
                        }
                    }

                    final int childrenCount = mChildrenCount;
                    if (childrenCount != 0 || mOverlay != null) {
                    if (newTouchTarget == null && childrenCount != 0) {
                        // Find a child that can receive the event.
                        // Scan children from front to back.
                        final View[] children = mChildren;
                        final float x = ev.getX(actionIndex);
                        final float y = ev.getY(actionIndex);

                        final boolean customOrder = isChildrenDrawingOrderEnabled();
                        for (int i = childrenCount - 1; i >= 0; i--) {
@@ -1906,27 +1930,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                                break;
                            }
                        }
                        if (mOverlay != null && newTouchTarget == null) {
                            // Check to see whether the overlay can handle the event
                            final View child = mOverlay;
                            if (canViewReceivePointerEvents(child) &&
                                    isTransformedTouchPointInView(x, y, child, null)) {
                                newTouchTarget = getTouchTarget(child);
                                if (newTouchTarget != null) {
                                    newTouchTarget.pointerIdBits |= idBitsToAssign;
                                } else {
                                    resetCancelNextUpFlag(child);
                                    if (dispatchTransformedTouchEvent(ev, false, child,
                                            idBitsToAssign)) {
                                        mLastTouchDownTime = ev.getDownTime();
                                        mLastTouchDownX = ev.getX();
                                        mLastTouchDownY = ev.getY();
                                        newTouchTarget = addTouchTarget(child, idBitsToAssign);
                                        alreadyDispatchedToNewTouchTarget = true;
                                    }
                                }
                            }
                        }
                    }

                    if (newTouchTarget == null && mFirstTouchTarget != null) {
+38 −11
Original line number Diff line number Diff line
@@ -23,17 +23,21 @@ import android.graphics.drawable.Drawable;
import java.util.ArrayList;

/**
 * ViewOverlay is a container that View uses to host all objects (views and drawables) that
 * are added to its "overlay", gotten through {@link View#getOverlay()}. Views and drawables are
 * added to the overlay via the add/remove methods in this class. These views and drawables are
 * drawn whenever the view itself is drawn; first the view draws its own content (and children,
 * if it is a ViewGroup), then it draws its overlay (if it has one).
 * ViewOverlay is a container that View uses to host all objects (views and
 * drawables) that are added to its "overlay", gotten through
 * {@link View#getOverlay()}. Views and drawables are added to the overlay
 * via the add/remove methods in this class. These views and drawables are
 * drawn whenever the view itself is drawn; first the view draws its own
 * content (and children, if it is a ViewGroup), then it draws its overlay
 * (if it has one).
 *
 * Besides managing and drawing the list of drawables, this class serves two purposes:
 * Besides managing and drawing the list of drawables, this class serves
 * two purposes:
 * (1) it noops layout calls because children are absolutely positioned and
 * (2) it forwards all invalidation calls to its host view. The invalidation redirect is
 * necessary because the overlay is not a child of the host view and invalidation cannot
 * therefore follow the normal path up through the parent hierarchy.
 * (2) it forwards all invalidation calls to its host view. The invalidation
 * redirect is necessary because the overlay is not a child of the host view
 * and invalidation cannot therefore follow the normal path up through the
 * parent hierarchy.
 *
 * @hide
 */
@@ -85,6 +89,22 @@ class ViewOverlay extends ViewGroup implements Overlay {

    @Override
    public void add(View child) {
        int deltaX = 0;
        int deltaY = 0;
        if (child.getParent() instanceof ViewGroup) {
            ViewGroup parent = (ViewGroup) child.getParent();
            if (parent != mHostView) {
                // Moving to different container; figure out how to position child such that
                // it is in the same location on the screen
                int[] parentLocation = new int[2];
                int[] hostViewLocation = new int[2];
                parent.getLocationOnScreen(parentLocation);
                mHostView.getLocationOnScreen(hostViewLocation);
                child.offsetLeftAndRight(parentLocation[0] - hostViewLocation[0]);
                child.offsetTopAndBottom(parentLocation[1] - hostViewLocation[1]);
            }
            parent.removeView(child);
        }
        super.addView(child);
    }

@@ -133,7 +153,6 @@ class ViewOverlay extends ViewGroup implements Overlay {
    public void invalidate(Rect dirty) {
        super.invalidate(dirty);
        if (mHostView != null) {
            dirty.offset(getLeft(), getTop());
            mHostView.invalidate(dirty);
        }
    }
@@ -203,7 +222,15 @@ class ViewOverlay extends ViewGroup implements Overlay {
    @Override
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
        if (mHostView != null) {
            mHostView.invalidate(dirty);
            dirty.offset(location[0], location[1]);
            if (mHostView instanceof ViewGroup) {
                location[0] = 0;
                location[1] = 0;
                super.invalidateChildInParent(location, dirty);
                return ((ViewGroup) mHostView).invalidateChildInParent(location, dirty);
            } else {
                invalidate(dirty);
            }
        }
        return null;
    }