Add mock animated taskbar to gesture nav tutorial for foldable devices.

Bug: 198434693
Test: launched and completed tutorial on regular phone and foldable device.
Change-Id: Id378e9bdd21fdfbc880ef528cb040b6390699d43
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation.xml b/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation.xml
index 34bd4e2..b0cc00b 100644
--- a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation.xml
+++ b/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation.xml
@@ -84,7 +84,7 @@
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:background="@color/mock_conversation_background"
-        android:paddingBottom="80dp"
+        android:paddingBottom="@dimen/gesture_tutorial_mock_taskbar_height"
 
         app:layout_constraintTop_toBottomOf="@id/top_bar"
         app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml b/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml
index 0309cc3..e5cd9bc 100644
--- a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml
+++ b/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml
@@ -51,7 +51,7 @@
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:background="@color/mock_list_background"
-        android:paddingBottom="80dp"
+        android:paddingBottom="@dimen/gesture_tutorial_mock_taskbar_height"
 
         app:layout_constraintTop_toBottomOf="@id/top_bar"
         app:layout_constraintBottom_toBottomOf="parent"
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_taskbar.xml b/quickstep/res/layout/gesture_tutorial_foldable_mock_taskbar.xml
new file mode 100644
index 0000000..ddfeeec
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_foldable_mock_taskbar.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.quickstep.interaction.AnimatedTaskbarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/gesture_tutorial_mock_taskbar_height">
+
+    <View
+        android:id="@+id/taskbar_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/gesture_tutorial_taskbar_color"
+
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"/>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/icon_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent">
+
+        <androidx.cardview.widget.CardView
+            android:id="@+id/taskbar_icon_1"
+            android:layout_width="@dimen/gesture_tutorial_taskbar_icon_size"
+            android:layout_height="@dimen/gesture_tutorial_taskbar_icon_size"
+            android:layout_marginStart="@dimen/gesture_tutorial_taskbar_padding_start_end"
+
+            app:cardElevation="0dp"
+            app:cardCornerRadius="@dimen/gesture_tutorial_taskbar_icon_corner_radius"
+            app:cardBackgroundColor="@color/mock_app_icon_1"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintHorizontal_chainStyle="spread_inside"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toStartOf="@id/taskbar_icon_2"/>
+
+        <androidx.cardview.widget.CardView
+            android:id="@+id/taskbar_icon_2"
+            android:layout_width="@dimen/gesture_tutorial_taskbar_icon_size"
+            android:layout_height="@dimen/gesture_tutorial_taskbar_icon_size"
+
+            app:cardElevation="0dp"
+            app:cardCornerRadius="@dimen/gesture_tutorial_taskbar_icon_corner_radius"
+            app:cardBackgroundColor="@color/mock_app_icon_2"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@id/taskbar_icon_1"
+            app:layout_constraintEnd_toStartOf="@id/taskbar_icon_3"/>
+
+        <androidx.cardview.widget.CardView
+            android:id="@+id/taskbar_icon_3"
+            android:layout_width="@dimen/gesture_tutorial_taskbar_icon_size"
+            android:layout_height="@dimen/gesture_tutorial_taskbar_icon_size"
+
+            app:cardElevation="0dp"
+            app:cardCornerRadius="@dimen/gesture_tutorial_taskbar_icon_corner_radius"
+            app:cardBackgroundColor="@color/mock_app_icon_3"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@id/taskbar_icon_2"
+            app:layout_constraintEnd_toStartOf="@id/taskbar_icon_4"/>
+
+        <androidx.cardview.widget.CardView
+            android:id="@+id/taskbar_icon_4"
+            android:layout_width="@dimen/gesture_tutorial_taskbar_icon_size"
+            android:layout_height="@dimen/gesture_tutorial_taskbar_icon_size"
+
+            app:cardElevation="0dp"
+            app:cardCornerRadius="@dimen/gesture_tutorial_taskbar_icon_corner_radius"
+            app:cardBackgroundColor="@color/mock_app_icon_1"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@id/taskbar_icon_3"
+            app:layout_constraintEnd_toStartOf="@id/taskbar_icon_5"/>
+
+        <androidx.cardview.widget.CardView
+            android:id="@+id/taskbar_icon_5"
+            android:layout_width="@dimen/gesture_tutorial_taskbar_icon_size"
+            android:layout_height="@dimen/gesture_tutorial_taskbar_icon_size"
+
+            app:cardElevation="0dp"
+            app:cardCornerRadius="@dimen/gesture_tutorial_taskbar_icon_corner_radius"
+            app:cardBackgroundColor="@color/mock_app_icon_4"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@id/taskbar_icon_4"
+            app:layout_constraintEnd_toStartOf="@id/taskbar_icon_6"/>
+
+        <androidx.cardview.widget.CardView
+            android:id="@+id/taskbar_icon_6"
+            android:layout_width="@dimen/gesture_tutorial_taskbar_icon_size"
+            android:layout_height="@dimen/gesture_tutorial_taskbar_icon_size"
+            android:layout_marginEnd="@dimen/gesture_tutorial_taskbar_padding_start_end"
+
+            app:cardElevation="0dp"
+            app:cardCornerRadius="@dimen/gesture_tutorial_taskbar_icon_corner_radius"
+            app:cardBackgroundColor="@color/mock_app_icon_2"
+            app:layout_constraintDimensionRatio="1:1"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@id/taskbar_icon_5"
+            app:layout_constraintEnd_toEndOf="parent"/>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</com.android.quickstep.interaction.AnimatedTaskbarView>
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 41d0a1d..08e6178 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -101,6 +101,15 @@
         android:layout_height="match_parent"
         android:background="@drawable/gesture_tutorial_ripple"/>
 
