Changed the contentheight while pulsing

While pulsing, the contentHeight was limited to the pulsing view,
which is not working well when we want to dynamically expand
notifications from the pulsing state. This also fixes that
multiple pulsing views could be visible at the same time.

Test: atest SystemUITests
Bug: 125942236
Change-Id: Ia1dd51e3ef18cebc16da3c3245ebf10dd1dd9759
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 110d515..3788793 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -290,6 +290,7 @@
                 && !mAmbientState.isPanelTracking();
         int baseZHeight = mAmbientState.getBaseZHeight();
         int backgroundTop = 0;
+        int clipTopAmount = 0;
         float firstElementRoundness = 0.0f;
         ExpandableNotificationRow previousRow = null;
 
@@ -319,7 +320,8 @@
                             rowTranslationY + getNotificationMergeSize());
                 }
             }
-            updateNotificationClipHeight(row, notificationClipEnd);
+            int clipTop = updateNotificationClipHeight(row, notificationClipEnd, notGoneIndex);
+            clipTopAmount = Math.max(clipTop, clipTopAmount);
             float inShelfAmount = updateIconAppearance(row, expandAmount, scrolling, scrollingFast,
                     expandingAnimated, isLastChild);
             numViewsInShelf += inShelfAmount;
@@ -379,9 +381,9 @@
             previousColor = ownColorUntinted;
             previousRow = row;
         }
-
         clipTransientViews();
 
+        setClipTopAmount(clipTopAmount);
         setBackgroundTop(backgroundTop);
         setFirstElementRoundness(firstElementRoundness);
         mShelfIcons.setSpeedBumpIndex(mAmbientState.getSpeedBumpIndex());
@@ -415,7 +417,7 @@
             View transientView = mHostLayout.getTransientView(i);
             if (transientView instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow transientRow = (ExpandableNotificationRow) transientView;
-                updateNotificationClipHeight(transientRow, getTranslationY());
+                updateNotificationClipHeight(transientRow, getTranslationY(), -1);
             } else {
                 Log.e(TAG, "NotificationShelf.clipTransientViews(): "
                         + "Trying to clip non-row transient view");
@@ -432,9 +434,13 @@
 
     private void updateIconClipAmount(ExpandableNotificationRow row) {
         float maxTop = row.getTranslationY();
+        if (getClipTopAmount() != 0) {
+            // if the shelf is clipped, lets make sure we also clip the icon
+            maxTop = Math.max(maxTop, getTranslationY() + getClipTopAmount());
+        }
         StatusBarIconView icon = row.getEntry().expandedIcon;
         float shelfIconPosition = getTranslationY() + icon.getTop() + icon.getTranslationY();
-        if (shelfIconPosition < maxTop && !mAmbientState.isDark()) {
+        if (shelfIconPosition < maxTop && !mAmbientState.isFullyDark()) {
             int top = (int) (maxTop - shelfIconPosition);
             Rect clipRect = new Rect(0, top, icon.getWidth(), Math.max(top, icon.getHeight()));
             icon.setClipBounds(clipRect);
@@ -485,8 +491,8 @@
         }
     }
 
-    private void updateNotificationClipHeight(ExpandableNotificationRow row,
-            float notificationClipEnd) {
+    private int updateNotificationClipHeight(ExpandableNotificationRow row,
+            float notificationClipEnd, int childIndex) {
         float viewEnd = row.getTranslationY() + row.getActualHeight();
         boolean isPinned = (row.isPinned() || row.isHeadsUpAnimatingAway())
                 && !mAmbientState.isDozingAndNotPulsing(row);
@@ -497,10 +503,17 @@
                 clipBottomAmount = Math.min(row.getIntrinsicHeight() - row.getCollapsedHeight(),
                         clipBottomAmount);
             }
-            row.setClipBottomAmount(clipBottomAmount);
+            if (!row.isAmbientPulsing()
+                    && (!mAmbientState.isPulseExpanding() || childIndex != 0)) {
+                row.setClipBottomAmount(clipBottomAmount);
+            } else {
+                row.setClipBottomAmount(0);
+                return clipBottomAmount;
+            }
         } else {
             row.setClipBottomAmount(0);
         }
+        return 0;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index f318c54..1cd9293 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -168,14 +168,13 @@
         } else {
             if (!mAmbientPulseManager.hasNotifications()) {
                 // No pulsing notifications, we need to make notifications visible
-                val target = if (mReachedWakeUpHeight) (mWakeUpHeight / 2.0f) else 0.0f
-
+                val target = if (mReachedWakeUpHeight) mWakeUpHeight else 0.0f
                 mWakeUpCoordinator.setNotificationsVisible(height > target, true /* animate */,
                         true /* increaseSpeed */)
             }
             expansionHeight = max(mWakeUpHeight, expansionHeight)
         }
-        val emptyDragAmount = mWakeUpCoordinator.setPulseWakeUpHeight(expansionHeight)
+        val emptyDragAmount = mWakeUpCoordinator.setPulseHeight(expansionHeight)
         setEmptyDragAmount(emptyDragAmount * RUBBERBAND_FACTOR_STATIC)
     }
 
