Improved the clipping of notification groups

Groups now correctly respect the clipBottomAmount and
animations work much better when swiping things away.

Also removed the group measuring logic when expanding,
Since we're now not shrinking the first notification anymore!

This also fixed a bug where a child could be invisible

Test: Add group, swipe children away
Bug: 32437839
Bug: 33203156
Change-Id: I255aa9695086e64eb10c7dccdc6122d8a8572bb5
(cherry picked from commit b3dadccbc5c7040260a51a3e17efcb74aeec6a11)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index a1384dc..661cc3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1685,6 +1685,9 @@
         if (mGuts != null) {
             mGuts.setClipBottomAmount(clipBottomAmount);
         }
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setClipBottomAmount(clipBottomAmount);
+        }
     }
 
     public boolean isMaxExpandHeightInitialized() {
@@ -1863,9 +1866,6 @@
             super.applyToView(view);
             if (view instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-                if (this.isBottomClipped) {
-                    row.setClipToActualHeight(true);
-                }
                 row.applyChildrenState(mOverallState);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 4b95f07..91abc87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -41,7 +41,7 @@
                 outline.setRect(translation,
                         mClipTopAmount,
                         getWidth() + translation,
-                        Math.max(getActualHeight(), mClipTopAmount));
+                        Math.max(getActualHeight() - mClipBottomAmount, mClipTopAmount));
             } else {
                 outline.setRect(mOutlineRect);
             }
@@ -66,6 +66,12 @@
         invalidateOutline();
     }
 
