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

Commit b08013c3 authored by Adam Powell's avatar Adam Powell
Browse files

Added overlay support for drawing/responding to text anchors.

Overlays let views draw and respond to touch events outside of their
bounds. This allows selection anchors to be friendlier and easier to
grab. This is currently private API, pending further evaluation.

Added themes/styles for text selection anchors.

Added assets for text selection anchors as provided by UX. The
left/right anchors are currently not suitable for use. They are here
for bookkeeping and replacement later. The theme currently uses the
'middle' anchor asset for all three. This will be changed once assets
are ready.

Change-Id: I01b21e5ae90cab201f86f38f2f5eeaf2bd7f6bcd
parent 838e93ed
Loading
Loading
Loading
Loading
+45 −34
Original line number Diff line number Diff line
@@ -5828,28 +5828,6 @@
 visibility="public"
>
</field>
<field name="kraken_resource_pad58"
 type="int"
 transient="false"
 volatile="false"
 value="16843463"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="kraken_resource_pad59"
 type="int"
 transient="false"
 volatile="false"
 value="16843462"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="kraken_resource_pad6"
 type="int"
 transient="false"
@@ -5861,17 +5839,6 @@
 visibility="public"
>
</field>
<field name="kraken_resource_pad60"
 type="int"
 transient="false"
 volatile="false"
 value="16843461"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="kraken_resource_pad7"
 type="int"
 transient="false"
@@ -9513,6 +9480,39 @@
 visibility="public"
>
</field>
<field name="textSelectHandle"
 type="int"
 transient="false"
 volatile="false"
 value="16843463"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="textSelectHandleLeft"
 type="int"
 transient="false"
 volatile="false"
 value="16843461"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="textSelectHandleRight"
 type="int"
 transient="false"
 volatile="false"
 value="16843462"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="textSize"
 type="int"
 transient="false"
@@ -223937,8 +223937,19 @@
 visibility="public"
>
</method>
<method name="isShowing"
 return="boolean"
 abstract="true"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="onTouchEvent"
 return="void"
 return="boolean"
 abstract="true"
 native="false"
 synchronized="false"
