Merge "Updating taskbar icon alignment state" into sc-v2-dev
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index f4168d9..255ba1e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -15,27 +15,29 @@
  */
 package com.android.launcher3.taskbar;
 
-import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
 import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
-import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_LAUNCHER_STATE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.graphics.Rect;
 import android.view.MotionEvent;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatorListeners;
-import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
+import com.android.quickstep.RecentsAnimationController;
+import com.android.systemui.shared.recents.model.ThumbnailData;
 
 
 /**
@@ -51,12 +53,19 @@
     final TaskbarDragLayer mTaskbarDragLayer;
     final TaskbarView mTaskbarView;
 
+    private final AnimatedFloat mIconAlignmentForResumedState =
+            new AnimatedFloat(this::onIconAlignmentRatioChanged);
+    private final AnimatedFloat mIconAlignmentForGestureState =
+            new AnimatedFloat(this::onIconAlignmentRatioChanged);
+
     private AnimatedFloat mTaskbarBackgroundAlpha;
     private AlphaProperty mIconAlphaForHome;
-    private @Nullable Animator mAnimator;
     private boolean mIsAnimatingToLauncher;
     private TaskbarKeyguardController mKeyguardController;
 
+    private LauncherState mTargetStateOverride = null;
+    private TaskbarControllers mControllers;
+
     public LauncherTaskbarUIController(
             BaseQuickstepLauncher launcher, TaskbarActivityContext context) {
         mContext = context;
@@ -67,7 +76,6 @@
         mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
         mHotseatController = new TaskbarHotseatController(
                 mLauncher, mTaskbarView::updateHotseatItems);
-
     }
 
     @Override
@@ -77,21 +85,17 @@
         MultiValueAlpha taskbarIconAlpha = taskbarControllers.taskbarViewController
                 .getTaskbarIconAlpha();
         mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
-        mTaskbarStateHandler.setAnimationController(taskbarIconAlpha.getProperty(
-                ALPHA_INDEX_LAUNCHER_STATE));
+        mControllers = taskbarControllers;
+
         mHotseatController.init();
-        setTaskbarViewVisible(!mLauncher.hasBeenResumed());
         mLauncher.setTaskbarUIController(this);
         mKeyguardController = taskbarControllers.taskbarKeyguardController;
+        onLauncherResumedOrPaused(mLauncher.hasBeenResumed());
+        mIconAlignmentForResumedState.finishAnimation();
     }
 
     @Override
     protected void onDestroy() {
-        if (mAnimator != null) {
-            // End this first, in case it relies on properties that are about to be cleaned up.
-            mAnimator.end();
-        }
-        mTaskbarStateHandler.setAnimationController(null);
         mHotseatController.cleanup();
         setTaskbarViewVisible(true);
         mLauncher.getHotseat().setIconsAlpha(1f);
@@ -100,7 +104,7 @@
 
     @Override
     protected boolean isTaskbarTouchable() {
-        return !mIsAnimatingToLauncher;
+        return !mIsAnimatingToLauncher && mTargetStateOverride == null;
     }
 
     @Override
@@ -128,63 +132,82 @@
             }
         }
 
-        long duration = QuickstepTransitionManager.CONTENT_ALPHA_DURATION;
-        if (mAnimator != null) {
-            mAnimator.cancel();
-        }
-        if (isResumed) {
-            mAnimator = createAnimToLauncher(mLauncher.getStateManager().getState(), duration);
-        } else {
-            mAnimator = createAnimToApp(duration);
-        }
-        mAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mAnimator = null;
-            }
-        });
-        mAnimator.start();
+        ObjectAnimator anim = mIconAlignmentForResumedState.animateToValue(
+                getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
+                .setDuration(QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
+
+        anim.addListener(AnimatorListeners.forEndCallback(() -> mIsAnimatingToLauncher = false));
+        anim.start();
+        mIsAnimatingToLauncher = isResumed;
     }
 
     /**
-     * Create Taskbar animation when going from an app to Launcher.
+     * Create Taskbar animation when going from an app to Launcher as part of recents transition.
      * @param toState If known, the state we will end up in when reaching Launcher.
-     * TODO: Move this and createAnimToApp to TaskbarStateHandler using the BACKGROUND state
+     * @param callbacks callbacks to track the recents animation lifecycle. The state change is
+     *                 automatically reset once the recents animation finishes
      */