+    <include
+        layout="@layout/gesture_tutorial_foldable_mock_taskbar"
+        android:id="@+id/gesture_tutorial_fake_taskbar_view"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/gesture_tutorial_mock_taskbar_height"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentEnd="true" />
+
     <ImageView
         android:id="@+id/gesture_tutorial_edge_gesture_video"
         android:layout_width="match_parent"
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 5edcc9d..3b291db 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -40,6 +40,7 @@
     <color name="gesture_tutorial_fake_previous_task_view_color">#3C4043</color> <!-- Gray -->
     <color name="gesture_tutorial_action_button_label_color">#FF000000</color>
     <color name="gesture_tutorial_primary_color">#B7F29F</color> <!-- Light Green -->
+    <color name="gesture_tutorial_taskbar_color">#202124</color>
 
     <!-- Mock hotseat -->
     <color name="mock_app_icon_1">#8AB4F8</color>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index e08eda8..bca3bc0 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -121,6 +121,7 @@
     <dimen name="gesture_tutorial_foldable_feedback_margin_start_end">140dp</dimen>
     <dimen name="gesture_tutorial_multi_row_task_view_spacing">72dp</dimen>
     <dimen name="gesture_tutorial_small_task_view_corner_radius">18dp</dimen>
+    <dimen name="gesture_tutorial_mock_taskbar_height">80dp</dimen>
 
     <!-- Gesture Tutorial mock conversations -->
     <dimen name="gesture_tutorial_message_icon_size">44dp</dimen>
@@ -155,6 +156,11 @@
     <dimen name="gesture_tutorial_webpage_large_line_height">36dp</dimen>
     <dimen name="gesture_tutorial_webpage_small_line_height">22dp</dimen>
 
