Loading core/java/android/view/ViewGroup.java +98 −31 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -1572,6 +1578,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager break; break; } } } } if (preorderedList != null) preorderedList.clear(); } } } } Loading Loading @@ -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. Loading Loading @@ -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; Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -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) { Loading Loading @@ -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; Loading tests/HwAccelerationTest/AndroidManifest.xml +9 −0 Original line number Original line Diff line number Diff line Loading @@ -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> tests/HwAccelerationTest/res/layout/z_ordering.xml 0 → 100644 +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 tests/HwAccelerationTest/res/values/styles.xml +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> tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java 0 → 100644 +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); } } } } Loading
core/java/android/view/ViewGroup.java +98 −31 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -1572,6 +1578,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager break; break; } } } } if (preorderedList != null) preorderedList.clear(); } } } } Loading Loading @@ -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. Loading Loading @@ -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; Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -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) { Loading Loading @@ -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; Loading
tests/HwAccelerationTest/AndroidManifest.xml +9 −0 Original line number Original line Diff line number Diff line Loading @@ -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>
tests/HwAccelerationTest/res/layout/z_ordering.xml 0 → 100644 +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
tests/HwAccelerationTest/res/values/styles.xml +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>
tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java 0 → 100644 +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); } } } }