-    public Animator createAnimToLauncher(@NonNull LauncherState toState, long duration) {
-        PendingAnimation anim = new PendingAnimation(duration);
-        mTaskbarStateHandler.setState(toState, anim);
-
-        anim.setFloat(mTaskbarBackgroundAlpha, AnimatedFloat.VALUE, 0, LINEAR);
-        mTaskbarView.alignIconsWithLauncher(mLauncher.getDeviceProfile(), anim);
-
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mIsAnimatingToLauncher = true;
-            }
-
+    public Animator createAnimToLauncher(@NonNull LauncherState toState,
+            @NonNull RecentsAnimationCallbacks callbacks,
+            long duration) {
+        ObjectAnimator animator = mIconAlignmentForGestureState
+                .animateToValue(mIconAlignmentForGestureState.value, 1)
+                .setDuration(duration);
+        animator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                mIsAnimatingToLauncher = false;
-                setTaskbarViewVisible(false);
+                mTargetStateOverride = null;
             }
-        });
 
-        return anim.buildAnim();
-    }
-
-    private Animator createAnimToApp(long duration) {
-        PendingAnimation anim = new PendingAnimation(duration);
-        anim.setFloat(mTaskbarBackgroundAlpha, AnimatedFloat.VALUE, 1, LINEAR);
-        anim.addListener(AnimatorListeners.forEndCallback(mTaskbarView.resetIconPosition(anim)));
-        anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
-                setTaskbarViewVisible(true);
+                mTargetStateOverride = toState;
             }
         });
-        return anim.buildAnim();
+        callbacks.addListener(new RecentsAnimationListener() {
+            @Override
+            public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+                endGestureStateOverride();
+            }
+
+            @Override
+            public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+                endGestureStateOverride();
+            }
+
+            private void endGestureStateOverride() {
+                callbacks.removeListener(this);
+                mIconAlignmentForGestureState
+                        .animateToValue(mIconAlignmentForGestureState.value, 0)
+                        .start();
+            }
+        });
+        return animator;
+    }
+
+    private float getCurrentIconAlignmentRatio() {
+        return  Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
+    }
+
+    private void onIconAlignmentRatioChanged() {
+        if (mControllers == null) {
+            return;
+        }
+        float alignment = getCurrentIconAlignmentRatio();
+        mControllers.taskbarViewController.setLauncherIconAlignment(
+                alignment, mLauncher.getDeviceProfile());
+
+        mTaskbarBackgroundAlpha.updateValue(1 - alignment);
+
+        LauncherState state = mTargetStateOverride != null ? mTargetStateOverride
+                : mLauncher.getStateManager().getState();
+        if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+            // If the hotseat icons are visible, then switch taskbar in last frame
+            setTaskbarViewVisible(alignment < 1);
+        } else {
+            mLauncher.getHotseat().setIconsAlpha(1);
+            mIconAlphaForHome.setValue(1 - alignment);
+        }
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 000799b..106ebe5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -17,7 +17,6 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 
 import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
@@ -93,6 +92,7 @@
     private final ViewCache mViewCache = new ViewCache();
 
     private final boolean mIsSafeModeEnabled;