+    <!-- Gesture Tutorial mock taskbar -->
+    <dimen name="gesture_tutorial_taskbar_icon_size">44dp</dimen>
+    <dimen name="gesture_tutorial_taskbar_icon_corner_radius">100dp</dimen>
+    <dimen name="gesture_tutorial_taskbar_padding_start_end">218dp</dimen>
+
     <!-- All Set page -->
     <dimen name="allset_page_margin_horizontal">40dp</dimen>
     <dimen name="allset_title_margin_top">24dp</dimen>
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskbarView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskbarView.java
new file mode 100644
index 0000000..e8cc45b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskbarView.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2021 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.quickstep.interaction;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.launcher3.R;
+
+import java.util.ArrayList;
+
+
+/**
+ * Helper View for the gesture tutorial mock taskbar view.
+ *
+ * This helper class allows animating this mock taskview to and from a mock hotseat and the bottom
+ * of the screen.
+ */
+public class AnimatedTaskbarView extends ConstraintLayout {
+
+    private View mBackground;
+    private View mIconContainer;
+    private View mIcon1;
+    private View mIcon2;
+    private View mIcon3;
+    private View mIcon4;
+    private View mIcon5;
+    private View mIcon6;
+
+    @Nullable private Animator mRunningAnimator;
+
+    public AnimatedTaskbarView(@NonNull Context context) {
+        super(context);
+    }
+
+    public AnimatedTaskbarView(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AnimatedTaskbarView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public AnimatedTaskbarView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mBackground = findViewById(R.id.taskbar_background);
+        mIconContainer = findViewById(R.id.icon_container);
+        mIcon1 = findViewById(R.id.taskbar_icon_1);
+        mIcon2 = findViewById(R.id.taskbar_icon_2);
+        mIcon3 = findViewById(R.id.taskbar_icon_3);
+        mIcon4 = findViewById(R.id.taskbar_icon_4);
+        mIcon5 = findViewById(R.id.taskbar_icon_5);
+        mIcon6 = findViewById(R.id.taskbar_icon_6);
+    }
+
+    /**
+     * Animates this fake taskbar's disappearance into the given hotseat view.
+     */
+    public void animateDisappearanceToHotseat(ViewGroup hotseat) {
+        ArrayList<Animator> animators = new ArrayList<>();
+        int hotseatTop = hotseat.getTop();
+
+        animators.add(ObjectAnimator.ofFloat(
+                mBackground, View.TRANSLATION_Y, 0, mBackground.getHeight()));
+        animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 1f, 0f));
+        animators.add(createIconDisappearanceToHotseatAnimator(
+                mIcon1, hotseat.findViewById(R.id.hotseat_icon_1), hotseatTop));
+        animators.add(createIconDisappearanceToHotseatAnimator(
+                mIcon2, hotseat.findViewById(R.id.hotseat_icon_2), hotseatTop));
+        animators.add(createIconDisappearanceToHotseatAnimator(
+                mIcon3, hotseat.findViewById(R.id.hotseat_icon_3), hotseatTop));
+        animators.add(createIconDisappearanceToHotseatAnimator(
+                mIcon4, hotseat.findViewById(R.id.hotseat_icon_4), hotseatTop));
+        animators.add(createIconDisappearanceToHotseatAnimator(
+                mIcon5, hotseat.findViewById(R.id.hotseat_icon_5), hotseatTop));
+        animators.add(createIconDisappearanceToHotseatAnimator(
+                mIcon6, hotseat.findViewById(R.id.hotseat_icon_6), hotseatTop));
+
+        AnimatorSet animatorSet = new AnimatorSet();
+
+        animatorSet.playTogether(animators);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                setVisibility(INVISIBLE);
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                setVisibility(VISIBLE);
+            }
+        });
+
+        start(animatorSet);
+    }
+
+    /**
+     * Animates this fake taskbar's appearance from the given hotseat view.
+     */
+    public void animateAppearanceFromHotseat(ViewGroup hotseat) {
+        ArrayList<Animator> animators = new ArrayList<>();
+        int hotseatTop = hotseat.getTop();
+
+        animators.add(ObjectAnimator.ofFloat(
+                mBackground, View.TRANSLATION_Y, mBackground.getHeight(), 0));
+        animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 0f, 1f));
+        animators.add(createIconAppearanceFromHotseatAnimator(
+                mIcon1, hotseat.findViewById(R.id.hotseat_icon_1), hotseatTop));
+        animators.add(createIconAppearanceFromHotseatAnimator(
+                mIcon2, hotseat.findViewById(R.id.hotseat_icon_2), hotseatTop));
+        animators.add(createIconAppearanceFromHotseatAnimator(
+                mIcon3, hotseat.findViewById(R.id.hotseat_icon_3), hotseatTop));
+        animators.add(createIconAppearanceFromHotseatAnimator(
+                mIcon4, hotseat.findViewById(R.id.hotseat_icon_4), hotseatTop));
+        animators.add(createIconAppearanceFromHotseatAnimator(
+                mIcon5, hotseat.findViewById(R.id.hotseat_icon_5), hotseatTop));
+        animators.add(createIconAppearanceFromHotseatAnimator(
+                mIcon6, hotseat.findViewById(R.id.hotseat_icon_6), hotseatTop));
+
+        AnimatorSet animatorSet = new AnimatorSet();
+
+        animatorSet.playTogether(animators);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                setVisibility(VISIBLE);
+            }
+        });
+
+        start(animatorSet);
+    }
+
+    /**
+     * Animates this fake taskbar's disappearance to the bottom of the screen.
+     */
+    public void animateDisappearanceToBottom() {
+        ArrayList<Animator> animators = new ArrayList<>();
+
+        animators.add(ObjectAnimator.ofFloat(
+                mBackground, View.TRANSLATION_Y, 0, mBackground.getHeight()));
+        animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 1f, 0f));
+        animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_X, 1f, 0f));
+        animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_Y, 1f, 0f));
+
+        initializeIconContainerPivot();
+
+        AnimatorSet animatorSet = new AnimatorSet();
+
+        animatorSet.playTogether(animators);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                setVisibility(INVISIBLE);
+                resetIconContainerPivot();
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                super.onAnimationCancel(animation);
+                resetIconContainerPivot();
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                setVisibility(VISIBLE);
+            }
+        });
+
+        start(animatorSet);
+    }
+
+    /**
+     * Animates this fake taskbar's appearance from the bottom of the screen.
+     */
+    public void animateAppearanceFromBottom() {
+        ArrayList<Animator> animators = new ArrayList<>();
+
+        animators.add(ObjectAnimator.ofFloat(
+                mBackground, View.TRANSLATION_Y, mBackground.getHeight(), 0));
+        animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 0f, 1f));
+        animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_X, 0f, 1f));
+        animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_Y, 0f, 1f));
+
+        initializeIconContainerPivot();
+
+        AnimatorSet animatorSet = new AnimatorSet();
+
+        animatorSet.playTogether(animators);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                setVisibility(VISIBLE);
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                resetIconContainerPivot();
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                super.onAnimationCancel(animation);
+                resetIconContainerPivot();
+            }
+        });
+
+        start(animatorSet);
+    }
+
+    private void initializeIconContainerPivot() {
+        mIconContainer.setPivotX(getWidth() / 2f);
+        mIconContainer.setPivotY(getHeight() * 0.8f);
+    }
+
+    private void resetIconContainerPivot() {
+        mIconContainer.resetPivot();
+        mIconContainer.setScaleX(1f);
+        mIconContainer.setScaleY(1f);
+    }
+
+    private void start(Animator animator) {
+        if (mRunningAnimator != null) {
+            mRunningAnimator.cancel();
+        }
+
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                super.onAnimationCancel(animation);
+                mRunningAnimator = null;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                mRunningAnimator = null;
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                mRunningAnimator = animator;
+            }
+        });
+
+        animator.start();
+    }
+
+    private Animator createIconDisappearanceToHotseatAnimator(
+            View taskbarIcon, View hotseatIcon, int hotseatTop) {
+        ArrayList<Animator> animators = new ArrayList<>();
+
+        animators.add(ObjectAnimator.ofFloat(
+                taskbarIcon,
+                View.TRANSLATION_Y,
+                0,
+                (hotseatTop + hotseatIcon.getTop()) - (getTop() + taskbarIcon.getTop())));
+        animators.add(ObjectAnimator.ofFloat(
+                taskbarIcon, View.TRANSLATION_X, 0, hotseatIcon.getLeft() - taskbarIcon.getLeft()));
+        animators.add(ObjectAnimator.ofFloat(
+                taskbarIcon,
+                View.SCALE_X,
+                1f,
+                (float) hotseatIcon.getWidth() / (float) taskbarIcon.getWidth()));
+        animators.add(ObjectAnimator.ofFloat(
+                taskbarIcon,
+                View.SCALE_Y,
+                1f,
+                (float) hotseatIcon.getHeight() / (float) taskbarIcon.getHeight()));
+        animators.add(ObjectAnimator.ofFloat(taskbarIcon, View.ALPHA, 1f, 0f));
+
+        AnimatorSet animatorSet = new AnimatorSet();
+
+        animatorSet.playTogether(animators);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                taskbarIcon.setVisibility(INVISIBLE);
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                taskbarIcon.setVisibility(VISIBLE);
+            }
+        });
+
+        return animatorSet;
+    }
+
+    private Animator createIconAppearanceFromHotseatAnimator(
+            View taskbarIcon, View hotseatIcon, int hotseatTop) {
+        ArrayList<Animator> animators = new ArrayList<>();
+
+        animators.add(ObjectAnimator.ofFloat(
+                taskbarIcon,
+                View.TRANSLATION_Y,
+                (hotseatTop + hotseatIcon.getTop()) - (getTop() + taskbarIcon.getTop()),
+                0));
+        animators.add(ObjectAnimator.ofFloat(
+                taskbarIcon, View.TRANSLATION_X, hotseatIcon.getLeft() - taskbarIcon.getLeft(), 0));
+        animators.add(ObjectAnimator.ofFloat(
+                taskbarIcon,
+                View.SCALE_X,
+                (float) hotseatIcon.getWidth() / (float) taskbarIcon.getWidth(),
+                1f));
+        animators.add(ObjectAnimator.ofFloat(
+                taskbarIcon,
+                View.SCALE_Y,
+                (float) hotseatIcon.getHeight() / (float) taskbarIcon.getHeight(),
+                1f));
+        animators.add(ObjectAnimator.ofFloat(taskbarIcon, View.ALPHA, 0f, 1f));
+
+        AnimatorSet animatorSet = new AnimatorSet();
+
+        animatorSet.playTogether(animators);
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                taskbarIcon.setVisibility(VISIBLE);
+            }
+        });
+
+        return animatorSet;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index a45f273..bbb22e6 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -95,8 +95,10 @@
                         showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
                         break;
                     case OVERVIEW_GESTURE_COMPLETED:
