Animate the dot with the bubble bar

The previous behavior relied on a BEHIND_STACK suppression flag to
determine whether the dot should be drawn or not. setBehindStack was
called as part of updating bubble layout properties in BubbleBarView,
which happens at each animation frame of the bubble bar collapsing
and expanding.

Instead of using the suppression flag, we now directly set the dot
scale based on the progress of the collapse and expand animation.

This change also sets the badge visibility directly from BubbleBarView
and cleans up the BEHIND_STACK suppression flag.

Flag: com.android.wm.shell.enable_bubble_bar
Fixes: 349822532
Test: manual
       - have some bubbles and expand bar
       - trigger a new bubble X
       - observe bubble added with notification dot
       - tap on the selected bubble to collapse
       - observe the notification dot animates for bubble X
       - expand the bar
       - observe notification dot animates for bubble X
       - tap on bubble X
       - observe notification dot animates out
       - tap on a different bubble
       - observe notification dot does not reappear
Change-Id: I6efe0dfa8b4f73064cee8b45556ff0928f6f7c08
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 0ea5031..5708403 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -848,16 +848,18 @@
                 // where the bubble will end up when the animation ends
                 final float targetX = expandedX + expandedBarShift;
                 bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
-                // When we're expanded, we're not stacked so we're not behind the stack
-                bv.setBehindStack(false, animate);
+                // When we're expanded, the badge is visible for all bubbles
+                bv.updateBadgeVisibility(/* show= */ true);
+                bv.setDotScale(widthState);
                 bv.setAlpha(1);
             } else {
                 // If bar is on the right, account for bubble bar expanding and shifting left
                 final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
                 final float targetX = collapsedX + collapsedBarShift;
                 bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
-                // If we're not the first bubble we're behind the stack
-                bv.setBehindStack(i > 0, animate);
+                // The badge is always visible for the first bubble
+                bv.updateBadgeVisibility(/* show= */ i == 0);
+                bv.setDotScale(widthState);
                 // If we're fully collapsed, hide all bubbles except for the first 2. If there are
                 // only 2 bubbles, hide the second bubble as well because it's the overflow.
                 if (widthState == 0) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 2f92fbb..0e26c54 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -35,8 +35,6 @@
 import com.android.launcher3.icons.IconNormalizer;
 import com.android.wm.shell.animation.Interpolators;
 
-import java.util.EnumSet;
-
 // TODO: (b/276978250) This is will be similar to WMShell's BadgedImageView, it'd be nice to share.
 
 /**
@@ -47,22 +45,6 @@
 
     public static final int DEFAULT_PATH_SIZE = 100;
 
-    /**
-     * Flags that suppress the visibility of the 'new' dot or the app badge, for one reason or
-     * another. If any of these flags are set, the dot will not be shown.
-     * If {@link SuppressionFlag#BEHIND_STACK} then the app badge will not be shown.
-     */
-    enum SuppressionFlag {
-        // TODO: (b/277815200) implement flyout
-        // Suppressed because the flyout is visible - it will morph into the dot via animation.
-        FLYOUT_VISIBLE,
-        // Suppressed because this bubble is behind others in the collapsed stack.
-        BEHIND_STACK,
-    }
-
-    private final EnumSet<SuppressionFlag> mSuppressionFlags =
-            EnumSet.noneOf(SuppressionFlag.class);
-
     private final ImageView mBubbleIcon;
     private final ImageView mAppIcon;
     private final int mBubbleSize;
@@ -230,7 +212,7 @@
         }
     }
 
-    void updateBadgeVisibility() {
+    void updateBadgeVisibility(boolean show) {
         if (mBubble instanceof BubbleBarOverflow) {
             // The overflow bubble does not have a badge, so just bail.
             return;
@@ -241,39 +223,24 @@
                 ? -(bubble.getIcon().getWidth() - appBadgeBitmap.getWidth())
                 : 0;
         mAppIcon.setTranslationX(translationX);
-        mAppIcon.setVisibility(isBehindStack() ? GONE : VISIBLE);
-    }
-
-    /** Sets whether this bubble is in the stack & not the first bubble. **/
-    void setBehindStack(boolean behindStack, boolean animate) {
-        if (behindStack) {
-            mSuppressionFlags.add(SuppressionFlag.BEHIND_STACK);
-        } else {
-            mSuppressionFlags.remove(SuppressionFlag.BEHIND_STACK);
-        }
-        updateDotVisibility(animate);
-        updateBadgeVisibility();
-    }
-
-    /** Whether this bubble is in the stack & not the first bubble. **/
-    boolean isBehindStack() {
-        return mSuppressionFlags.contains(SuppressionFlag.BEHIND_STACK);
+        mAppIcon.setVisibility(show ? VISIBLE : GONE);
     }
 
     /** Whether the dot indicating unseen content in a bubble should be shown. */
     private boolean shouldDrawDot() {
         boolean bubbleHasUnseenContent = mBubble != null
                 && mBubble instanceof BubbleBarBubble
-                && mSuppressionFlags.isEmpty()
                 && !((BubbleBarBubble) mBubble).getInfo().isNotificationSuppressed();
-
         // Always render the dot if it's animating, since it could be animating out. Otherwise, show
         // it if the bubble wants to show it, and we aren't suppressing it.
         return bubbleHasUnseenContent || mDotIsAnimating;
     }
 
     /** How big the dot should be, fraction from 0 to 1. */
-    private void setDotScale(float fraction) {
+    void setDotScale(float fraction) {
+        if (!shouldDrawDot()) {
+            return;
+        }
         mDotScale = fraction;
         invalidate();
     }
@@ -283,14 +250,14 @@
      */
     private void animateDotScale() {
         float toScale = shouldDrawDot() ? 1f : 0f;
-        mDotIsAnimating = true;
+        boolean isDotScaleChanging = Float.compare(mDotScale, toScale) != 0;
 
-        // Don't restart the animation if we're already animating to the given value.
-        if (mAnimatingToDotScale == toScale || !shouldDrawDot()) {
-            mDotIsAnimating = false;
+        // Don't restart the animation if we're already animating to the given value or if the dot
+        // scale is not changing
+        if ((mDotIsAnimating && mAnimatingToDotScale == toScale) || !isDotScaleChanging) {
             return;
         }
-
+        mDotIsAnimating = true;
         mAnimatingToDotScale = toScale;
 
         final boolean showDot = toScale > 0f;