@@ -261,15 +260,6 @@
 
     fun setPulsing(pulsing: Boolean) {
         mPulsing = pulsing
-        val hasAmbientNotifications = mAmbientPulseManager.hasNotifications();
-        if (pulsing && hasAmbientNotifications) {
-            mWakeUpCoordinator.setNotificationsVisible(true /* visible */, true /* animate */,
-                    false /* increaseSpeed */)
-        } else if (!pulsing && !hasAmbientNotifications) {
-            // TODO: figure out the optimal UX for this, should we extend the pulse instead?
-            mWakeUpCoordinator.setNotificationsVisible(false /* visible */, true /* animate */,
-                    false /* increaseSpeed */)
-        }
     }
 
     fun onStartedWakingUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 1ea3bb1..cfdb0c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -20,6 +20,7 @@
 import android.util.FloatProperty
 import android.view.animation.Interpolator
 import com.android.systemui.Interpolators
+import com.android.systemui.statusbar.AmbientPulseManager
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 
@@ -27,7 +28,8 @@
 import javax.inject.Singleton
 
 @Singleton
-class NotificationWakeUpCoordinator @Inject constructor() {
+class NotificationWakeUpCoordinator @Inject constructor(
+        private val mAmbientPulseManager: AmbientPulseManager) {
 
     private val mNotificationVisibility
             = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
@@ -130,7 +132,18 @@
         }
     }
 
-    fun setPulseWakeUpHeight(height: Float): Float {
-        return mStackScroller.setPulseWakeUpHeight(height)
+    fun setPulseHeight(height: Float): Float {
+        return mStackScroller.setPulseHeight(height)
+    }
+
+    fun setPulsing(pulsing: Boolean) {
+        val hasAmbientNotifications = mAmbientPulseManager.hasNotifications();
+        if (pulsing && hasAmbientNotifications) {
+            setNotificationsVisible(true /* visible */, true /* animate */,
+                    false /* increaseSpeed */)
+        } else if (!pulsing && !hasAmbientNotifications) {
+            setNotificationsVisible(false /* visible */, true /* animate */,
+                    false /* increaseSpeed */)
+        }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 0fbc55b..1575f18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -721,6 +721,7 @@
         }
     }
 
+    @Override
     public boolean isAmbientPulsing() {
         return mIsAmbientPulsing;
     }
@@ -3004,9 +3005,9 @@
 
     @Override
     public boolean isAboveShelf() {
-        return !isOnKeyguard()
+        return isAmbientPulsing() || (!isOnKeyguard()
                 && (mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf)
-                || mExpandAnimationRunning || mChildIsExpanding);
+                || mExpandAnimationRunning || mChildIsExpanding));
     }
 
     public void setOnAmbient(boolean onAmbient) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index d1a89b4..29a9989 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -527,6 +527,10 @@
     public void setHeadsUpIsVisible() {
     }
 