-                        fadeOutFakeTaskView(true, true, () ->
-                                showFeedback(R.string.home_gesture_feedback_overview_detected));
+                        fadeOutFakeTaskView(true, true, () -> {
+                            showFeedback(R.string.home_gesture_feedback_overview_detected);
+                            showFakeTaskbar(/* animateFromHotseat= */ false);
+                        });
                         break;
                     case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
                     case HOME_OR_OVERVIEW_CANCELLED:
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
index dcae07d..423e66f 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
@@ -61,7 +61,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
-                controller.resetFakeTaskView();
+                controller.resetFakeTaskView(true);
             }
         });
         ArrayList<Animator> animators = new ArrayList<>();
@@ -76,7 +76,7 @@
             @Override
             public void onAnimationCancel(Animator animation) {
                 super.onAnimationCancel(animation);
-                controller.resetFakeTaskView();
+                controller.resetFakeTaskView(true);
             }
         });
         finalAnimation.playSequentially(animators);
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 24ef1fa..0fea0d7 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -93,8 +93,8 @@
                 switch (result) {
                     case HOME_GESTURE_COMPLETED: {
                         animateFakeTaskViewHome(finalVelocity, () -> {
-                            resetFakeTaskView();
                             showFeedback(R.string.overview_gesture_feedback_home_detected);
+                            resetFakeTaskView(true);
                         });
                         break;
                     }
@@ -146,6 +146,7 @@
 
         AnimatorSet animset = new AnimatorSet();
         animset.playTogether(animators);
+        hideFakeTaskbar(/* animateToHotseat= */ false);
         animset.start();
         mRunningWindowAnim = SwipeUpAnimationLogic.RunningWindowAnim.wrap(animset);
     }
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
index 57a76ca..f63a945 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
@@ -72,7 +72,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
-                controller.resetFakeTaskView();
+                controller.resetFakeTaskView(false);
             }
         });
         ArrayList<Animator> animators = new ArrayList<>();
