Wrap short shelf width to icon count when less than lockscreen max

Move width updates into #updateAppearance.

Use numViewsInShelf for smooth width transitions.

Bug: 213480466
Test: add notif, shelf expands
Test: swipe away notif, shelf shrinks
Test: tap hidden/visible part of shelf
  => only visible part of shelf launches full shade
Test: the above in LTR/RTL

Change-Id: Icf5bfa6f901267446bd2dd16b39a6290538541b6
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index ff9fc30..3dd717d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import static com.android.systemui.statusbar.phone.NotificationIconContainer.MAX_ICONS_ON_LOCKSCREEN;
-
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -41,6 +39,7 @@
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.row.NotificationBackgroundView;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
@@ -48,7 +47,6 @@
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
 import com.android.systemui.statusbar.notification.stack.ViewState;
 import com.android.systemui.statusbar.phone.NotificationIconContainer;
-import com.android.systemui.util.Utils;
 
 /**
  * A notification shelf view that is placed inside the notification scroller. It manages the
@@ -85,7 +83,7 @@
     private int mIndexOfFirstViewInShelf = -1;
     private float mCornerAnimationDistance;
     private NotificationShelfController mController;
-    private int mActualWidth = -1;
+    private float mActualWidth = -1;
 
     /** Fraction of lockscreen to shade animation (on lockscreen swipe down). */
     private float mFractionToShade;
@@ -211,10 +209,6 @@
 
             final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight();
             viewState.yTranslation = stackEnd - viewState.height;
-
-            final int shortestWidth = mShelfIcons.calculateWidthFor(MAX_ICONS_ON_LOCKSCREEN);
-            final float fraction = Interpolators.STANDARD.getInterpolation(mFractionToShade);
-            updateStateWidth(viewState, fraction, shortestWidth);
         } else {
             viewState.hidden = true;
             viewState.location = ExpandableViewState.LOCATION_GONE;
@@ -223,15 +217,23 @@
     }
 
     /**
-     * @param shelfState View state for NotificationShelf
-     * @param fraction Fraction of lockscreen to shade transition
+     * @param fractionToShade Fraction of lockscreen to shade transition
      * @param shortestWidth Shortest width to use for lockscreen shelf
      */
     @VisibleForTesting
