Add spring animation when stashing transient taskbar.

Bug: 273961611
Change-Id: I35a658a5e30a155094a48effdefc3895f45e0483
Flag: ENABLE_TRANSIENT_TASKBAR
Test: stash transient taskbar
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 225bdcc..599095b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -300,6 +300,8 @@
     <dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
     <dimen name="transient_taskbar_stashed_size">32dp</dimen>
     <dimen name="transient_taskbar_all_apps_button_translation_x_offset">4dp</dimen>
+    <dimen name="transient_taskbar_stash_spring_velocity_dp_per_s">400dp</dimen>
+
     <!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
     <dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
     <!-- Taskbar swipe up thresholds -->
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index f082fc6..48b3f72 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -84,6 +84,9 @@
     private boolean mIsStashed;
     private boolean mTaskbarHidden;
 
+    private float mTranslationYForSwipe;
+    private float mTranslationYForStash;
+
     public StashedHandleViewController(TaskbarActivityContext activity,
             StashedHandleView stashedHandleView) {
         mActivity = activity;
@@ -254,7 +257,20 @@
      * Sets the translation of the stashed handle during the swipe up gesture.
      */
     protected void setTranslationYForSwipe(float transY) {
-        mStashedHandleView.setTranslationY(transY);
+        mTranslationYForSwipe = transY;
+        updateTranslationY();
+    }
+
+    /**
+     * Sets the translation of the stashed handle during the spring on stash animation.
+     */
+    protected void setTranslationYForStash(float transY) {
+        mTranslationYForStash = transY;
+        updateTranslationY();
+    }
+
+    private void updateTranslationY() {
+        mStashedHandleView.setTranslationY(mTranslationYForSwipe + mTranslationYForStash);
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 62713ca..a8345dc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -56,7 +56,6 @@
 import android.view.RoundedCorner;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
 import android.widget.FrameLayout;
 import android.widget.Toast;
 
@@ -233,6 +232,7 @@
                 new TaskbarInsetsController(this),
                 new VoiceInteractionWindowController(this),
                 new TaskbarTranslationController(this),
+                new TaskbarSpringOnStashController(this),
                 isDesktopMode
                         ? new DesktopTaskbarRecentAppsController(this)
                         : TaskbarRecentAppsController.DEFAULT,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 3375877..82b455d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -35,6 +35,7 @@
     val lastDrawnTransientRect = RectF()
     var backgroundHeight = context.deviceProfile.taskbarSize.toFloat()
     var translationYForSwipe = 0f
+    var translationYForStash = 0f
 
     private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat()
     private val transientBackgroundBounds = context.transientTaskbarBounds
@@ -136,7 +137,9 @@
             val bottom =
                 canvas.height - bottomMargin +
                     bottomMarginProgress +
-                    (-mapRange(1f - progress, 0f, stashedHandleHeight / 2f) + translationYForSwipe)
+                    translationYForSwipe +
+                    translationYForStash +
+                    -mapRange(1f - progress, 0f, stashedHandleHeight / 2f)
 
             // Draw shadow.
             val shadowAlpha =
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 931d79f..fb919ee 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -57,6 +57,7 @@
     public final VoiceInteractionWindowController voiceInteractionWindowController;
     public final TaskbarRecentAppsController taskbarRecentAppsController;
     public final TaskbarTranslationController taskbarTranslationController;
+    public final TaskbarSpringOnStashController taskbarSpringOnStashController;
     public final TaskbarOverlayController taskbarOverlayController;
     public final TaskbarEduTooltipController taskbarEduTooltipController;
     public final KeyboardQuickSwitchController keyboardQuickSwitchController;
@@ -103,6 +104,7 @@
             TaskbarInsetsController taskbarInsetsController,
             VoiceInteractionWindowController voiceInteractionWindowController,
             TaskbarTranslationController taskbarTranslationController,
+            TaskbarSpringOnStashController taskbarSpringOnStashController,
             TaskbarRecentAppsController taskbarRecentAppsController,
             TaskbarEduTooltipController taskbarEduTooltipController,
             KeyboardQuickSwitchController keyboardQuickSwitchController) {
@@ -127,6 +129,7 @@
         this.taskbarInsetsController = taskbarInsetsController;
         this.voiceInteractionWindowController = voiceInteractionWindowController;
         this.taskbarTranslationController = taskbarTranslationController;
+        this.taskbarSpringOnStashController = taskbarSpringOnStashController;
         this.taskbarRecentAppsController = taskbarRecentAppsController;
         this.taskbarEduTooltipController = taskbarEduTooltipController;
         this.keyboardQuickSwitchController = keyboardQuickSwitchController;
@@ -149,6 +152,7 @@
         taskbarScrimViewController.init(this);
         taskbarUnfoldAnimationController.init(this);
         taskbarKeyguardController.init(navbarButtonsViewController);
+        taskbarSpringOnStashController.init(this);
         stashedHandleViewController.init(this);
         taskbarStashController.init(this, sharedState.setupUIVisible);
         taskbarEduController.init(this);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 58d6244..6b9297d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -184,6 +184,14 @@
         invalidate();
     }
 
+    /*
+     * Sets the translation of the background during the spring on stash animation.
+     */
+    protected void setBackgroundTranslationYForStash(float translationY) {
+        mBackgroundRenderer.setTranslationYForStash(translationY);
+        invalidate();
+    }
+
     /** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */
     protected RectF getLastDrawnTransientRect() {
         return mBackgroundRenderer.getLastDrawnTransientRect();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 7c3d14d..2badc24 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -161,6 +161,13 @@
         mTaskbarDragLayer.setBackgroundTranslationYForSwipe(transY);
     }
 
+    /**
+     * Sets the translation of the background during the spring on stash animation.
+     */
+    public void setTranslationYForStash(float transY) {
+        mTaskbarDragLayer.setBackgroundTranslationYForStash(transY);
+    }
+
     private void updateBackgroundOffset() {
         mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value);
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java
new file mode 100644
index 0000000..d65b5c0
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.anim.AnimatedFloat.VALUE;
+
+import android.animation.ValueAnimator;
+
+import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController;
+import com.android.launcher3.util.DisplayController;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the spring animation when stashing the transient taskbar.
+ */
+public class TaskbarSpringOnStashController implements LoggableTaskbarController {
+
+    private final TaskbarActivityContext mContext;
+    private TaskbarControllers mControllers;
+    private final AnimatedFloat mTranslationForStash = new AnimatedFloat(
+            this::updateTranslationYForStash);
+
+    private final boolean mIsTransientTaskbar;
+
+    private final float mStartVelocityPxPerS;
+
+    public TaskbarSpringOnStashController(TaskbarActivityContext context) {
+        mContext = context;
+        mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext);
+        mStartVelocityPxPerS = context.getResources()
+                .getDimension(R.dimen.transient_taskbar_stash_spring_velocity_dp_per_s);
+    }
+
+    /**
+     * Initialization method.
+     */
+    public void init(TaskbarControllers controllers) {
+        mControllers = controllers;
+    }
+
+    private void updateTranslationYForStash() {
+        if (!mIsTransientTaskbar) {
+            return;
+        }
+
+        float transY = mTranslationForStash.value;
+        mControllers.stashedHandleViewController.setTranslationYForStash(transY);
+        mControllers.taskbarViewController.setTranslationYForStash(transY);
+        mControllers.taskbarDragLayerController.setTranslationYForStash(transY);
+    }
+
+    /**
+     * Returns a spring animation to be used when stashing the transient taskbar.
+     */
+    public @Nullable ValueAnimator createSpringToStash() {
+        if (!mIsTransientTaskbar) {
+            return null;
+        }
+        return new SpringAnimationBuilder(mContext)
+                .setStartValue(mTranslationForStash.value)
+                .setEndValue(0)
+                .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
+                .setStiffness(SpringForce.STIFFNESS_LOW)
+                .setStartVelocity(mStartVelocityPxPerS)
+                .build(mTranslationForStash, VALUE);
+    }
+
+
+    @Override
+    public void dumpLogs(String prefix, PrintWriter pw) {
+        pw.println(prefix + "TaskbarSpringOnStashController:");
+
+        pw.println(prefix + "\tmTranslationForStash=" + mTranslationForStash.value);
+        pw.println(prefix + "\tmStartVelocityPxPerS=" + mStartVelocityPxPerS);
+    }
+}
+
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index cbc1672..30cfcdf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -712,6 +712,9 @@
             play(as, mTaskbarStashedHandleAlpha.animateToValue(1), alphaStartDelay,
                     Math.max(0, duration - alphaStartDelay), LINEAR);
 