@@ -88,7 +88,7 @@
             @Override
             public void onAnimationCancel(Animator animation) {
                 super.onAnimationCancel(animation);
-                controller.resetFakeTaskView();
+                controller.resetFakeTaskView(false);
             }
         });
         finalAnimation.playSequentially(animators);
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index a923519..68df208 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -198,11 +198,12 @@
             }
         }
         AnimatorSet animset = anim.buildAnim();
+        hideFakeTaskbar(/* animateToHotseat= */ false);
         animset.start();
         mRunningWindowAnim = RunningWindowAnim.wrap(animset);
     }
 
-    void resetFakeTaskView() {
+    void resetFakeTaskView(boolean animateFromHome) {
         mFakeTaskView.setVisibility(View.VISIBLE);
         PendingAnimation anim = new PendingAnimation(300);
         anim.setFloat(mTaskViewSwipeUpAnimation
@@ -210,12 +211,14 @@
         anim.setViewAlpha(mFakeTaskView, 1, ACCEL);
         anim.addListener(mResetTaskView);
         AnimatorSet animset = anim.buildAnim();
+        showFakeTaskbar(animateFromHome);
         animset.start();
         mRunningWindowAnim = RunningWindowAnim.wrap(animset);
     }
 
     void animateFakeTaskViewHome(PointF finalVelocity, @Nullable Runnable onEndRunnable) {
         cancelRunningAnimation();
+        hideFakeTaskbar(/* animateToHotseat= */ true);
         mFakePreviousTaskView.setVisibility(View.INVISIBLE);
         mFakeHotseatView.setVisibility(View.VISIBLE);
         mShowPreviousTasks = false;
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 9c1ff4d..a59b0d7 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -89,6 +89,7 @@
     @Nullable View mHotseatIconView;
     final ClipIconView mFakeIconView;
     final FrameLayout mFakeTaskView;
+    final AnimatedTaskbarView mFakeTaskbarView;
     final AnimatedTaskView mFakePreviousTaskView;
     final View mRippleView;
     final RippleDrawable mRippleDrawable;
@@ -104,6 +105,7 @@
     private final Runnable mTitleViewCallback;
     @Nullable private Runnable mFeedbackViewCallback;
     @Nullable private Runnable mFakeTaskViewCallback;
+    @Nullable private Runnable mFakeTaskbarViewCallback;
     private final Runnable mShowFeedbackRunnable;
 
     TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
@@ -122,6 +124,7 @@
         mFakeHotseatView = rootView.findViewById(R.id.gesture_tutorial_fake_hotseat_view);
         mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
         mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
+        mFakeTaskbarView = rootView.findViewById(R.id.gesture_tutorial_fake_taskbar_view);
         mFakePreviousTaskView =
                 rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_view);
         mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
@@ -319,6 +322,10 @@
             mFakeTaskView.removeCallbacks(mFakeTaskViewCallback);
             mFakeTaskViewCallback = null;
         }
+        if (mFakeTaskbarViewCallback != null) {
+            mFakeTaskbarView.removeCallbacks(mFakeTaskbarViewCallback);
+            mFakeTaskbarViewCallback = null;
+        }
         mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
     }
 
