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

Commit 80d55ba8 authored by Chris Craik's avatar Chris Craik Committed by Android Git Automerger
Browse files

am 9ecf9b12: Merge "Respect Z ordering in touch dispatch, software drawing" into lmp-preview-dev

* commit '9ecf9b1292d547aebe4588f1051b22f9683e2149':
  Respect Z ordering in touch dispatch, software drawing
parents 2fb43485 b8a09134
Loading
Loading
Loading
Loading
+98 −31
Original line number Original line Diff line number Diff line
@@ -456,6 +456,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    // views during a transition when they otherwise would have become gone/invisible
    // views during a transition when they otherwise would have become gone/invisible
    private ArrayList<View> mVisibilityChangingChildren;
    private ArrayList<View> mVisibilityChangingChildren;


    // Temporary holder of presorted children, only used for
    // input/software draw dispatch for correctly Z ordering.
    private ArrayList<View> mPreSortedChildren;

    // Indicates how many of this container's child subtrees contain transient state
    // Indicates how many of this container's child subtrees contain transient state
    @ViewDebug.ExportedProperty(category = "layout")
    @ViewDebug.ExportedProperty(category = "layout")
    private int mChildCountWithTransientState = 0;
    private int mChildCountWithTransientState = 0;
@@ -1499,13 +1503,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            final float y = event.getY();
            final float y = event.getY();
            final int childrenCount = mChildrenCount;
            final int childrenCount = mChildrenCount;
            if (childrenCount != 0) {
            if (childrenCount != 0) {
                final boolean customChildOrder = isChildrenDrawingOrderEnabled();
                final ArrayList<View> preorderedList = buildOrderedChildList();
                final boolean customOrder = preorderedList == null
                        && isChildrenDrawingOrderEnabled();
                final View[] children = mChildren;
                final View[] children = mChildren;
                HoverTarget lastHoverTarget = null;
                HoverTarget lastHoverTarget = null;
                for (int i = childrenCount - 1; i >= 0; i--) {
                for (int i = childrenCount - 1; i >= 0; i--) {
                    final int childIndex = customChildOrder
                    int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
                            ? getChildDrawingOrder(childrenCount, i) : i;
                    final View child = (preorderedList == null)
                    final View child = children[childIndex];
                            ? children[childIndex] : preorderedList.get(childIndex);
                    if (!canViewReceivePointerEvents(child)
                    if (!canViewReceivePointerEvents(child)
                            || !isTransformedTouchPointInView(x, y, child, null)) {
                            || !isTransformedTouchPointInView(x, y, child, null)) {
                        continue;
                        continue;
@@ -1572,6 +1578,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                        break;
                        break;
                    }
                    }
                }
                }
                if (preorderedList != null) preorderedList.clear();
            }
            }
        }
        }


@@ -1778,23 +1785,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        // Send the event to the child under the pointer.
        // Send the event to the child under the pointer.
        final int childrenCount = mChildrenCount;
        final int childrenCount = mChildrenCount;
        if (childrenCount != 0) {
        if (childrenCount != 0) {
            final View[] children = mChildren;
            final float x = event.getX();
            final float x = event.getX();
            final float y = event.getY();
            final float y = event.getY();


            final boolean customOrder = isChildrenDrawingOrderEnabled();
            final ArrayList<View> preorderedList = buildOrderedChildList();
            final boolean customOrder = preorderedList == null
                    && isChildrenDrawingOrderEnabled();
            final View[] children = mChildren;
            for (int i = childrenCount - 1; i >= 0; i--) {
            for (int i = childrenCount - 1; i >= 0; i--) {
                final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
                int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
                final View child = children[childIndex];
                final View child = (preorderedList == null)
                        ? children[childIndex] : preorderedList.get(childIndex);
                if (!canViewReceivePointerEvents(child)
                if (!canViewReceivePointerEvents(child)
                        || !isTransformedTouchPointInView(x, y, child, null)) {
                        || !isTransformedTouchPointInView(x, y, child, null)) {
                    continue;
                    continue;
                }
                }


                if (dispatchTransformedGenericPointerEvent(event, child)) {
                if (dispatchTransformedGenericPointerEvent(event, child)) {
                    if (preorderedList != null) preorderedList.clear();
                    return true;
                    return true;
                }
                }
            }
            }
            if (preorderedList != null) preorderedList.clear();
        }
        }


        // No child handled the event.  Send it to this view group.
        // No child handled the event.  Send it to this view group.