+            play(as, mControllers.taskbarSpringOnStashController.createSpringToStash(), 0, duration,
+                    LINEAR);
+
             if (skipStashAnimation) {
                 skipInterpolator = INSTANT;
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 4d92a9e..ad16eed 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -103,6 +103,7 @@
     private AnimatedFloat mTaskbarNavButtonTranslationY;
     private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
     private float mTaskbarIconTranslationYForSwipe;
+    private float mTaskbarIconTranslationYForSpringOnStash;
 
     private final int mTaskbarBottomMargin;
     private final int mStashedHandleHeight;
@@ -291,10 +292,19 @@
         updateTranslationY();
     }
 
+    /**
+     * Sets the translation of the TaskbarView during the spring on stash animation.
+     */
+    public void setTranslationYForStash(float transY) {
+        mTaskbarIconTranslationYForSpringOnStash = transY;
+        updateTranslationY();
+    }
+
     private void updateTranslationY() {
         mTaskbarView.setTranslationY(mTaskbarIconTranslationYForHome.value
                 + mTaskbarIconTranslationYForStash.value
-                + mTaskbarIconTranslationYForSwipe);
+                + mTaskbarIconTranslationYForSwipe
+                + mTaskbarIconTranslationYForSpringOnStash);
     }
 
     /**
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 4cca24e..172cb46 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -50,6 +50,7 @@
     @Mock lateinit var voiceInteractionWindowController: VoiceInteractionWindowController
     @Mock lateinit var taskbarRecentAppsController: TaskbarRecentAppsController
     @Mock lateinit var taskbarTranslationController: TaskbarTranslationController
+    @Mock lateinit var taskbarSpringOnStashController: TaskbarSpringOnStashController
     @Mock lateinit var taskbarOverlayController: TaskbarOverlayController
     @Mock lateinit var taskbarEduTooltipController: TaskbarEduTooltipController
     @Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController
@@ -89,6 +90,7 @@
                 taskbarInsetsController,
                 voiceInteractionWindowController,
                 taskbarTranslationController,
+                taskbarSpringOnStashController,
                 taskbarRecentAppsController,
                 taskbarEduTooltipController,
                 keyboardQuickSwitchController