-    public void updateStateWidth(ShelfState shelfState, float fraction, int shortestWidth) {
-        shelfState.actualWidth = mAmbientState.isOnKeyguard()
-                ? (int) MathUtils.lerp(shortestWidth, getWidth(), fraction)
+    public void updateActualWidth(float fractionToShade, float shortestWidth) {
+        final float actualWidth = mAmbientState.isOnKeyguard()
+                ? MathUtils.lerp(shortestWidth, getWidth(), fractionToShade)
                 : getWidth();
+        ActivatableNotificationView anv = (ActivatableNotificationView) this;
+        NotificationBackgroundView bg = anv.getBackgroundNormal();
+        if (bg != null) {
+            anv.getBackgroundNormal().setActualWidth((int) actualWidth);
+        }
+        if (mShelfIcons != null) {
+            mShelfIcons.setActualLayoutWidth((int) actualWidth);
+        }
+        mActualWidth = actualWidth;
     }
 
     /**
@@ -245,7 +247,7 @@
      * @return Actual width of shelf, accounting for possible ongoing width animation
      */
     public int getActualWidth() {
-        return mActualWidth > -1 ? mActualWidth : getWidth();
+        return mActualWidth > -1 ? (int) mActualWidth : getWidth();
     }
 
     /**
@@ -412,6 +414,10 @@
                 || !mShowNotificationShelf
                 || numViewsInShelf < 1f;
 
+        final float fractionToShade = Interpolators.STANDARD.getInterpolation(mFractionToShade);
+        final float shortestWidth = mShelfIcons.calculateWidthFor(numViewsInShelf);
+        updateActualWidth(fractionToShade, shortestWidth);
+
         // TODO(b/172289889) transition last icon in shelf to notification icon and vice versa.
         setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE);
         setBackgroundTop(backgroundTop);
@@ -921,30 +927,17 @@
     public class ShelfState extends ExpandableViewState {
         private boolean hasItemsInStableShelf;
         private ExpandableView firstViewInShelf;
-        public int actualWidth = -1;
-
-        private void updateShelfWidth(View view) {
-            if (actualWidth < 0) {
-                return;
-            }
-            mActualWidth = actualWidth;
-            ActivatableNotificationView anv = (ActivatableNotificationView) view;
-            anv.getBackgroundNormal().setActualWidth(actualWidth);
-            mShelfIcons.setActualLayoutWidth(actualWidth);
-        }
 
         @Override
         public void applyToView(View view) {
             if (!mShowNotificationShelf) {
                 return;
             }
-
             super.applyToView(view);
             setIndexOfFirstViewInShelf(firstViewInShelf);
             updateAppearance();
             setHasItemsInStableShelf(hasItemsInStableShelf);
             mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
-            updateShelfWidth(view);
         }
 
         @Override
@@ -952,13 +945,11 @@
             if (!mShowNotificationShelf) {
                 return;
             }
-
             super.animateTo(view, properties);
             setIndexOfFirstViewInShelf(firstViewInShelf);
             updateAppearance();
             setHasItemsInStableShelf(hasItemsInStableShelf);
             mShelfIcons.setAnimationsEnabled(mAnimationsEnabled);
-            updateShelfWidth(view);
         }
     }
 }
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 ebfed1a..034b751 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -387,16 +387,18 @@
     }
 
     /**
-     * @return Width of shelf for the given number of icons and overflow dot
+     * @return Width of shelf for the given number of icons
      */
-    public int calculateWidthFor(int numMaxIcons) {
+    public float calculateWidthFor(float numIcons) {
         if (getChildCount() == 0) {
-            return 0;
+            return 0f;
         }
-        return (int) (getActualPaddingStart()
-                + numMaxIcons * mIconSize
-                + mOverflowWidth
-                + getActualPaddingEnd());
+        final float contentWidth = numIcons <= MAX_ICONS_ON_LOCKSCREEN + 1
+                ? numIcons * mIconSize
+                : MAX_ICONS_ON_LOCKSCREEN * mIconSize + (float) mOverflowWidth;
+        return getActualPaddingStart()
+                + contentWidth
+                + getActualPaddingEnd();
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index d280f54..5d16036 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -36,14 +36,14 @@
         setFractionToShade(0f)
         setOnLockscreen(true)
 
-        shelf.updateStateWidth(shelfState, /* fraction */ 0f, /* shortestWidth */ 10)
-        assertTrue(shelfState.actualWidth == 10)
+        shelf.updateActualWidth(/* fractionToShade */ 0f, /* shortestWidth */ 10f);
+        assertTrue(shelf.actualWidth == 10)
 
-        shelf.updateStateWidth(shelfState, /* fraction */ 0.5f, /* shortestWidth */ 10)
-        assertTrue(shelfState.actualWidth == 20)
+        shelf.updateActualWidth(/* fractionToShade */ 0.5f, /* shortestWidth */ 10f)
+        assertTrue(shelf.actualWidth == 20)
 
-        shelf.updateStateWidth(shelfState, /* fraction */ 1f, /* shortestWidth */ 10)
-        assertTrue(shelfState.actualWidth == 30)
+        shelf.updateActualWidth(/* fractionToShade */ 1f, /* shortestWidth */ 10f)
+        assertTrue(shelf.actualWidth == 30)
     }
 
     @Test
@@ -51,8 +51,8 @@
         setFractionToShade(0f)
         setOnLockscreen(false)
 
-        shelf.updateStateWidth(shelfState, /* fraction */ 0f, /* shortestWidth */ 10)
-        assertTrue(shelfState.actualWidth == 30)
+        shelf.updateActualWidth(/* fraction */ 0f, /* shortestWidth */ 10f)
+        assertTrue(shelf.actualWidth == 30)
     }
 
     @Test