@@ -1910,13 +1922,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                        final float y = ev.getY(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 ArrayList<View> preorderedList = buildOrderedChildList();
                        final boolean customOrder = preorderedList == null
                                && isChildrenDrawingOrderEnabled();
                        final View[] children = mChildren;
                        final View[] children = mChildren;

                        final boolean customOrder = isChildrenDrawingOrderEnabled();
                        for (int i = childrenCount - 1; i >= 0; i--) {
                        for (int i = childrenCount - 1; i >= 0; i--) {
                            final int childIndex = customOrder ?
                            final int childIndex = customOrder
                                    getChildDrawingOrder(childrenCount, i) : i;
                                    ? getChildDrawingOrder(childrenCount, i) : i;
                            final View child = children[childIndex];
                            final View child = (preorderedList == null)
                                    ? children[childIndex] : preorderedList.get(childIndex);
                            if (!canViewReceivePointerEvents(child)
                            if (!canViewReceivePointerEvents(child)
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                continue;
                                continue;
@@ -1934,7 +1948,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                // Child wants to receive touch within its bounds.
                                // Child wants to receive touch within its bounds.
                                mLastTouchDownTime = ev.getDownTime();
                                mLastTouchDownTime = ev.getDownTime();
                                if (preorderedList != null) {
                                    // childIndex points into presorted list, find original index
                                    for (int j = 0; j < childrenCount; j++) {
                                        if (children[childIndex] == mChildren[j]) {
                                            mLastTouchDownIndex = j;
                                            break;
                                        }
                                    }
                                } else {
                                    mLastTouchDownIndex = childIndex;
                                    mLastTouchDownIndex = childIndex;
                                }
                                mLastTouchDownX = ev.getX();
                                mLastTouchDownX = ev.getX();
                                mLastTouchDownY = ev.getY();
                                mLastTouchDownY = ev.getY();
                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
@@ -1942,6 +1966,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                                break;
                                break;
                            }
                            }
                        }
                        }
                        if (preorderedList != null) preorderedList.clear();
                    }
                    }


                    if (newTouchTarget == null && mFirstTouchTarget != null) {
                    if (newTouchTarget == null && mFirstTouchTarget != null) {
@@ -2928,7 +2953,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
     */
     */
    @Override
    @Override
    protected void dispatchDraw(Canvas canvas) {
    protected void dispatchDraw(Canvas canvas) {
        final int count = mChildrenCount;
        final int childrenCount = mChildrenCount;
        final View[] children = mChildren;
        final View[] children = mChildren;
        int flags = mGroupFlags;
        int flags = mGroupFlags;


@@ -2936,11 +2961,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;


            final boolean buildCache = !isHardwareAccelerated();
            final boolean buildCache = !isHardwareAccelerated();
            for (int i = 0; i < count; i++) {
            for (int i = 0; i < childrenCount; i++) {
                final View child = children[i];
                final View child = children[i];
                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
                    final LayoutParams params = child.getLayoutParams();
                    final LayoutParams params = child.getLayoutParams();
                    attachLayoutAnimationParameters(child, params, i, count);
                    attachLayoutAnimationParameters(child, params, i, childrenCount);
                    bindLayoutAnimation(child);
                    bindLayoutAnimation(child);
                    if (cache) {
                    if (cache) {
                        child.setDrawingCacheEnabled(true);
                        child.setDrawingCacheEnabled(true);
@@ -2997,21 +3022,22 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        boolean more = false;
        boolean more = false;
        final long drawingTime = getDrawingTime();
        final long drawingTime = getDrawingTime();


        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {

            for (int i = 0; i < count; i++) {
        // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
                final View child = children[i];
        // draw reordering internally
                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
        final ArrayList<View> preorderedList = canvas.isHardwareAccelerated()
                    more |= drawChild(canvas, child, drawingTime);
                ? null : buildOrderedChildList();
                }
        final boolean customOrder = preorderedList == null
            }
                && isChildrenDrawingOrderEnabled();
        } else {
        for (int i = 0; i < childrenCount; i++) {
            for (int i = 0; i < count; i++) {
            int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
                final View child = children[getChildDrawingOrder(count, i)];
            final View child = (preorderedList == null)
                    ? children[childIndex] : preorderedList.get(childIndex);
            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
                more |= drawChild(canvas, child, drawingTime);
                more |= drawChild(canvas, child, drawingTime);
            }
            }
        }
        }
        }
        if (preorderedList != null) preorderedList.clear();


        // Draw any disappearing views that have animations
        // Draw any disappearing views that have animations
        if (mDisappearingChildren != null) {
        if (mDisappearingChildren != null) {
@@ -3096,6 +3122,47 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        return i;
        return i;
    }
    }


    private boolean hasChildWithZ() {
        for (int i = 0; i < mChildrenCount; i++) {
            if (mChildren[i].getZ() != 0) return true;
        }
        return false;
    }

    /**
     * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
     * sorted first by Z, then by child drawing order (if applicable).
     *
     * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
     * children.
     */
    private ArrayList<View> buildOrderedChildList() {
        final int count = mChildrenCount;
        if (count <= 1 || !hasChildWithZ()) return null;

        if (mPreSortedChildren == null) {
            mPreSortedChildren = new ArrayList<View>(count);
        } else {
            mPreSortedChildren.ensureCapacity(count);
        }

        final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
        for (int i = 0; i < mChildrenCount; i++) {
            // add next child (in child order) to end of list
            int childIndex = useCustomOrder ? getChildDrawingOrder(mChildrenCount, i) : i;
            View nextChild = mChildren[childIndex];
            float currentZ = nextChild.getZ();

            // insert ahead of any Views with greater Z
            int insertIndex = i;
            while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
                insertIndex--;
            }
            mPreSortedChildren.add(insertIndex, nextChild);
        }
        return mPreSortedChildren;
    }

    private void notifyAnimationListener() {
    private void notifyAnimationListener() {
        mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
        mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
        mGroupFlags |= FLAG_ANIMATION_DONE;
        mGroupFlags |= FLAG_ANIMATION_DONE;
+9 −0
Original line number Original line Diff line number Diff line
@@ -902,5 +902,14 @@
                <category android:name="com.android.test.hwui.TEST" />
                <category android:name="com.android.test.hwui.TEST" />
            </intent-filter>
            </intent-filter>
        </activity>
        </activity>

        <activity
                android:name=".ZOrderingActivity"
                android:label="Reordering/Z Ordering">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="com.android.test.hwui.TEST" />
            </intent-filter>
        </activity>
    </application>
    </application>
</manifest>
</manifest>
+17 −0
Original line number Original line Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:id="@+id/parent">
    <RelativeLayout
            android:layout_width="400dp"
            android:layout_height="200dp"
            android:layout_weight="1"
            android:orientation="vertical">
        <TextView style="@style/TopLeftReorderTextView"/>
        <TextView style="@style/BottomLeftReorderTextView"/>
        <TextView style="@style/TopRightReorderTextView"/>
        <TextView style="@style/BottomRightReorderTextView"/>
    </RelativeLayout>
</LinearLayout>
 No newline at end of file
+14 −11
Original line number Original line Diff line number Diff line
<resources>
<resources>
    <style name="ReorderTextView" parent="@android:style/TextAppearance.Medium">
    <style name="ReorderTextView" parent="@android:style/TextAppearance.Medium">
        <item name="android:layout_width">match_parent</item>
        <item name="android:background">@drawable/appwidget_background</item>
        <item name="android:layout_width">300dp</item>
        <item name="android:layout_height">100dp</item>
        <item name="android:layout_height">100dp</item>
        <item name="android:gravity">center</item>
        <item name="android:gravity">center</item>
    </style>
    </style>
    <style name="LeftReorderTextView" parent="@style/ReorderTextView">
    <style name="LeftReorderTextView" parent="@style/ReorderTextView">
        <item name="android:translationX">20dp</item>
        <item name="android:translationX">50dp</item>
        <item name="android:layout_alignParentLeft">true</item>
    </style>
    </style>
    <style name="RightReorderTextView" parent="@style/ReorderTextView">
    <style name="RightReorderTextView" parent="@style/ReorderTextView">
        <item name="android:translationX">-20dp</item>
        <item name="android:translationX">-50dp</item>
        <item name="android:layout_alignParentRight">true</item>
    </style>
    </style>


    <style name="TopLeftReorderTextView" parent="@style/LeftReorderTextView">
    <style name="TopLeftReorderTextView" parent="@style/LeftReorderTextView">
        <item name="android:background">#666</item>
        <item name="android:text">200</item>
        <item name="android:text">100</item>
        <item name="android:translationZ">200dp</item>
        <item name="android:translationZ">100dp</item>
        <item name="android:layout_alignParentTop">true</item>
    </style>
    </style>
    <style name="BottomLeftReorderTextView" parent="@style/LeftReorderTextView">
    <style name="BottomLeftReorderTextView" parent="@style/LeftReorderTextView">
        <item name="android:background">#bbb</item>
        <item name="android:text">300</item>
        <item name="android:text">300</item>
        <item name="android:translationZ">300dp</item>
        <item name="android:translationZ">300dp</item>
        <item name="android:layout_alignParentBottom">true</item>
    </style>
    </style>
    <style name="TopRightReorderTextView" parent="@style/RightReorderTextView">
    <style name="TopRightReorderTextView" parent="@style/RightReorderTextView">
        <item name="android:background">#888</item>
        <item name="android:text">100</item>
        <item name="android:text">200</item>
        <item name="android:translationZ">100dp</item>
        <item name="android:translationZ">200dp</item>
        <item name="android:layout_alignParentTop">true</item>
    </style>
    </style>
    <style name="BottomRightReorderTextView" parent="@style/RightReorderTextView">
    <style name="BottomRightReorderTextView" parent="@style/RightReorderTextView">
        <item name="android:background">#ccc</item>
        <item name="android:text">400</item>
        <item name="android:text">400</item>
        <item name="android:translationZ">400dp</item>
        <item name="android:translationZ">400dp</item>
        <item name="android:layout_alignParentBottom">true</item>
    </style>
    </style>
</resources>
</resources>
+28 −0
Original line number Original line Diff line number Diff line
package com.android.test.hwui;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

public class ZOrderingActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.z_ordering);

        ViewGroup grandParent = (ViewGroup) findViewById(R.id.parent);
        if (grandParent == null) throw new IllegalStateException();
        View.OnClickListener l = new View.OnClickListener() {
            @Override
            public void onClick(View v) {}
        };
        for (int i = 0; i < grandParent.getChildCount(); i++) {
            ViewGroup parent = (ViewGroup) grandParent.getChildAt(i);
            for (int j = 0; j < parent.getChildCount(); j++) {
                parent.getChildAt(j).setOnClickListener(l);
            }
        }
    }
}