Align bubble bar stash anim with taskbar (1/n)

Only scale bubble bar background during stash and unstash animation.
Follows the logic used for taskbar. We scale only the background and
clip the icons separately.

Bug: 345488489
Test: PersistentBubbleStashControllerTest
Test: TransientBubbleStashControllerTest
Test: BubbleBarViewAnimatorTest
Test: stash and unstash bubble bar in app by swiping up from taskbar
Test: expand and collapse bubble bar in app by swiping up on bar
Test: expand and collapse bubble bar on home screen by tapping on it

Flag: com.android.wm.shell.enable_bubble_bar
Change-Id: Ifc7922c444f2179fc49643424815e5e7dde519cc
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 25939e1..f08318e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -71,6 +71,27 @@
             }
         }
 
+    /**
+     * Scale of the background in the x direction. Pivot is at the left edge if [anchorLeft] is
+     * `true` and at the right edge if it is `false`
+     */
+    var scaleX: Float = 1f
+        set(value) {
+            if (field != value) {
+                field = value
+                invalidateSelf()
+            }
+        }
+
+    /** Scale of the background in the y direction. Pivot is at the bottom edge. */
+    var scaleY: Float = 1f
+        set(value) {
+            if (field != value) {
+                field = value
+                invalidateSelf()
+            }
+        }
+
     init {
         val res = context.resources
         // configure fill paint
@@ -123,13 +144,17 @@
         )
         // Create background path
         val backgroundPath = Path()
-        val topOffset = backgroundHeight - bounds.height().toFloat()
+        val scaledBackgroundHeight = backgroundHeight * scaleY
+        val scaledWidth = width * scaleX
+        val topOffset = scaledBackgroundHeight - bounds.height().toFloat()
         val radius = backgroundHeight / 2f
-        val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - width)
-        val right = bounds.left + (if (anchorLeft) width else bounds.width().toFloat())
-        val top = bounds.top - topOffset + arrowVisibleHeight
 
-        val bottom = bounds.top + bounds.height().toFloat()
+        val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - scaledWidth)
+        val right = bounds.left + (if (anchorLeft) scaledWidth else bounds.width().toFloat())
+        // Calculate top with scaled heights for background and arrow to align with stash handle
+        val top = bounds.bottom - scaledBackgroundHeight + getScaledArrowVisibleHeight()
+        val bottom = bounds.bottom.toFloat()
+
         backgroundPath.addRoundRect(left, top, right, bottom, radius, radius, Path.Direction.CW)
         addArrowPathIfNeeded(backgroundPath, topOffset)
 
