Merge "Fix SUW unstash animation." into udc-dev am: 9e0eee3729 am: bdb4531729

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/23352149

Change-Id: I007fef4b5b720f3aa997d193f4666f1a0e14b11b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 1ceb653..8e1059b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -54,6 +54,10 @@
     // Initialized in init.
     private TaskbarControllers mControllers;
 
+    // Used to defer any UI updates during the SUW unstash animation.
+    private boolean mDeferUpdatesForSUW;
+    private Runnable mDeferredUpdates;
+
     public TaskbarModelCallbacks(
             TaskbarActivityContext context, TaskbarView container) {
         mContext = context;
@@ -194,10 +198,38 @@
         }
         hotseatItemInfos = mControllers.taskbarRecentAppsController
                 .updateHotseatItemInfos(hotseatItemInfos);
+
+        if (mDeferUpdatesForSUW) {
+            ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
+            mDeferredUpdates = () -> {
+                updateHotseatItemsAndBackground(finalHotseatItemInfos);
+            };
+        } else {
+            updateHotseatItemsAndBackground(hotseatItemInfos);
+        }
+    }
+
+    private void updateHotseatItemsAndBackground(ItemInfo[] hotseatItemInfos) {
         mContainer.updateHotseatItems(hotseatItemInfos);
         mControllers.taskbarViewController.updateIconsBackground();
     }
 
+    /**
+     * This is used to defer UI updates after SUW builds the unstash animation.
+     * @param defer if true, defers updates to the UI
+     *              if false, posts updates (if any) to the UI
+     */
+    public void setDeferUpdatesForSUW(boolean defer) {
+        mDeferUpdatesForSUW = defer;
+
+        if (!mDeferUpdatesForSUW) {
+            if (mDeferredUpdates != null) {
+                mContainer.post(mDeferredUpdates);
+                mDeferredUpdates = null;
+            }
+        }
+    }
+
     @Override
     public void onRunningTasksChanged() {
         updateRunningApps();
@@ -232,5 +264,7 @@
             pw.println(
                     String.format("%s\tpredicted items count=%s", prefix, mPredictedItems.size()));
         }
+        pw.println(String.format("%s\tmDeferUpdatesForSUW=%b", prefix, mDeferUpdatesForSUW));
+        pw.println(String.format("%s\tupdates pending=%b", prefix, (mDeferredUpdates != null)));
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 6f82c7d..00e14ad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -585,10 +585,14 @@
      *                            actually be used since this animation tracks a swipe progress.
      */
     protected void addUnstashToHotseatAnimation(AnimatorSet animation, int placeholderDuration) {
+        // Defer any UI updates now to avoid the UI becoming stale when the animation plays.
+        mControllers.taskbarViewController.setDeferUpdatesForSUW(true);
         createAnimToIsStashed(
                 /* isStashed= */ false,
                 placeholderDuration,
                 TRANSITION_UNSTASH_SUW_MANUAL);
+        animation.addListener(AnimatorListeners.forEndCallback(
+                () -> mControllers.taskbarViewController.setDeferUpdatesForSUW(false)));
         animation.play(mAnimator);
     }
 
@@ -804,7 +808,7 @@
         }
 
         mControllers.taskbarViewController.addRevealAnimToIsStashed(skippable, isStashed, duration,
-                EMPHASIZED);
+                EMPHASIZED, animationType == TRANSITION_UNSTASH_SUW_MANUAL);
 
         play(skippable, mControllers.stashedHandleViewController
                 .createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 7429185..4abd995 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -30,6 +30,7 @@
 import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
 import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_REVEAL_ANIM;
 
+import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
@@ -286,7 +287,7 @@
     }
 
     private ValueAnimator createRevealAnimForView(View view, boolean isStashed, float newWidth,
-            boolean isQsb) {
+            boolean isQsb, boolean dispatchOnAnimationStart) {
         Rect viewBounds = new Rect(0, 0, view.getWidth(), view.getHeight());
         int centerY = viewBounds.centerY();
         int halfHandleHeight = mStashedHandleHeight / 2;
@@ -318,8 +319,24 @@
                 : 0f;
         float stashedRadius = stashedRect.height() / 2f;
 
-        return new RoundedRectRevealOutlineProvider(radius, stashedRadius, viewBounds, stashedRect)
+        ValueAnimator reveal = new RoundedRectRevealOutlineProvider(radius,
+                stashedRadius, viewBounds, stashedRect)
                 .createRevealAnimator(view, !isStashed, 0);
+        // SUW animation does not dispatch animation start until *after* the animation is complete.
+        // In order to work properly, the reveal animation start needs to be called immediately.
+        if (dispatchOnAnimationStart) {
+            for (Animator.AnimatorListener listener : reveal.getListeners()) {
+                listener.onAnimationStart(reveal);
+            }
+        }
+        return reveal;
+    }
+
+    /**
+     * Defers any updates to the UI for the setup wizard animation.
+     */
+    public void setDeferUpdatesForSUW(boolean defer) {
+        mModelCallbacks.setDeferUpdatesForSUW(defer);
     }
 
     /**
@@ -332,7 +349,7 @@
      * @param interpolator The interpolator to use for all animations.
      */
     public void addRevealAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
-            Interpolator interpolator) {
+            Interpolator interpolator, boolean dispatchOnAnimationStart) {
         AnimatorSet reveal = new AnimatorSet();
 
         Rect stashedBounds = new Rect();
@@ -349,8 +366,8 @@
             boolean isQsb = child == mTaskbarView.getQsb();
 
             // Crop the icons to/from the nav handle shape.
-            reveal.play(createRevealAnimForView(child, isStashed, newChildWidth, isQsb)
-                    .setDuration(duration));
+            reveal.play(createRevealAnimForView(child, isStashed, newChildWidth, isQsb,
+                    dispatchOnAnimationStart).setDuration(duration));
 
             // Translate the icons to/from their locations as the "nav handle."