Hide taskbar view for app open/close animation.

Bug: 246635237
Test: open app in hotseat
      close app in hotseat
      the 'matching' view in taskbar should be hidden
      tested icon, predicted icon, folders in taskbar/hotseat
Change-Id: I74382480826afafe6ae58e78faf26fe10812e29b
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 5ddf2a8..ea7eba3 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -634,7 +634,10 @@
         boolean appTargetsAreTranslucent = areAllTargetsTranslucent(appTargets);
 
         RectF launcherIconBounds = new RectF();
-        FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
+        FloatingIconView floatingView = getFloatingIconView(mLauncher, v,
+                mLauncher.getTaskbarUIController() == null
+                        ? null
+                        : mLauncher.getTaskbarUIController().findMatchingView(v),
                 !appTargetsAreTranslucent, launcherIconBounds, true /* isOpening */);
         Rect crop = new Rect();
         Matrix matrix = new Matrix();
@@ -1350,6 +1353,9 @@
                     isTransluscent, fallbackBackgroundColor);
         } else if (launcherView != null) {
             floatingIconView = getFloatingIconView(mLauncher, launcherView,
+                    mLauncher.getTaskbarUIController() == null
+                            ? null
+                            : mLauncher.getTaskbarUIController().findMatchingView(launcherView),
                     true /* hideOriginal */, targetRect, false /* isOpening */);
         } else {
             targetRect.set(getDefaultWindowTargetRect());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index b552e9b..13f0405 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -17,6 +17,8 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
 
 import android.content.Intent;
@@ -277,4 +279,30 @@
      * No-op if the view is not yet open.
      */
     public void launchSplitTasks(@NonNull View taskview, @NonNull GroupTask groupTask) { }
+
+    /**
+     * Returns the matching view (if any) in the taskbar.
+     * @param view The view to match.
+     */
+    public @Nullable View findMatchingView(View view) {
+        if (!(view.getTag() instanceof ItemInfo)) {
+            return null;
+        }
+        ItemInfo info = (ItemInfo) view.getTag();
+        if (info.container != CONTAINER_HOTSEAT && info.container != CONTAINER_HOTSEAT_PREDICTION) {
+            return null;
+        }
+
+        // Taskbar has the same items as the hotseat and we can use screenId to find the match.
+        int screenId = info.screenId;
+        View[] views = mControllers.taskbarViewController.getIconViews();
+        for (int i = views.length - 1; i >= 0; --i) {
+            if (views[i] != null
+                    && views[i].getTag() instanceof ItemInfo
+                    && ((ItemInfo) views[i].getTag()).screenId == screenId) {
+                return views[i];
+            }
+        }
+        return null;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index bb781c8..3151374 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -105,6 +105,9 @@
     private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) {
         RectF iconLocation = new RectF();
         FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView,
+                mActivity.getTaskbarUIController() == null
+                        ? null
+                        : mActivity.getTaskbarUIController().findMatchingView(workspaceView),
                 true /* hideOriginal */, iconLocation, false /* isOpening */);
 
         // We want the window alpha to be 0 once this threshold is met, so that the
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 55af622..e233e46 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -95,6 +95,9 @@
     private ClipIconView mClipIconView;
     private @Nullable Drawable mBadge;
 
+    // A view whose visibility should update in sync with mOriginalIcon.
+    private @Nullable View mMatchVisibilityView;
+
     private View mOriginalIcon;
     private RectF mPositionOut;
     private Runnable mOnTargetChangeRunnable;
@@ -386,7 +389,7 @@
      * Checks if the icon result is loaded. If true, we set the icon immediately. Else, we add a
      * callback to set the icon once the icon result is loaded.
      */
-    private void checkIconResult(View originalView) {
+    private void checkIconResult() {
         CancellationSignal cancellationSignal = new CancellationSignal();
 
         if (mIconLoadResult == null) {
@@ -399,7 +402,7 @@
                 setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
                         mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
                 setVisibility(VISIBLE);
-                setIconAndDotVisible(originalView, false);
+                updateViewsVisibility(false  /* isVisible */);
             } else {
                 mIconLoadResult.onIconLoaded = () -> {
                     if (cancellationSignal.isCanceled()) {
@@ -410,7 +413,7 @@
                             mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
 
                     setVisibility(VISIBLE);
-                    setIconAndDotVisible(originalView, false);
+                    updateViewsVisibility(false  /* isVisible */);
                 };
                 mLoadIconSignal = cancellationSignal;
             }
@@ -481,9 +484,9 @@
             // No need to wait for icon load since we can display the BubbleTextView drawable.
             setVisibility(View.VISIBLE);
         }
-        if (!mIsOpening && mOriginalIcon != null) {
+        if (!mIsOpening) {
             // When closing an app, we want the item on the workspace to be invisible immediately
-            setIconAndDotVisible(mOriginalIcon, false);
+            updateViewsVisibility(false  /* isVisible */);
         }
     }
 
@@ -562,13 +565,14 @@
     /**
      * Creates a floating icon view for {@param originalView}.
      * @param originalView The view to copy
+     * @param secondView A view whose visibility should update in sync with originalView.
      * @param hideOriginal If true, it will hide {@param originalView} while this view is visible.
      *                     Else, we will not draw anything in this view.
      * @param positionOut Rect that will hold the size and position of v.
      * @param isOpening True if this view replaces the icon for app open animation.
      */
     public static FloatingIconView getFloatingIconView(Launcher launcher, View originalView,
-            boolean hideOriginal, RectF positionOut, boolean isOpening) {
+            @Nullable View secondView, boolean hideOriginal, RectF positionOut, boolean isOpening) {
         final DragLayer dragLayer = launcher.getDragLayer();
         ViewGroup parent = (ViewGroup) dragLayer.getParent();
         FloatingIconView view = launcher.getViewCache().getView(R.layout.floating_icon_view,
@@ -578,6 +582,7 @@
         // Init properties before getting the drawable.
         view.mIsOpening = isOpening;
         view.mOriginalIcon = originalView;
+        view.mMatchVisibilityView = secondView;
         view.mPositionOut = positionOut;
 
         // Get the drawable on the background thread
@@ -597,7 +602,8 @@
         view.matchPositionOf(launcher, originalView, isOpening, positionOut);
 
         // We need to add it to the overlay, but keep it invisible until animation starts..
-        setIconAndDotVisible(view, false);
+        view.setVisibility(View.INVISIBLE);
+
         parent.addView(view);
         dragLayer.addView(view.mListenerView);
         view.mListenerView.setListener(view::fastFinish);
@@ -606,7 +612,7 @@
             view.mEndRunnable = null;
 
             if (hideOriginal) {
-                setIconAndDotVisible(originalView, true);
+                view.updateViewsVisibility(true /* isVisible */);
                 view.finish(dragLayer);
             } else {
                 view.finish(dragLayer);
@@ -617,12 +623,21 @@
         // Must be called after the fastFinish listener and end runnable is created so that
         // the icon is not left in a hidden state.
         if (shouldLoadIcon) {
-            view.checkIconResult(originalView);
+            view.checkIconResult();
         }
 
         return view;
     }
 
+    private void updateViewsVisibility(boolean isVisible) {
+        if (mOriginalIcon != null) {
+            setIconAndDotVisible(mOriginalIcon, isVisible);
+        }
+        if (mMatchVisibilityView != null) {
+            setIconAndDotVisible(mMatchVisibilityView, isVisible);
+        }
+    }
+
     private void finish(DragLayer dragLayer) {
         ((ViewGroup) dragLayer.getParent()).removeView(this);
         dragLayer.removeView(mListenerView);