+    @Override
+    public void setClipBottomAmount(int clipBottomAmount) {
+        super.setClipBottomAmount(clipBottomAmount);
+        invalidateOutline();
+    }
+
     protected void setOutlineAlpha(float alpha) {
         if (alpha != mOutlineAlpha) {
             mOutlineAlpha = alpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 0f5981b..37a900e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -38,7 +38,7 @@
     protected OnHeightChangedListener mOnHeightChangedListener;
     private int mActualHeight;
     protected int mClipTopAmount;
-    private float mClipBottomAmount;
+    protected int mClipBottomAmount;
     private boolean mDark;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
     private static Rect mClipRect = new Rect();
@@ -241,7 +241,7 @@
         return mClipTopAmount;
     }
 
-    public float getClipBottomAmount() {
+    public int getClipBottomAmount() {
         return mClipBottomAmount;
     }
 
@@ -354,11 +354,8 @@
     private void updateClipping() {
         if (mClipToActualHeight) {
             int top = getClipTopAmount();
-            if (top >= getActualHeight()) {
-                top = getActualHeight() - 1;
-            }
-            mClipRect.set(0, top, getWidth(), (int) (getActualHeight() + getExtraBottomPadding()
-                                - mClipBottomAmount));
+            mClipRect.set(0, top, getWidth(), Math.max(getActualHeight() + getExtraBottomPadding()
+                                - mClipBottomAmount, top));
             setClipBounds(mClipRect);
         } else {
             setClipBounds(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index add4764..680562a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -156,7 +156,6 @@
             mShelfState.alpha = 1.0f;
             mShelfState.belowSpeedBump = mAmbientState.getSpeedBumpIndex() == 0;
             mShelfState.shadowAlpha = 1.0f;
-            mShelfState.isBottomClipped = false;
             mShelfState.hideSensitive = false;
             mShelfState.xTranslation = getTranslationX();
             if (mNotGoneIndex != -1) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 2895890..03697b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -48,7 +48,7 @@
             return mAnimationFilter;
         }
     }.setDuration(200);
-    
+
     private static final AnimationProperties ADD_ICON_PROPERTIES = new AnimationProperties() {
         private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
index 58e6838..7854c98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
@@ -106,11 +106,6 @@
      */
     public int location;
 
-    /**
-     * Whether a child in a group is being clipped at the bottom.
-     */
-    public boolean isBottomClipped;
-
     @Override
     public void copyFrom(ViewState viewState) {
         super.copyFrom(viewState);
@@ -125,7 +120,6 @@
             clipTopAmount = svs.clipTopAmount;
             notGoneIndex = svs.notGoneIndex;
             location = svs.location;
-            isBottomClipped = svs.isBottomClipped;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 26e1342..b8f8cb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -76,6 +76,7 @@
     private NotificationViewWrapper mNotificationHeaderWrapper;
     private NotificationHeaderUtil mHeaderUtil;
     private ViewState mHeaderViewState;
+    private int mClipBottomAmount;
 
     public NotificationChildrenContainer(Context context) {
         this(context, null);
@@ -433,7 +434,6 @@
 
         boolean childrenExpanded = !mNotificationParent.isGroupExpansionChanging()
                 && mChildrenExpanded;
-        int parentHeight = parentState.height;
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
             if (!firstChild) {
@@ -457,20 +457,9 @@
 
             ExpandableViewState childState = resultState.getViewStateForView(child);
             int intrinsicHeight = child.getIntrinsicHeight();
-            if (childrenExpanded) {
-                // When a group is expanded and moving into bottom stack, the bottom visible child
-                // adjusts its height to move into it. Children after it are hidden.
-                if (updateChildStateForExpandedGroup(child, parentHeight, childState, yPosition)) {
-                    // Clipping might be deactivated if the view is transforming, however, clipping
-                    // the child into the bottom stack should take precedent over this.
-                    childState.isBottomClipped = true;
-                }
-            } else {
-                childState.hidden = false;
-                childState.height = intrinsicHeight;
-                childState.isBottomClipped = false;
-            }
+            childState.height = intrinsicHeight;
             childState.yTranslation = yPosition;
+            childState.hidden = false;
             // When the group is expanded, the children cast the shadows rather than the parent
             // so use the parent's elevation here.
             childState.zTranslation = childrenExpanded
@@ -601,6 +590,34 @@
         if (mHeaderViewState != null) {
             mHeaderViewState.applyToView(mNotificationHeader);
         }
+        updateChildrenClipping();
+    }
+
+    private void updateChildrenClipping() {
+        int childCount = mChildren.size();
+        int layoutEnd = mNotificationParent.getActualHeight() - mClipBottomAmount;
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+            float childTop = child.getTranslationY();
+            float childBottom = childTop + child.getActualHeight();
+            boolean visible = true;
+            int clipBottomAmount = 0;
+            if (childTop > layoutEnd) {
+                visible = false;
+            } else if (childBottom > layoutEnd) {
+                clipBottomAmount = (int) (childBottom - layoutEnd);
+            }
+
+            boolean isVisible = child.getVisibility() == VISIBLE;
+            if (visible != isVisible) {
+                child.setVisibility(visible ? VISIBLE : INVISIBLE);
+            }
+
+            child.setClipBottomAmount(clipBottomAmount);
+        }
     }
 
     /**
@@ -653,6 +670,7 @@
         if (mNotificationHeader != null) {
             mHeaderViewState.applyToView(mNotificationHeader);
         }
+        updateChildrenClipping();
     }
 
     public ExpandableNotificationRow getViewAtPosition(float y) {
@@ -889,4 +907,9 @@
             }
         }
     }
+
+    public void setClipBottomAmount(int clipBottomAmount) {
+        mClipBottomAmount = clipBottomAmount;
+        updateChildrenClipping();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 522e4a9..e8e3adb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -766,12 +766,14 @@
      */
     private float getAppearEndPosition() {
         int appearPosition;
+        int minNotificationsForShelf = 1;
         if (mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) {
             appearPosition = mHeadsUpManager.getTopHeadsUpPinnedHeight();
+            minNotificationsForShelf = 2;
         } else {
-            appearPosition = getFirstItemMinHeight();
+            appearPosition = 0;
         }
-        if (getNotGoneChildCount() > 1) {
+        if (getNotGoneChildCount() >= minNotificationsForShelf) {
             appearPosition += mShelf.getIntrinsicHeight();
         }
         return appearPosition + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
@@ -1092,29 +1094,7 @@
 
     @Override
     public int getMaxExpandHeight(ExpandableView view) {
-        int maxContentHeight = view.getMaxContentHeight();
-        if (view.isSummaryWithChildren() && view.getParent() == this) {
-            // Faking a measure with the group expanded to simulate how the group would look if
-            // it was. Doing a calculation here would be highly non-trivial because of the
-            // algorithm
-            mGroupExpandedForMeasure = true;
-            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-            mGroupManager.toggleGroupExpansion(row.getStatusBarNotification());
-            row.setForceUnlocked(true);
-            mAmbientState.setLayoutHeight(mMaxLayoutHeight);
-            mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
-            mAmbientState.setLayoutHeight(getLayoutHeight());
-            mGroupManager.toggleGroupExpansion(
-                    row.getStatusBarNotification());
-            mGroupExpandedForMeasure = false;
-            row.setForceUnlocked(false);
-            ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(view);
-            if (viewState != null) {
-                // The view could have been removed
-                return Math.min(viewState.height, maxContentHeight);
-            }
-        }
-        return maxContentHeight;
+        return view.getMaxContentHeight();
     }
 
     public void setScrollingEnabled(boolean enable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 1dc346d..17e73d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -323,9 +323,6 @@
         int childHeight = getMaxAllowedChildHeight(child);
         childViewState.yTranslation = currentYPosition;
         boolean isDismissView = child instanceof DismissView;
-        if (i == 0) {
-            updateFirstChildHeight(child, childViewState, childHeight, algorithmState, ambientState);
-        }
 
         childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
         if (isDismissView) {
@@ -450,29 +447,6 @@
     }
 
     /**
-     * Update the height of the first child i.e clamp it to the bottom stack
-     * @param child the child to update
-     * @param childViewState the viewstate of the child
-     * @param childHeight the height of the child
-     * @param algorithmState the algorithm state
-     * @param ambientState The ambient state of the algorithm
-     */
-    protected void updateFirstChildHeight(ExpandableView child, ExpandableViewState childViewState,
-            int childHeight, StackScrollAlgorithmState algorithmState,
-            AmbientState ambientState) {
-
-        int bottomStart= ambientState.getInnerHeight();
-        if (algorithmState.visibleChildren.size() > 1) {
-            bottomStart -= ambientState.getShelf().getIntrinsicHeight()
-                    - mPaddingBetweenElements;
-        }
-        bottomStart += ambientState.getScrollY();
-            // Collapse and expand the first child while the shade is being expanded
-        childViewState.height = (int) Math.max(Math.min(bottomStart, (float) childHeight),
-                    child.getCollapsedHeight());
-    }
-
-    /**
      * Calculate the Z positions for all children based on the number of items in both stacks and
      * save it in the resultState
      *  @param resultState The result state to update the zTranslation values