From f8da30dc65b833558a4eb654f7d80dfdd60d844a Mon Sep 17 00:00:00 2001 From: Teng-Hui Zhu Date: Mon, 15 Aug 2016 10:28:20 -0700 Subject: [PATCH] Correctly report the transparent region First, we fix the transparent region computation to use the order as the drawing. Previously, it is using the tree traverse order, not the draw order. Second, add the y offset for any view with positive z value, this will allow some space for shadow. b/30124573 Change-Id: I98d38261ffd346b762651e087cb243e45fed6952 --- core/java/android/view/View.java | 10 ++++++++-- core/java/android/view/ViewGroup.java | 26 +++++++++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index e7553ec943ece..329984972ec31 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -20269,8 +20269,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // remove it from the transparent region. final int[] location = attachInfo.mTransparentLocation; getLocationInWindow(location); - region.op(location[0], location[1], location[0] + mRight - mLeft, - location[1] + mBottom - mTop, Region.Op.DIFFERENCE); + // When a view has Z value, then it will be better to leave some area below the view + // for drawing shadow. The shadow outset is proportional to the Z value. Note that + // the bottom part needs more offset than the left, top and right parts due to the + // spot light effects. + int shadowOffset = getZ() > 0 ? (int) getZ() : 0; + region.op(location[0] - shadowOffset, location[1] - shadowOffset, + location[0] + mRight - mLeft + shadowOffset, + location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); } else { if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { // The SKIP_DRAW flag IS set and the background drawable exists, we remove diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 3ff8d4f2e2b1b..6933efc15b683 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -6406,16 +6406,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return true; } super.gatherTransparentRegion(region); - final View[] children = mChildren; - final int count = mChildrenCount; + // Instead of naively traversing the view tree, we have to traverse according to the Z + // order here. We need to go with the same order as dispatchDraw(). + // One example is that after surfaceView punch a hole, we will still allow other views drawn + // on top of that hole. In this case, those other views should be able to cut the + // transparent region into smaller area. + final int childrenCount = mChildrenCount; boolean noneOfTheChildrenAreTransparent = true; - for (int i = 0; i < count; i++) { - final View child = children[i]; - if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { - if (!child.gatherTransparentRegion(region)) { - noneOfTheChildrenAreTransparent = false; + if (childrenCount > 0) { + final ArrayList preorderedList = buildOrderedChildList(); + final boolean customOrder = preorderedList == null + && isChildrenDrawingOrderEnabled(); + final View[] children = mChildren; + for (int i = 0; i < childrenCount; i++) { + final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); + if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { + if (!child.gatherTransparentRegion(region)) { + noneOfTheChildrenAreTransparent = false; + } } } + if (preorderedList != null) preorderedList.clear(); } return meOpaque || noneOfTheChildrenAreTransparent; }