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

Commit edf6f4b4 authored by Chet Haase's avatar Chet Haase
Browse files

Make adding views specific to a ViewGroup's overlay

Adding views to views (possible with the new Overlay API) is weird.
This change moves the view-management facilities of Overlay to a subclass
that is specific to the overlay returned from ViewGroup.getOverlay().
So now you can add drawables to all view overlays, but only add/remove
views to/from the overlay returned from ViewGroup.getOverlay().

Also, the previous approach of using an interface for Overlay was
changed to classes for both ViewOverlay and ViewGroupOverlay.

Finally, this change makes not handling touch correctly the proper,
and documented, behavior of overlay views. There are various tricky issues
to sort out with input in overlays (including click handling as well as focus)
and we don't want developers starting to use overlays as some kind of general
container hierarchy, so we're purposely constraining overlays to have visual-only
behavior.

Issue #8459085 Overlay needs to handle touch correctly

Change-Id: I207b8dbf528f87c92369d270d8b0a6556826d207
parent a56b78dc
Loading
Loading
Loading
Loading
+12 −9
Original line number Original line Diff line number Diff line
@@ -24966,14 +24966,6 @@ package android.view {
    field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
    field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
  }
  }
  public abstract interface Overlay {
    method public abstract void add(android.graphics.drawable.Drawable);
    method public abstract void add(android.view.View);
    method public abstract void clear();
    method public abstract void remove(android.graphics.drawable.Drawable);
    method public abstract void remove(android.view.View);
  }
  public class ScaleGestureDetector {
  public class ScaleGestureDetector {
    ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener);
    ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener);
    method public float getCurrentSpan();
    method public float getCurrentSpan();