@@ -429,6 +436,38 @@
         mActionButton.setOnClickListener(this::onActionButtonClicked);
     }
 
+    void hideFakeTaskbar(boolean animateToHotseat) {
+        if (!mTutorialFragment.isLargeScreen()) {
+            return;
+        }
+        if (mFakeTaskbarViewCallback != null) {
+            mFakeTaskbarView.removeCallbacks(mFakeTaskbarViewCallback);
+        }
+        if (animateToHotseat) {
+            mFakeTaskbarViewCallback = () ->
+                    mFakeTaskbarView.animateDisappearanceToHotseat(mFakeHotseatView);
+        } else {
+            mFakeTaskbarViewCallback = mFakeTaskbarView::animateDisappearanceToBottom;
+        }
+        mFakeTaskbarView.post(mFakeTaskbarViewCallback);
+    }
+
+    void showFakeTaskbar(boolean animateFromHotseat) {
+        if (!mTutorialFragment.isLargeScreen()) {
+            return;
+        }
+        if (mFakeTaskbarViewCallback != null) {
+            mFakeTaskbarView.removeCallbacks(mFakeTaskbarViewCallback);
+        }
+        if (animateFromHotseat) {
+            mFakeTaskbarViewCallback = () ->
+                    mFakeTaskbarView.animateAppearanceFromHotseat(mFakeHotseatView);
+        } else {
+            mFakeTaskbarViewCallback = mFakeTaskbarView::animateAppearanceFromBottom;
+        }
+        mFakeTaskbarView.post(mFakeTaskbarViewCallback);
+    }
+
     void updateFakeAppTaskViewLayout(@LayoutRes int mockAppTaskLayoutResId) {
         updateFakeViewLayout(mFakeTaskView, mockAppTaskLayoutResId);
     }
@@ -480,6 +519,8 @@
                     mTutorialFragment.isLargeScreen()
                             ? R.dimen.gesture_tutorial_foldable_feedback_margin_start_end
                             : R.dimen.gesture_tutorial_feedback_margin_start_end));
+
+            mFakeTaskbarView.setVisibility(mTutorialFragment.isLargeScreen() ? View.VISIBLE : GONE);
         }
     }