Crop taskbar icons during stash/unstash animation.

When we stash, we crop the taskbar icons to the height of the
stashed handle.

In a follow up CL we will translate the icons so that at the
end of the stash animation, the icons will overlap with the
stashed handle for a more seamless handoff.

This will be good to get in first so that we can see if there is
any performance regression by running multiple outline
animations at the same time.

Test: stash/unstash observe cropping
Bug: 267806083
Change-Id: I19b05647a669c11376ac1d3267fd600131246be8
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index ba7a910..c95535b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -596,6 +596,10 @@
             }
         }
 
+        if (DisplayController.isTransientTaskbar(mActivity)) {
+            fullLengthAnimatorSet.play(mControllers.taskbarViewController
+                    .createRevealAnimToIsStashed(isStashed));
+        }
         fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
                 .createRevealAnimToIsStashed(isStashed));
         // Return the stashed handle to its default scale in case it was changed as part of the
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 69f79ba..9824fe0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -27,6 +27,8 @@
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
 
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.graphics.Rect;
 import android.util.FloatProperty;
@@ -49,6 +51,8 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.anim.RevealOutlineAnimation;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.icons.ThemedIconDrawable;
@@ -95,6 +99,7 @@
     private float mTaskbarIconTranslationYForSwipe;
 
     private final int mTaskbarBottomMargin;
+    private final int mStashedHandleHeight;
 
     private final AnimatedFloat mThemeIconsBackground = new AnimatedFloat(
             this::updateIconsBackground);
@@ -127,6 +132,8 @@
         mTaskbarBottomMargin = DisplayController.isTransientTaskbar(activity)
                 ? activity.getResources().getDimensionPixelSize(R.dimen.transient_taskbar_margin)
                 : 0;
+        mStashedHandleHeight = activity.getResources()
+                .getDimensionPixelSize(R.dimen.taskbar_stashed_handle_height);
 
         if (DisplayController.isTransientTaskbar(mActivity)) {
             mSwipeDownDetector = new SingleAxisSwipeDetector(activity,
@@ -280,6 +287,40 @@
                 ));
     }
 
+    private ValueAnimator createRevealAnimForView(View view, boolean isStashed) {
+        Rect viewBounds = new Rect(0, 0, view.getWidth(), view.getHeight());
+        int centerY = viewBounds.centerY();
+        int halfHandleHeight = mStashedHandleHeight / 2;
+
+        Rect stashedRect = new Rect(viewBounds.left,
+                centerY - halfHandleHeight,
+                viewBounds.right,
+                centerY + halfHandleHeight);
+
+        float radius = 0;
+        float stashedRadius = viewBounds.width() / 2f;
+
+        return new RoundedRectRevealOutlineProvider(radius, stashedRadius, viewBounds, stashedRect)
+                .createRevealAnimator(view, !isStashed, 0);
+    }
+
+    /**
+     * Creates and returns a {@link RevealOutlineAnimation} Animator that updates the icon shape
+     * and size.
+     * @param isStashed When true, the icon crops vertically to the size of the stashed handle.
+     *                  When false, the reverse happens.
+     */
+    public AnimatorSet createRevealAnimToIsStashed(boolean isStashed) {
+        AnimatorSet as = new AnimatorSet();
+        for (int i = mTaskbarView.getChildCount() - 1; i >= 0; i--) {
+            View child = mTaskbarView.getChildAt(i);
+            if (child instanceof BubbleTextView) {
+                as.play(createRevealAnimForView(child, isStashed));
+            }
+        }
+        return as;
+    }
+
     /**
      * Sets the taskbar icon alignment relative to Launcher hotseat icons
      * @param alignmentRatio [0, 1]