Cancel badge scale anim when setting new badge scale

Otherwise it's possible the badge scale animation will override the
non-animated set value, which could mean a badge continues to show
even though it shouldn't:
- Animate badge scale to 1
- Before animation finishes, set badge scale to 0
- Badge scale ends at 1, since animation wasn't cancelled, so we
  continue to show it indefinitely

Also exported some properties in case a similar issue arises.

Bug: 111791593
Change-Id: Ia1a417239b909886adf9351e9bdc06a3b22d8b73
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 01e3a10..230ea4f 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -112,10 +114,13 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private float mTextAlpha = 1;
 
+    @ViewDebug.ExportedProperty(category = "launcher")
     private BadgeInfo mBadgeInfo;
     private BadgeRenderer mBadgeRenderer;
     private int mBadgeColor;
+    @ViewDebug.ExportedProperty(category = "launcher")
     private float mBadgeScale;
+    private Animator mBadgeScaleAnim;
     private boolean mForceHideBadge;
     private Point mTempSpaceForBadgeOffset = new Point();
     private Rect mTempIconBounds = new Rect();
@@ -188,10 +193,29 @@
     public void reset() {
         mBadgeInfo = null;
         mBadgeColor = Color.TRANSPARENT;
+        cancelBadgeScaleAnim();
         mBadgeScale = 0f;
         mForceHideBadge = false;
     }
 
+    private void cancelBadgeScaleAnim() {
+        if (mBadgeScaleAnim != null) {
+            mBadgeScaleAnim.cancel();
+        }
+    }
+
+    private void animateBadgeScale(float... badgeScales) {
+        cancelBadgeScaleAnim();
+        mBadgeScaleAnim = ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, badgeScales);
+        mBadgeScaleAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mBadgeScaleAnim = null;
+            }
+        });
+        mBadgeScaleAnim.start();
+    }
+
     public void applyFromShortcutInfo(ShortcutInfo info) {
         applyFromShortcutInfo(info, false);
     }
@@ -378,7 +402,7 @@
         if (forceHideBadge) {
             invalidate();
         } else if (hasBadge()) {
-            ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, 0, 1).start();
+            animateBadgeScale(0, 1);
         }
     }
 
@@ -524,8 +548,9 @@
             if (wasBadged || isBadged) {
                 // Animate when a badge is first added or when it is removed.
                 if (animate && (wasBadged ^ isBadged) && isShown()) {
-                    ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, newBadgeScale).start();
+                    animateBadgeScale(newBadgeScale);
                 } else {
+                    cancelBadgeScaleAnim();
                     mBadgeScale = newBadgeScale;
                     invalidate();
                 }