+    public boolean isAmbientPulsing() {
+        return false;
+    }
+
     public boolean isChildInGroup() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index cb066f1..96e9a4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -40,6 +40,7 @@
 public class AmbientState {
 
     private static final int NO_SECTION_BOUNDARY = -1;
+    private static final float MAX_PULSE_HEIGHT = 100000f;
 
     private ArrayList<ExpandableView> mDraggedViews = new ArrayList<>();
     private int mScrollY;
@@ -80,7 +81,7 @@
     private ExpandableNotificationRow mExpandingNotification;
     private float mDarkAmount;
     private boolean mAppearing;
-    private float mPulseWakeUpHeight = Float.MAX_VALUE;
+    private float mPulseHeight = MAX_PULSE_HEIGHT;
     private float mDozeAmount = 0.0f;
 
     public AmbientState(Context context) {
@@ -185,6 +186,9 @@
     /** Dark ratio of the status bar **/
     public void setDarkAmount(float darkAmount) {
         mDarkAmount = darkAmount;
+        if (darkAmount == 1.0f) {
+            mPulseHeight = MAX_PULSE_HEIGHT;
+        }
     }
 
     /** Returns the dark ratio of the status bar */
@@ -290,15 +294,22 @@
      * @return the inner height of the algorithm.
      */
     public int getInnerHeight(boolean ignorePulseHeight) {
+        if (mDozeAmount == 1.0f && !isPulseExpanding()) {
+            return mShelf.getHeight();
+        }
         int height = Math.max(mLayoutMinHeight,
                 Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding);
         if (ignorePulseHeight) {
             return height;
         }
-        float pulseHeight = Math.min(mPulseWakeUpHeight, (float) height);
+        float pulseHeight = Math.min(mPulseHeight, (float) height);
         return (int) MathUtils.lerp(height, pulseHeight, mDozeAmount);
     }
 
+    public boolean isPulseExpanding() {
+        return mPulseHeight != MAX_PULSE_HEIGHT && mDarkAmount != 1.0f;
+    }
+
     public boolean isShadeExpanded() {
         return mShadeExpanded;
     }
@@ -506,15 +517,16 @@
         return mAppearing;
     }
 
-    public void setPulseWakeUpHeight(float height) {
-        mPulseWakeUpHeight = height;
+    public void setPulseHeight(float height) {
+        mPulseHeight = height;
     }
 
     public void setDozeAmount(float dozeAmount) {
         if (dozeAmount != mDozeAmount) {
             mDozeAmount = dozeAmount;
-            if (dozeAmount == 0.0f || dozeAmount == 1.0f) {
-                mPulseWakeUpHeight = Float.MAX_VALUE;
+            if (dozeAmount == 1.0f) {
+                // We woke all the way up, let's reset the pulse height
+                mPulseHeight = MAX_PULSE_HEIGHT;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index ee61c44..8455322 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -253,6 +253,11 @@
                 newTop = (int) Math.ceil(firstView.getTranslationY());
             }
             top = Math.max(newTop, top);
+            if (firstView.isAmbientPulsing()) {
+                // If we're pulsing, the notification can actually go below!
+                bottom = Math.max(bottom, finalTranslationY
+                        + ExpandableViewState.getFinalActualHeight(firstView));
+            }
         }
         top = Math.max(minTopPosition, top);
         ActivatableNotificationView lastView = getLastVisibleChild();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 4bb8aa6..09768ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -2270,9 +2270,7 @@
         float previousPaddingAmount = 0.0f;
         int numShownItems = 0;
         boolean finish = false;
-        int maxDisplayedNotifications = mAmbientState.isFullyDark()
-                ? (hasPulsingNotifications() ? 1 : 0)
-                : mMaxDisplayedNotifications;
+        int maxDisplayedNotifications = mMaxDisplayedNotifications;
 
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView expandableView = (ExpandableView) getChildAt(i);
@@ -2281,11 +2279,7 @@
                     && !expandableView.hasNoContentHeight() && !footerViewOnLockScreen) {
                 boolean limitReached = maxDisplayedNotifications != -1
                         && numShownItems >= maxDisplayedNotifications;
-                boolean notificationOnAmbientThatIsNotPulsing = mAmbientState.isFullyDark()
-                        && hasPulsingNotifications()
-                        && expandableView instanceof ExpandableNotificationRow
-                        && !isPulsing(((ExpandableNotificationRow) expandableView).getEntry());
-                if (limitReached || notificationOnAmbientThatIsNotPulsing) {
+                if (limitReached) {
                     expandableView = mShelf;
                     finish = true;
                 }
@@ -5626,8 +5620,8 @@
      * @param height the new wake up height
      * @return the overflow how much the height is further than he lowest notification
      */
-    public float setPulseWakeUpHeight(float height) {
-        mAmbientState.setPulseWakeUpHeight(height);
+    public float setPulseHeight(float height) {
+        mAmbientState.setPulseHeight(height);
         requestChildrenUpdate();
         return Math.max(0, height - mAmbientState.getInnerHeight(true /* ignorePulseHeight */));
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 7882fd3..0f3cccc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -101,6 +101,7 @@
         updateZValuesForState(algorithmState, ambientState);
 
         updateHeadsUpStates(algorithmState, ambientState);
+        updatePulsingStates(algorithmState, ambientState);
 
         updateDimmedActivatedHideSensitive(ambientState, algorithmState);
         updateClipping(algorithmState, ambientState);
@@ -477,6 +478,23 @@
         return algorithmState.getPaddingAfterChild(child);
     }
 
+    private void updatePulsingStates(StackScrollAlgorithmState algorithmState,
+            AmbientState ambientState) {
+        int childCount = algorithmState.visibleChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            View child = algorithmState.visibleChildren.get(i);
+            if (!(child instanceof ExpandableNotificationRow)) {
+                continue;
+            }
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            if (!row.isAmbientPulsing() || (i == 0 && ambientState.isPulseExpanding())) {
+                continue;
+            }
+            ExpandableViewState viewState = row.getViewState();
+            viewState.hidden = false;
+        }
+    }
+
     private void updateHeadsUpStates(StackScrollAlgorithmState algorithmState,
             AmbientState ambientState) {
         int childCount = algorithmState.visibleChildren.size();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index a1560bd..dfc5c86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -196,6 +196,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationListController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
@@ -366,6 +367,8 @@
     InjectionInflationController mInjectionInflater;
     @Inject
     PulseExpansionHandler mPulseExpansionHandler;
+    @Inject
+    NotificationWakeUpCoordinator mWakeUpCoordinator;
 
     // expanded notifications
     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -3901,6 +3904,7 @@
                     }
                     updateScrimController();
                     mPulseExpansionHandler.setPulsing(pulsing);
+                    mWakeUpCoordinator.setPulsing(pulsing);
                 }
             }, reason);
             // DozeScrimController is in pulse state, now let's ask ScrimController to start