@@ -25278,7 +25270,7 @@ package android.view {
    method public int getNextFocusUpId();
    method public int getNextFocusUpId();
    method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
    method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
    method public int getOverScrollMode();
    method public int getOverScrollMode();
    method public android.view.Overlay getOverlay();
    method public android.view.ViewOverlay getOverlay();
    method public int getPaddingBottom();
    method public int getPaddingBottom();
    method public int getPaddingEnd();
    method public int getPaddingEnd();
    method public int getPaddingLeft();
    method public int getPaddingLeft();
@@ -26019,12 +26011,23 @@ package android.view {
    method public abstract void onChildViewRemoved(android.view.View, android.view.View);
    method public abstract void onChildViewRemoved(android.view.View, android.view.View);
  }
  }
  public class ViewGroupOverlay extends android.view.ViewOverlay {
    method public void add(android.view.View);
    method public void remove(android.view.View);
  }
  public abstract interface ViewManager {
  public abstract interface ViewManager {
    method public abstract void addView(android.view.View, android.view.ViewGroup.LayoutParams);
    method public abstract void addView(android.view.View, android.view.ViewGroup.LayoutParams);
    method public abstract void removeView(android.view.View);
    method public abstract void removeView(android.view.View);
    method public abstract void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
    method public abstract void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
  }
  }
  public class ViewOverlay {
    method public void add(android.graphics.drawable.Drawable);
    method public void clear();
    method public void remove(android.graphics.drawable.Drawable);
  }
  public abstract interface ViewParent {
  public abstract interface ViewParent {
    method public abstract void bringChildToFront(android.view.View);
    method public abstract void bringChildToFront(android.view.View);
    method public abstract void childDrawableStateChanged(android.view.View);
    method public abstract void childDrawableStateChanged(android.view.View);
+1 −1
Original line number Original line Diff line number Diff line
@@ -18,7 +18,7 @@ package android.animation;
import android.graphics.Rect;
import android.graphics.Rect;


/**
/**
 * This evaluator can be used to perform type interpolation between <code>int</code> values.
 * This evaluator can be used to perform type interpolation between <code>Rect</code> values.
 */
 */
public class RectEvaluator implements TypeEvaluator<Rect> {
public class RectEvaluator implements TypeEvaluator<Rect> {


+17 −27
Original line number Original line Diff line number Diff line
@@ -12107,7 +12107,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        //System.out.println("Attached! " + this);
        //System.out.println("Attached! " + this);
        mAttachInfo = info;
        mAttachInfo = info;
        if (mOverlay != null) {
        if (mOverlay != null) {
            mOverlay.dispatchAttachedToWindow(info, visibility);
            mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
        }
        }
        mWindowAttachCount++;
        mWindowAttachCount++;
        // We will need to evaluate the drawable state at least once.
        // We will need to evaluate the drawable state at least once.
@@ -12178,7 +12178,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        mAttachInfo = null;
        mAttachInfo = null;
        if (mOverlay != null) {
        if (mOverlay != null) {
            mOverlay.dispatchDetachedFromWindow();
            mOverlay.getOverlayView().dispatchDetachedFromWindow();
        }
        }
    }
    }
@@ -12831,7 +12831,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                    if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                    if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                        dispatchDraw(canvas);
                        dispatchDraw(canvas);
                        if (mOverlay != null && !mOverlay.isEmpty()) {
                        if (mOverlay != null && !mOverlay.isEmpty()) {
                            mOverlay.draw(canvas);
                            mOverlay.getOverlayView().draw(canvas);
                        }
                        }
                    } else {
                    } else {
                        draw(canvas);
                        draw(canvas);
@@ -13147,7 +13147,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                dispatchDraw(canvas);
                dispatchDraw(canvas);
                if (mOverlay != null && !mOverlay.isEmpty()) {
                if (mOverlay != null && !mOverlay.isEmpty()) {
                    mOverlay.draw(canvas);
                    mOverlay.getOverlayView().draw(canvas);
                }
                }
            } else {
            } else {
                draw(canvas);
                draw(canvas);
@@ -13905,7 +13905,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            onDrawScrollBars(canvas);
            onDrawScrollBars(canvas);
            if (mOverlay != null && !mOverlay.isEmpty()) {
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.dispatchDraw(canvas);
                mOverlay.getOverlayView().dispatchDraw(canvas);
            }
            }
            // we're done...
            // we're done...
@@ -14049,34 +14049,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        onDrawScrollBars(canvas);
        onDrawScrollBars(canvas);
        if (mOverlay != null && !mOverlay.isEmpty()) {
        if (mOverlay != null && !mOverlay.isEmpty()) {
            mOverlay.dispatchDraw(canvas);
            mOverlay.getOverlayView().dispatchDraw(canvas);
        }
        }
    }
    }
    /**
    /**
     * Called by the addToOverlay() methods to create, attach, and size the overlay as necessary
     * Returns the overlay for this view, creating it if it does not yet exist.
     * Adding drawables to the overlay will cause them to be displayed whenever
     * the view itself is redrawn. Objects in the overlay should be actively
     * managed: remove them when they should not be displayed anymore. The
     * overlay will always have the same size as its host view.
     *
     * @return The ViewOverlay object for this view.
     * @see ViewOverlay
     */
     */
    private void setupOverlay() {
    public ViewOverlay getOverlay() {
        if (mOverlay == null) {
        if (mOverlay == null) {
            mOverlay = new ViewOverlay(mContext, this);
            mOverlay = new ViewOverlay(mContext, this);
            mOverlay.mAttachInfo = mAttachInfo;
            mOverlay.setRight(mRight);
            mOverlay.setBottom(mBottom);
        }
        }
        }
    /**
     * Returns the overlay for this view, creating it if it does not yet exist. Adding drawables
     * and/or views to the overlay will cause them to be displayed whenever the view itself is
     * redrawn. Objects in the overlay should be actively managed: remove them when they should
     * not be displayed anymore and invalidate this view appropriately when overlay drawables
     * change. The overlay will always have the same size as its host view.
     *
     * @return The Overlay object for this view.
     * @see Overlay
     */
    public Overlay getOverlay() {
        setupOverlay();
        return mOverlay;
        return mOverlay;
    }
    }
@@ -14360,8 +14350,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) {
    private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) {
        onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
        onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
        if (mOverlay != null) {
        if (mOverlay != null) {
            mOverlay.setRight(mRight);
            mOverlay.getOverlayView().setRight(newWidth);
            mOverlay.setBottom(mBottom);
            mOverlay.getOverlayView().setBottom(newHeight);
        }
        }
    }
    }