@@ -142,19 +167,20 @@
     private fun addArrowPathIfNeeded(sourcePath: Path, topOffset: Float) {
         if (!showingArrow || arrowHeightFraction <= 0) return
         val arrowPath = Path()
+        val scaledHeight = getScaledArrowHeight()
         RoundedArrowDrawable.addDownPointingRoundedTriangleToPath(
             arrowWidth,
-            arrowHeight,
+            scaledHeight,
             arrowTipRadius,
             arrowPath
         )
         // flip it horizontally
         val pathTransform = Matrix()
-        pathTransform.setRotate(180f, arrowWidth * 0.5f, arrowHeight * 0.5f)
+        pathTransform.setRotate(180f, arrowWidth * 0.5f, scaledHeight * 0.5f)
         arrowPath.transform(pathTransform)
         // shift to arrow position
         val arrowStart = bounds.left + arrowPositionX - (arrowWidth / 2f)
-        val arrowTop = (1 - arrowHeightFraction) * arrowVisibleHeight - topOffset
+        val arrowTop = (1 - arrowHeightFraction) * getScaledArrowVisibleHeight() - topOffset
         arrowPath.offset(arrowStart, arrowTop)
         // union with rectangle
         sourcePath.op(arrowPath, Path.Op.UNION)
@@ -183,6 +209,7 @@
 
     fun setBackgroundHeight(newHeight: Float) {
         backgroundHeight = newHeight
+        invalidateSelf()
     }
 
     /**
@@ -199,6 +226,14 @@
         invalidateSelf()
     }
 
+    private fun getScaledArrowHeight(): Float {
+        return arrowHeight * scaleY
+    }
+
+    private fun getScaledArrowVisibleHeight(): Float {
+        return max(0f, getScaledArrowHeight() - (arrowHeight - arrowVisibleHeight))
+    }
+
     companion object {
         private const val DARK_THEME_STROKE_ALPHA = 51
         private const val LIGHT_THEME_STROKE_ALPHA = 41
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 06301c7..9c6ba8b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -306,6 +306,20 @@
     }
 
     /**
+     * Set scale for bubble bar background in x direction
+     */
+    public void setBackgroundScaleX(float scaleX) {
+        mBubbleBarBackground.setScaleX(scaleX);
+    }
+
+    /**
+     * Set scale for bubble bar background in y direction
+     */
+    public void setBackgroundScaleY(float scaleY) {
+        mBubbleBarBackground.setScaleY(scaleY);
+    }
+
+    /**
      * Sets new icon sizes and newBubbleBarPadding between icons and bubble bar borders.
      *
      * @param newIconSize         new icon size
@@ -322,7 +336,7 @@
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View childView = getChildAt(i);
-            childView.setScaleY(mIconScale);
+            childView.setScaleX(mIconScale);
             childView.setScaleY(mIconScale);
             FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams();
             params.height = (int) mIconSize;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index d9e3406..d0be5ec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -82,6 +82,10 @@
     private final MultiValueAlpha mBubbleBarAlpha;
     private final AnimatedFloat mBubbleBarScaleX = new AnimatedFloat(this::updateScaleX);
     private final AnimatedFloat mBubbleBarScaleY = new AnimatedFloat(this::updateScaleY);
+    private final AnimatedFloat mBubbleBarBackgroundScaleX = new AnimatedFloat(
+            this::updateBackgroundScaleX);
+    private final AnimatedFloat mBubbleBarBackgroundScaleY = new AnimatedFloat(
+            this::updateBackgroundScaleY);
     private final AnimatedFloat mBubbleBarTranslationY = new AnimatedFloat(
             this::updateTranslationY);
 
@@ -266,6 +270,14 @@
         return mBubbleBarScaleY;
     }
 
+    public AnimatedFloat getBubbleBarBackgroundScaleX() {
+        return mBubbleBarBackgroundScaleX;
+    }
+
+    public AnimatedFloat getBubbleBarBackgroundScaleY() {
+        return mBubbleBarBackgroundScaleY;
+    }
+
     public AnimatedFloat getBubbleBarTranslationY() {
         return mBubbleBarTranslationY;
     }
@@ -535,6 +547,14 @@
         mBarView.setScaleY(scale);
     }
 
+    private void updateBackgroundScaleX(float scale) {
+        mBarView.setBackgroundScaleX(scale);
+    }
+
+    private void updateBackgroundScaleY(float scale) {
+        mBarView.setBackgroundScaleY(scale);
+    }
+
     //
     // Manipulating the specific bubble views in the bar
     //
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 99c50f2..6a955d9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -169,6 +169,8 @@
         bubbleBarView.translationY = 0f
         bubbleBarView.scaleX = 1f
         bubbleBarView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
+        bubbleBarView.setBackgroundScaleX(1f)
+        bubbleBarView.setBackgroundScaleY(1f)
         bubbleBarView.relativePivotY = 0.5f
 
         // this is the offset between the center of the bubble bar and the center of the stash
@@ -311,6 +313,7 @@
             animatingBubble = null
             if (!canceled) bubbleStashController.stashBubbleBarImmediate()
             bubbleBarView.relativePivotY = 1f
+            bubbleBarView.scaleY = 1f
             bubbleStashController.updateTaskbarTouchRegion()
         }
         animator.start()
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 1157305..0700ab7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -67,8 +67,8 @@
     // bubble bar properties
     private lateinit var bubbleBarAlpha: MultiPropertyFactory<View>.MultiProperty
     private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat
-    private lateinit var bubbleBarScaleX: AnimatedFloat
-    private lateinit var bubbleBarScaleY: AnimatedFloat
+    private lateinit var bubbleBarBackgroundScaleX: AnimatedFloat
+    private lateinit var bubbleBarBackgroundScaleY: AnimatedFloat
     private val handleCenterFromScreenBottom =
         context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
 
@@ -149,8 +149,8 @@
         bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
         // bubble bar has only alpha property, getting it at index 0
         bubbleBarAlpha = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
-        bubbleBarScaleX = bubbleBarViewController.bubbleBarScaleX
-        bubbleBarScaleY = bubbleBarViewController.bubbleBarScaleY
+        bubbleBarBackgroundScaleX = bubbleBarViewController.bubbleBarBackgroundScaleX
+        bubbleBarBackgroundScaleY = bubbleBarViewController.bubbleBarBackgroundScaleY
         stashedHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0
         stashHandleViewAlpha = bubbleStashedHandleViewController?.stashedHandleAlpha?.get(0)
     }
@@ -160,8 +160,8 @@
         if (isBubblesShowingOnHome || isBubblesShowingOnOverview) {
             isStashed = false
             animatorSet.playTogether(
-                bubbleBarScaleX.animateToValue(1f),
-                bubbleBarScaleY.animateToValue(1f),
+                bubbleBarBackgroundScaleX.animateToValue(1f),
+                bubbleBarBackgroundScaleY.animateToValue(1f),
                 bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
                 bubbleBarAlpha.animateToValue(1f)
             )
@@ -181,8 +181,8 @@
         stashHandleViewAlpha?.value = 0f
         this.bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY)
         bubbleBarAlpha.setValue(1f)
-        bubbleBarScaleX.updateValue(1f)
-        bubbleBarScaleY.updateValue(1f)
+        bubbleBarBackgroundScaleX.updateValue(1f)
+        bubbleBarBackgroundScaleY.updateValue(1f)
         isStashed = false
         onIsStashedChanged()
     }
@@ -192,8 +192,8 @@
         stashHandleViewAlpha?.value = 1f
         this.bubbleBarTranslationYAnimator.updateValue(getStashTranslation())
         bubbleBarAlpha.setValue(0f)
-        bubbleBarScaleX.updateValue(getStashScaleX())
-        bubbleBarScaleY.updateValue(getStashScaleY())
+        bubbleBarBackgroundScaleX.updateValue(getStashScaleX())
+        bubbleBarBackgroundScaleY.updateValue(getStashScaleY())
         isStashed = true
         onIsStashedChanged()
     }
@@ -259,7 +259,7 @@
     override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY
 
     private fun getStashTranslation(): Float {
-        return bubbleBarTranslationY / 2f
+        return (bubbleBarTranslationY - stashedHeight) / 2f
     }
 
     @VisibleForTesting
@@ -366,8 +366,8 @@
         val scaleXTarget = if (isStashed) getStashScaleX() else 1f
         val scaleYTarget = if (isStashed) getStashScaleY() else 1f
         return AnimatorSet().apply {
-            play(bubbleBarScaleX.animateToValue(scaleXTarget))
-            play(bubbleBarScaleY.animateToValue(scaleYTarget))
+            play(bubbleBarBackgroundScaleX.animateToValue(scaleXTarget))
+            play(bubbleBarBackgroundScaleY.animateToValue(scaleYTarget))
         }
     }
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index 262d8da..a745b66 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -60,7 +60,7 @@
         const val TASK_BAR_TRANSLATION_Y = -TASKBAR_BOTTOM_SPACE
         const val HANDLE_VIEW_WIDTH = 150
         const val HANDLE_VIEW_HEIGHT = 4
-        const val BUBBLE_BAR_STASHED_TRANSLATION_Y = -2.5f
+        const val BUBBLE_BAR_STASHED_TRANSLATION_Y = -4.5f
     }
 
     @get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
@@ -302,8 +302,8 @@
 
         whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
         whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(barTranslationY)
-        whenever(bubbleBarViewController.bubbleBarScaleX).thenReturn(barScaleX)
-        whenever(bubbleBarViewController.bubbleBarScaleY).thenReturn(barScaleY)
+        whenever(bubbleBarViewController.bubbleBarBackgroundScaleX).thenReturn(barScaleX)
+        whenever(bubbleBarViewController.bubbleBarBackgroundScaleY).thenReturn(barScaleY)
         whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha)
         whenever(bubbleBarViewController.bubbleBarCollapsedWidth).thenReturn(BUBBLE_BAR_WIDTH)
         whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)