+    private boolean mIsDestroyed = false;
 
     public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
             TaskbarNavButtonController buttonController) {
@@ -208,6 +208,7 @@
      * Called when this instance of taskbar is no longer needed
      */
     public void onDestroy() {
+        mIsDestroyed = true;
         setUIController(TaskbarUIController.DEFAULT);
         mControllers.onDestroy();
         mWindowManager.removeViewImmediate(mDragLayer);
@@ -252,7 +253,7 @@
      * Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset).
      */
     public void setTaskbarWindowHeight(int height) {
-        if (mWindowLayoutParams.height == height) {
+        if (mWindowLayoutParams.height == height || mIsDestroyed) {
             return;
         }
         if (height != MATCH_PARENT) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
index 20d4133..edd2a22 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
@@ -18,45 +18,33 @@
 import static com.android.launcher3.LauncherState.TASKBAR;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 
-import androidx.annotation.Nullable;
-
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.SystemUiProxy;
 
 /**
- * StateHandler to animate Taskbar according to Launcher's state machine. Does nothing if Taskbar
- * isn't present (i.e. {@link #setAnimationController} is never called).
+ * StateHandler to animate Taskbar according to Launcher's state machine.
  */
 public class TaskbarStateHandler implements StateManager.StateHandler<LauncherState> {
 
     private final BaseQuickstepLauncher mLauncher;
 
-    // Contains Taskbar-related properties we should aniamte. If null, don't do anything.
-    private @Nullable MultiValueAlpha.AlphaProperty mTaskbarAlpha = null;
-
     private AnimatedFloat mNavbarButtonAlpha = new AnimatedFloat(this::updateNavbarButtonAlpha);
 
     public TaskbarStateHandler(BaseQuickstepLauncher launcher) {
         mLauncher = launcher;
     }
 
-    public void setAnimationController(MultiValueAlpha.AlphaProperty taskbarAlpha) {
-        mTaskbarAlpha = taskbarAlpha;
-        // Reapply state.
-        setState(mLauncher.getStateManager().getState());
-        updateNavbarButtonAlpha();
-    }
-
     @Override
     public void setState(LauncherState state) {
         setState(state, PropertySetter.NO_ANIM_PROPERTY_SETTER);
+        // Force update the alpha in case it was not initialized properly
+        updateNavbarButtonAlpha();
     }
 
     @Override
@@ -69,12 +57,7 @@
      * Sets the provided state
      */
     public void setState(LauncherState toState, PropertySetter setter) {
-        if (mTaskbarAlpha == null) {
-            return;
-        }
-
         boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
-        setter.setFloat(mTaskbarAlpha, MultiValueAlpha.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR);
         // Make the nav bar visible in states that taskbar isn't visible.
         // TODO: We should draw our own handle instead of showing the nav bar.
         float navbarButtonAlpha = isTaskbarVisible ? 0f : 1f;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index a952182..7753f96 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -15,11 +15,6 @@
  */
 package com.android.launcher3.taskbar;
 
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -34,10 +29,8 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
-import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -105,51 +98,6 @@
         mIconLongClickListener = mControllerCallbacks.getOnLongClickListener();
     }
 
-    /**
-     * Aligns the icons in the taskbar to that of Launcher.
-     */
-    public void alignIconsWithLauncher(DeviceProfile launcherDp, PropertySetter setter) {
-        Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(getContext());
-        float scaleUp = ((float) launcherDp.iconSizePx)
-                / mActivityContext.getDeviceProfile().iconSizePx;
-        int hotseatCellSize =
-                (launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right)
-                        / launcherDp.numShownHotseatIcons;
-
-        int offsetY = launcherDp.getTaskbarOffsetY();
-        setter.setFloat(this, VIEW_TRANSLATE_Y, -offsetY, LINEAR);
-        mActivityContext.setTaskbarWindowHeight(
-                mActivityContext.getDeviceProfile().taskbarSize + offsetY);
-
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            ItemInfo info = (ItemInfo) child.getTag();
-            setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
-
-            float childCenter = (child.getLeft() + child.getRight()) / 2;
-            float hotseatIconCenter = hotseatPadding.left + hotseatCellSize * info.screenId
-                    + hotseatCellSize / 2;
-            setter.setFloat(child, VIEW_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR);
-        }
-    }
-
-    /**
-     * Aligns the icons in the taskbar to that of Launcher.
-     * @return a callback to be executed at the end of the setter
-     */
-    public Runnable resetIconPosition(PropertySetter setter) {
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            setter.setFloat(child, SCALE_PROPERTY, 1, LINEAR);
-            setter.setFloat(child, VIEW_TRANSLATE_X, 0, LINEAR);
-        }
-        setter.setFloat(this, VIEW_TRANSLATE_Y, 0, LINEAR);
-        return () -> mActivityContext.setTaskbarWindowHeight(
-                mActivityContext.getDeviceProfile().taskbarSize);
-    }
-
     private void removeAndRecycle(View view) {
         removeView(view);
         view.setOnClickListener(null);
@@ -195,6 +143,7 @@
                     // so if the info changes we need to reinflate. This should only happen if a new
                     // folder is dragged to the position that another folder previously existed.
                     removeAndRecycle(hotseatView);
+                    hotseatView = null;
                 } else {
                     // View found
                     break;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 10cc926..c7ac4a4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -15,19 +15,29 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.graphics.Rect;
 import android.view.View;
 
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.MultiValueAlpha;
 
 /**
  * Handles properties/data collection, then passes the results to TaskbarView to render.
  */
 public class TaskbarViewController {
+    private static final Runnable NO_OP = () -> { };
 
     public static final int ALPHA_INDEX_HOME = 0;
-    public static final int ALPHA_INDEX_LAUNCHER_STATE = 1;
-    public static final int ALPHA_INDEX_IME = 2;
-    public static final int ALPHA_INDEX_KEYGUARD = 3;
+    public static final int ALPHA_INDEX_IME = 1;
+    public static final int ALPHA_INDEX_KEYGUARD = 2;
 
     private final TaskbarActivityContext mActivity;
     private final TaskbarView mTaskbarView;
@@ -36,10 +46,15 @@
     // Initialized in init.
     private TaskbarControllers mControllers;
 
+    // Animation to align icons with Launcher, created lazily. This allows the controller to be
+    // active only during the animation and does not need to worry about layout changes.
+    private AnimatorPlaybackController mIconAlignControllerLazy = null;
+    private Runnable mOnControllerPreCreateCallback = NO_OP;
+
     public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) {
         mActivity = activity;
         mTaskbarView = taskbarView;
-        mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, 4);
+        mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, 3);
         mTaskbarIconAlpha.setUpdateVisibility(true);
     }
 
@@ -72,6 +87,60 @@
     }
 
     /**
+     * Sets the taskbar icon alignment relative to Launcher hotseat icons
+     * @param alignmentRatio [0, 1]
+     *                       0 => not aligned
+     *                       1 => fully aligned
+     */
+    public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
+        if (mIconAlignControllerLazy == null) {
+            mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
+        }
+        mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
+        if (alignmentRatio <= 0 || alignmentRatio >= 1) {
+            // Cleanup lazy controller so that it is created again in next animation
+            mIconAlignControllerLazy = null;
+        }
+    }
+
+    /**
+     * Creates an animation for aligning the taskbar icons with the provided Launcher device profile
+     */
+    private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
+        mOnControllerPreCreateCallback.run();
+        PendingAnimation setter = new PendingAnimation(100);
+        Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
+        float scaleUp = ((float) launcherDp.iconSizePx) / mActivity.getDeviceProfile().iconSizePx;
+        int hotseatCellSize =
+                (launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right)
+                        / launcherDp.numShownHotseatIcons;
+
+        int offsetY = launcherDp.getTaskbarOffsetY();
+        setter.setFloat(mTaskbarView, VIEW_TRANSLATE_Y, -offsetY, LINEAR);
+
+        int collapsedHeight = mActivity.getDeviceProfile().taskbarSize;
+        int expandedHeight = collapsedHeight + offsetY;
+        setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
+                anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
+
+        int count = mTaskbarView.getChildCount();
+        for (int i = 0; i < count; i++) {
+            View child = mTaskbarView.getChildAt(i);
+            ItemInfo info = (ItemInfo) child.getTag();
+            setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
+
+            float childCenter = (child.getLeft() + child.getRight()) / 2;
+            float hotseatIconCenter = hotseatPadding.left + hotseatCellSize * info.screenId
+                    + hotseatCellSize / 2;
+            setter.setFloat(child, VIEW_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR);
+        }
+
+        AnimatorPlaybackController controller = setter.createPlaybackController();
+        mOnControllerPreCreateCallback = () -> controller.setPlayFraction(0);
+        return controller;
+    }
+
+    /**
      * Callbacks for {@link TaskbarView} to interact with its controller.
      */
     public class TaskbarViewCallbacks {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 0ebaea2..a8658a7 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1107,7 +1107,8 @@
                     mActivityRestartListener);
 
             mParallelRunningAnim = mActivityInterface.getParallelAnimationToLauncher(
-                    mGestureState.getEndTarget(), duration);
+                    mGestureState.getEndTarget(), duration,
+                    mTaskAnimationManager.getCurrentCallbacks());
             if (mParallelRunningAnim != null) {
                 mParallelRunningAnim.start();
             }
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index a45ced4..2699b07 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -346,7 +346,8 @@
      * an optional additional animation with the same duration.
      */
     public @Nullable Animator getParallelAnimationToLauncher(
-            GestureState.GestureEndTarget endTarget, long duration) {
+            GestureState.GestureEndTarget endTarget, long duration,
+            RecentsAnimationCallbacks callbacks) {
         if (endTarget == RECENTS) {
             ACTIVITY_TYPE activity = getCreatedActivity();
             if (activity == null) {
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 30abfbb..799a4c2 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -284,14 +284,15 @@
 
     @Override
     public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget,
-            long duration) {
+            long duration, RecentsAnimationCallbacks callbacks) {
         LauncherTaskbarUIController uiController = getTaskbarController();
-        Animator superAnimator = super.getParallelAnimationToLauncher(endTarget, duration);
-        if (uiController == null) {
+        Animator superAnimator = super.getParallelAnimationToLauncher(
+                endTarget, duration, callbacks);
+        if (uiController == null || callbacks == null) {
             return superAnimator;
         }
         LauncherState toState = stateFromGestureEndTarget(endTarget);
-        Animator taskbarAnimator = uiController.createAnimToLauncher(toState, duration);
+        Animator taskbarAnimator = uiController.createAnimToLauncher(toState, callbacks, duration);
         if (superAnimator == null) {
             return taskbarAnimator;
         } else {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 9731bf1..1c178ad 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -28,6 +28,7 @@
 import android.os.SystemProperties;
 import android.util.Log;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.Utilities;
@@ -261,6 +262,11 @@
         mLastAppearedTaskTarget = null;
     }
 
+    @Nullable
+    public RecentsAnimationCallbacks getCurrentCallbacks() {
+        return mCallbacks;
+    }
+
     public void dump() {
         // TODO
     }