+27 −30
Original line number Original line Diff line number Diff line
@@ -1876,34 +1876,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                    // have become out of sync.
                    // have become out of sync.
                    removePointersFromTouchTargets(idBitsToAssign);
                    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;
                    final int childrenCount = mChildrenCount;
                    if (newTouchTarget == null && childrenCount != 0) {
                    if (newTouchTarget == null && childrenCount != 0) {
                        final float x = ev.getX(actionIndex);
                        final float y = ev.getY(actionIndex);
                        // Find a child that can receive the event.
                        // Find a child that can receive the event.
                        // Scan children from front to back.
                        // Scan children from front to back.
                        final View[] children = mChildren;
                        final View[] children = mChildren;
@@ -2990,6 +2966,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        }
        }
    }
    }


    /**
     * Returns the ViewGroupOverlay for this view group, creating it if it does
     * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
     * {@link ViewGroupOverlay} allows views to be added to the overlay. These
     * views, like overlay drawables, are visual-only; they do not receive input
     * events and should not be used as anything other than a temporary
     * representation of a view in a parent container, such as might be used
     * by an animation effect.
     *
     * @return The ViewGroupOverlay object for this view.
     * @see ViewGroupOverlay
     */
    @Override
    public ViewGroupOverlay getOverlay() {
        if (mOverlay == null) {
            mOverlay = new ViewGroupOverlay(mContext, this);
        }
        return (ViewGroupOverlay) mOverlay;
    }

    /**
    /**
     * Returns the index of the child to draw for this iteration. Override this
     * Returns the index of the child to draw for this iteration. Override this
     * if you want to change the drawing order of children. By default, it
     * if you want to change the drawing order of children. By default, it
@@ -3055,11 +3051,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            }
            }
        }
        }
        if (mOverlay != null) {
        if (mOverlay != null) {
            mOverlay.mRecreateDisplayList = (mOverlay.mPrivateFlags & PFLAG_INVALIDATED)
            View overlayView = mOverlay.getOverlayView();
            overlayView.mRecreateDisplayList = (overlayView.mPrivateFlags & PFLAG_INVALIDATED)
                    == PFLAG_INVALIDATED;
                    == PFLAG_INVALIDATED;
            mOverlay.mPrivateFlags &= ~PFLAG_INVALIDATED;
            overlayView.mPrivateFlags &= ~PFLAG_INVALIDATED;
            mOverlay.getDisplayList();
            overlayView.getDisplayList();
            mOverlay.mRecreateDisplayList = false;
            overlayView.mRecreateDisplayList = false;
        }
        }
    }
    }


+27 −33
Original line number Original line Diff line number Diff line
@@ -15,43 +15,37 @@
 */
 */
package android.view;
package android.view;


import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;


/**
/**
 * An overlay is an extra layer that sits on top of a View (the "host view")
 * A group overlay is an extra layer that sits on top of a ViewGroup
 * which is drawn after all other content in that view (including children,
 * (the "host view") which is drawn after all other content in that view
 * if the view is a ViewGroup). Interaction with the overlay layer is done in
 * (including the view group's children). Interaction with the overlay
 * terms of adding/removing views and drawables.
 * layer is done by adding and removing views and drawables.
 *
 *
 * @see android.view.View#getOverlay()
 * <p>ViewGroupOverlay is a subclass of {@link ViewOverlay}, adding the ability to
 */
 * manage views for overlays on ViewGroups, in addition to the drawable
public interface Overlay {
 * support in ViewOverlay.</p>

    /**
     * Adds a Drawable to the overlay. The bounds of the drawable should be relative to
     * the host view. Any drawable added to the overlay should be removed when it is no longer
     * needed or no longer visible.
 *
 *
     * @param drawable The Drawable to be added to the overlay. This drawable will be
 * @see ViewGroup#getOverlay()
     * drawn when the view redraws its overlay.
     * @see #remove(android.graphics.drawable.Drawable)
     * @see #add(View)
 */
 */
    void add(Drawable drawable);
public class ViewGroupOverlay extends ViewOverlay {


    /**
    ViewGroupOverlay(Context context, View hostView) {
     * Removes the specified Drawable from the overlay.
        super(context, hostView);
     *
    }
     * @param drawable The Drawable to be removed from the overlay.
     * @see #add(android.graphics.drawable.Drawable)
     */
    void remove(Drawable drawable);


    /**
    /**
     * Adds a View to the overlay. The bounds of the added view should be
     * 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
     * relative to the host view. Any view added to the overlay should be
     * removed when it is no longer needed or no longer visible.
     * removed when it is no longer needed or no longer visible.
     *
     *
     * <p>Views in the overlay are visual-only; they do not receive input
     * events and do not participate in focus traversal. Overlay views
     * are intended to be transient, such as might be needed by a temporary
     * animation effect.</p>
     *
     * <p>If the view has a parent, the view will be removed from that parent
     * <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
     * 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
     * such that it is in the same relative location inside the activity. For
@@ -62,20 +56,20 @@ public interface Overlay {
     * @param view The View to be added to the overlay. The added view will be
     * @param view The View to be added to the overlay. The added view will be
     * drawn when the overlay is drawn.
     * drawn when the overlay is drawn.
     * @see #remove(View)
     * @see #remove(View)
     * @see #add(android.graphics.drawable.Drawable)
     * @see ViewOverlay#add(Drawable)
     */
     */
    void add(View view);
    public void add(View view) {
        mOverlayViewGroup.add(view);
    }


    /**
    /**
     * Removes the specified View from the overlay.
     * Removes the specified View from the overlay.
     *
     *
     * @param view The View to be removed from the overlay.
     * @param view The View to be removed from the overlay.
     * @see #add(View)
     * @see #add(View)
     * @see ViewOverlay#remove(Drawable)
     */
     */
    void remove(View view);
    public void remove(View view) {

        mOverlayViewGroup.remove(view);
    /**
    }
     * Removes all views and drawables from the overlay.
     */
    void clear();
}
}
Loading