+57 −0
Original line number Diff line number Diff line
@@ -1550,6 +1550,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
     */
    private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;

    /**
     * Indicates that this view has a visible/touchable overlay.
     * @hide
     */
    static final int HAS_OVERLAY = 0x10000000;

    /**
     * Always allow a user to overscroll this view, provided it is a
     * view that can scroll.
@@ -2837,6 +2843,57 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
        resetPressedState();
    }

    /**
     * Enable or disable drawing overlays after a full drawing pass. This enables a view to
     * draw on a topmost overlay layer after normal drawing completes and get right of first
     * refusal for touch events in the window.
     * 
     * <em>Warning:</em> Views that use this feature should take care to disable/enable overlay
     * appropriately when they are attached/detached from their window. All overlays should be
     * disabled when detached.
     * 
     * @param enabled true if overlay drawing should be enabled for this view, false otherwise
     * 
     * @see #onDrawOverlay(Canvas)
     * 
     * @hide
     */
    protected void setOverlayEnabled(boolean enabled) {
        final boolean oldValue = (mPrivateFlags & HAS_OVERLAY) == HAS_OVERLAY;
        mPrivateFlags = (mPrivateFlags & ~HAS_OVERLAY) | (enabled ? HAS_OVERLAY : 0);
        if (enabled != oldValue) {
            final ViewParent parent = getParent();
            if (parent != null) {
                try {
                    parent.childOverlayStateChanged(this);
                } catch (AbstractMethodError e) {
                    Log.e(VIEW_LOG_TAG, "Could not propagate hasOverlay state", e);
                }
            }
        }
    }

    /**
     * @return true if this View has an overlay enabled.
     * 
     * @see #setOverlayEnabled(boolean)
     * @see #onDrawOverlay(Canvas)
     * 
     * @hide
     */
    public boolean isOverlayEnabled() {
        return (mPrivateFlags & HAS_OVERLAY) == HAS_OVERLAY;
    }

    /**
     * Override this method to draw on an overlay layer above all other views in the window
     * after the standard drawing pass is complete. This allows a view to draw outside its
     * normal boundaries.
     * @hide
     */
    public void onDrawOverlay(Canvas canvas) {
    }

    private void resetPressedState() {
        if ((mViewFlags & ENABLED_MASK) == DISABLED) {
            return;
+100 −1
Original line number Diff line number Diff line
@@ -227,6 +227,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
     */
    protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;

    /**
     * When set, at least one child of this ViewGroup will return true from hasOverlay.
     */
    private static final int FLAG_CHILD_HAS_OVERLAY = 0x100000;

    /**
     * Indicates which types of drawing caches are to be kept in memory.
     * This field should be made private, so it is hidden from the SDK.
@@ -854,6 +859,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                final int scrolledYInt = (int) scrolledYFloat;
                final View[] children = mChildren;
                final int count = mChildrenCount;

                // Check for children with overlays first. They don't rely on hit rects to determine
                // if they can accept a new touch event.
                if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) {
                    for (int i = count - 1; i >= 0; i--) {
                        final View child = children[i];
                        // Don't let children respond to events as an overlay during an animation.
                        if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                                && child.getAnimation() == null
                                && child.isOverlayEnabled()) {
                            // offset the event to the view's coordinate system
                            final float xc = scrolledXFloat - child.mLeft;
                            final float yc = scrolledYFloat - child.mTop;
                            ev.setLocation(xc, yc);
                            child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
                            if (child.dispatchTouchEvent(ev))  {
                                // Event handled, we have a target now.
                                mMotionTarget = child;
                                return true;
                            }
                            // The event didn't get handled, try the next view.
                            // Don't reset the event's location, it's not
                            // necessary here.
                        }
                    }
                }

                // Now check views normally.
                for (int i = count - 1; i >= 0; i--) {
                    final View child = children[i];
                    if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
@@ -2312,6 +2345,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        if (clearChildFocus != null) {
            clearChildFocus(clearChildFocus);
        }

        mGroupFlags &= ~FLAG_CHILD_HAS_OVERLAY;
    }

    /**
@@ -2534,7 +2569,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                final int left = mLeft;
                final int top = mTop;

                if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
                if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY ||
                        dirty.intersect(0, 0, mRight - left, mBottom - top) ||
                        (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
                    mPrivateFlags &= ~DRAWING_CACHE_VALID;

@@ -3452,6 +3488,69 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        mAnimationListener = animationListener;
    }

    /**
     * Called when a child's overlay state changes between enabled/disabled.
     * @param child Child view whose state has changed or null
     * @hide
     */
    public void childOverlayStateChanged(View child) {
        boolean childHasOverlay = false;
        if (child != null) {
            childHasOverlay = child.isOverlayEnabled();
        } else {
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                if (childHasOverlay |= getChildAt(i).isOverlayEnabled()) {
                    break;
                }
            }
        }
        
        final boolean hasChildWithOverlay = childHasOverlay ||
                (mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY;

        final boolean oldValue = isOverlayEnabled();
        mGroupFlags = (mGroupFlags & ~FLAG_CHILD_HAS_OVERLAY) |
                (hasChildWithOverlay ? FLAG_CHILD_HAS_OVERLAY : 0);
        if (isOverlayEnabled() != oldValue) {
            final ViewParent parent = getParent();
            if (parent != null) {
                try {
                    parent.childOverlayStateChanged(this);
                } catch (AbstractMethodError e) {
                    Log.e("ViewGroup", "Could not propagate hasOverlay state", e);
                }
            }
        }
    }

    /**
     * @hide
     */
    public boolean isOverlayEnabled() {
        return super.isOverlayEnabled() ||
                ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY);
    }

    /**
     * @hide
     */
    @Override
    public void onDrawOverlay(Canvas canvas) {
        if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) {
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = getChildAt(i);
                if (child.isOverlayEnabled()) {
                    canvas.translate(child.mLeft + child.mScrollX, child.mTop + child.mScrollY);
                    child.onDrawOverlay(canvas);
                    canvas.translate(-(child.mLeft + child.mScrollX),
                            -(child.mTop + child.mScrollY));
                }
            }
        }
    }

    /**
     * LayoutParams are used by views to tell their parents how they want to be
     * laid out. See
+7 −0
Original line number Diff line number Diff line
@@ -208,4 +208,11 @@ public interface ViewParent {
     */
    public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
            boolean immediate);

    /**
     * Called when a child view's overlay state changes between enabled/disabled.
     * @param child Child view whose state changed or null.
     * @hide
     */
    public void childOverlayStateChanged(View child);
}
+18 −0
Original line number Diff line number Diff line
@@ -222,6 +222,8 @@ public final class ViewRoot extends Handler implements ViewParent,

    private final int mDensity;
    
    private boolean mHasOverlay;

    public static IWindowSession getWindowSession(Looper mainLooper) {
        synchronized (mStaticInit) {
            if (!mInitialized) {
@@ -1518,6 +1520,9 @@ public final class ViewRoot extends Handler implements ViewParent,
                        canvas.setScreenDensity(scalingRequired
                                ? DisplayMetrics.DENSITY_DEVICE : 0);
                        mView.draw(canvas);
                        if (mHasOverlay) {
                            mView.onDrawOverlay(canvas);
                        }
                    } finally {
                        mAttachInfo.mIgnoreDirtyState = false;
                        canvas.restoreToCount(saveCount);
@@ -2914,6 +2919,19 @@ public final class ViewRoot extends Handler implements ViewParent,
        return scrollToRectOrFocus(rectangle, immediate);
    }

    /**
     * @hide
     */
    public void childOverlayStateChanged(View child) {
        final boolean oldState = mHasOverlay;
        mHasOverlay = child.isOverlayEnabled();
        // Invalidate the whole thing when we change overlay states just in case
        // something left chunks of data drawn someplace it shouldn't have.
        if (mHasOverlay != oldState) {
            child.invalidate();
        }
    }

    class TakenSurfaceHolder extends BaseSurfaceHolder {
        @Override
        public boolean onAllowLockCanvas() {
Loading