Merge "Hide original icon immediately for app close." into ub-launcher3-qt-dev
diff --git a/quickstep/recents_ui_overrides/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml
index b316edd..c80e531 100644
--- a/quickstep/recents_ui_overrides/res/values/dimens.xml
+++ b/quickstep/recents_ui_overrides/res/values/dimens.xml
@@ -27,4 +27,5 @@
     <!-- Swipe up to home related -->
     <dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
     <dimen name="swipe_up_y_overshoot">10dp</dimen>
+    <dimen name="swipe_up_max_workspace_trans_y">-80dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 00e4a9d..5af09f7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -57,6 +57,7 @@
 import com.android.launcher3.views.FloatingIconView;
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.StaggeredWorkspaceAnim;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -151,8 +152,21 @@
             @NonNull
             @Override
             public AnimatorPlaybackController createActivityAnimationToHome() {
+                // Return an empty APC here since we have an non-user controlled animation to home.
                 long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
-                return activity.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy);
+                AnimatorSet as = new AnimatorSet();
+                as.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationStart(Animator animation) {
+                        activity.getStateManager().goToState(NORMAL, false);
+                    }
+                });
+                return AnimatorPlaybackController.wrap(as, accuracy);
+            }
+
+            @Override
+            public void playAtomicAnimation(float velocity) {
+                new StaggeredWorkspaceAnim(activity, workspaceView, velocity).start();
             }
         };
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index ca966c8..0d0478a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -1057,6 +1057,7 @@
                     setStateOnUiThread(target.endState);
                 }
             });
+            homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
             windowAnim.start(velocityPxPerMs);
             mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
             mLauncherTransitionController = null;
@@ -1134,12 +1135,10 @@
         // FolderIconView can be seen morphing into the icon shape.
         final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
         anim.addOnUpdateListener((currentRect, progress) -> {
-            float interpolatedProgress = Interpolators.ACCEL_1_5.getInterpolation(progress);
-
             homeAnim.setPlayFraction(progress);
 
-            float windowAlpha = Utilities.mapToRange(interpolatedProgress, 0,
-                    windowAlphaThreshold, 1f, 0f, Interpolators.LINEAR);
+            float windowAlpha = Math.max(0, Utilities.mapToRange(progress, 0,
+                    windowAlphaThreshold, 1f, 0f, Interpolators.LINEAR));
             mTransformParams.setProgress(progress)
                     .setCurrentRectAndTargetAlpha(currentRect, windowAlpha);
             mClipAnimationHelper.applyTransform(targetSet, mTransformParams,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
new file mode 100644
index 0000000..93b6e4b
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 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.util;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.anim.SpringObjectAnimator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+/**
+ * Creates an animation where all the workspace items are moved into their final location,
+ * staggered row by row from the bottom up.
+ * This is used in conjunction with the swipe up to home animation.
+ */
+public class StaggeredWorkspaceAnim {
+
+    private static final int APP_CLOSE_ROW_START_DELAY_MS = 16;
+    private static final int ALPHA_DURATION_MS = 200;
+
+    private static final float MAX_VELOCITY_PX_PER_S = 22f;
+
+    private static final float DAMPING_RATIO =
+            (SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY + SpringForce.DAMPING_RATIO_LOW_BOUNCY) / 2f;
+    private static final float STIFFNESS = SpringForce.STIFFNESS_LOW;
+
+    private final float mVelocity;
+    private final float mSpringTransY;
+    private final View mViewToIgnore;
+
+    private final List<ValueAnimator> mAnimators = new ArrayList<>();
+
+    /**
+     * @param floatingViewOriginalView The FloatingIconView's original view.
+     */
+    public StaggeredWorkspaceAnim(Launcher launcher, @Nullable View floatingViewOriginalView,
+            float velocity) {
+        mVelocity = velocity;
+        // We ignore this view since it's visibility and position is controlled by
+        // the FloatingIconView.
+        mViewToIgnore = floatingViewOriginalView;
+
+        // Scale the translationY based on the initial velocity to better sync the workspace items
+        // with the floating view.
+        float transFactor = 0.1f + 0.9f * Math.abs(velocity) / MAX_VELOCITY_PX_PER_S;
+        mSpringTransY = transFactor * launcher.getResources()
+                .getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);;
+
+        DeviceProfile grid = launcher.getDeviceProfile();
+        ShortcutAndWidgetContainer currentPage = ((CellLayout) launcher.getWorkspace()
+                .getChildAt(launcher.getWorkspace().getCurrentPage()))
+                .getShortcutsAndWidgets();
+
+        // Hotseat and QSB takes up two additional rows.
+        int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
+
+        // Set up springs on workspace items.
+        for (int i = currentPage.getChildCount() - 1; i >= 0; i--) {
+            View child = currentPage.getChildAt(i);
+            CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
+            addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows);
+        }
+
+        // Set up springs for the hotseat and qsb.
+        if (grid.isVerticalBarLayout()) {
+            ViewGroup hotseat = (ViewGroup) launcher.getHotseat().getChildAt(0);
+            for (int i = hotseat.getChildCount() - 1; i >= 0; i--) {
+                View child = hotseat.getChildAt(i);
+                CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
+                addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
+            }
+        } else {
+            View hotseat = launcher.getHotseat().getChildAt(0);
+            addStaggeredAnimationForView(hotseat, grid.inv.numRows + 1, totalRows);
+
+            View qsb = launcher.findViewById(R.id.search_container_all_apps);
+            addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
+        }
+    }
+
+    /**
+     * Starts the animation.
+     */
+    public void start() {
+        for (Animator a : mAnimators) {
+            if (a instanceof SpringObjectAnimator) {
+                ((SpringObjectAnimator) a).startSpring(1f, mVelocity, null);
+            } else {
+                a.start();
+            }
+        }
+    }
+
+    /**
+     * Adds an alpha/trans animator for {@param v}, with a start delay based on the view's row.
+     *
+     * @param v A view on the workspace.
+     * @param row The bottom-most row that contains the view.
+     * @param totalRows Total number of rows.
+     */
+    private void addStaggeredAnimationForView(View v, int row, int totalRows) {
+        if (v == mViewToIgnore) {
+            return;
+        }
+
+        // Invert the rows, because we stagger starting from the bottom of the screen.
+        int invertedRow = totalRows - row;
+        // Add 1 to the inverted row so that the bottom most row has a start delay.
+        long startDelay = (long) ((invertedRow + 1) * APP_CLOSE_ROW_START_DELAY_MS);
+
+        v.setTranslationY(mSpringTransY);
+        SpringObjectAnimator springTransY = new SpringObjectAnimator<>(
+                new ViewProgressProperty(v, View.TRANSLATION_Y), "staggeredSpringTransY", 1f,
+                DAMPING_RATIO, STIFFNESS, mSpringTransY, 0);
+        springTransY.setStartDelay(startDelay);
+        mAnimators.add(springTransY);
+
+        v.setAlpha(0);
+        ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
+        alpha.setInterpolator(LINEAR);
+        alpha.setDuration(ALPHA_DURATION_MS);
+        alpha.setStartDelay(startDelay);
+        mAnimators.add(alpha);
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 3364377..f8d454f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -52,6 +52,7 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -145,11 +146,13 @@
             };
 
     private final TaskOutlineProvider mOutlineProvider;
+    private final FooterOutlineProvider mFooterOutlineProvider;
 
     private Task mTask;
     private TaskThumbnailView mSnapshotView;
     private TaskMenuView mMenuView;
     private IconView mIconView;
+    private View mTaskFooterContainer;
     private DigitalWellBeingToast mDigitalWellBeingToast;
     private float mCurveScale;
     private float mFullscreenProgress;
@@ -180,6 +183,9 @@
         super(context, attrs, defStyleAttr);
         mActivity = BaseDraggingActivity.fromContext(context);
         setOnClickListener((view) -> {
+            if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+                android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "TaskView onClick");
+            }
             if (getTask() == null) {
                 return;
             }
@@ -203,6 +209,7 @@
         mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
         mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius);
         mOutlineProvider = new TaskOutlineProvider(getResources(), mCurrentFullscreenParams);
+        mFooterOutlineProvider = new FooterOutlineProvider(mCurrentFullscreenParams);
         setOutlineProvider(mOutlineProvider);
     }
 
@@ -212,6 +219,9 @@
         mSnapshotView = findViewById(R.id.snapshot);
         mIconView = findViewById(R.id.icon);
         mDigitalWellBeingToast = findViewById(R.id.digital_well_being_toast);
+        mTaskFooterContainer = findViewById(R.id.task_footer_container);
+        mTaskFooterContainer.setOutlineProvider(mFooterOutlineProvider);
+        mTaskFooterContainer.setClipToOutline(true);
     }
 
     public TaskMenuView getMenuView() {
@@ -279,6 +289,9 @@
 
     public void launchTask(boolean animate, boolean freezeTaskList, Consumer<Boolean> resultCallback,
             Handler resultCallbackHandler) {
+        if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+            android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "launchTask");
+        }
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             if (isRunningTask()) {
                 getRecentsView().finishRecentsAnimation(false /* toRecents */,
@@ -293,6 +306,9 @@
 
     private void launchTaskInternal(boolean animate, boolean freezeTaskList,
             Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
+        if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+            android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "launchTaskInternal");
+        }
         if (mTask != null) {
             final ActivityOptions opts;
             if (animate) {
@@ -410,6 +426,15 @@
                 .getInterpolation(progress);
         mIconView.setScaleX(scale);
         mIconView.setScaleY(scale);
+
+        int footerVerticalOffset = (int) (mTaskFooterContainer.getHeight() * (1.0f - scale));
+        mTaskFooterContainer.setTranslationY(
+                mCurrentFullscreenParams.mCurrentDrawnInsets.bottom +
+                mCurrentFullscreenParams.mCurrentDrawnInsets.top +
+                footerVerticalOffset);
+        mFooterOutlineProvider.setFullscreenDrawParams(
+                mCurrentFullscreenParams, footerVerticalOffset);
+        mTaskFooterContainer.invalidateOutline();
     }
 
     public void setIconScaleAnimStartProgress(float startProgress) {
@@ -550,6 +575,29 @@
         }
     }
 
+    private static final class FooterOutlineProvider extends ViewOutlineProvider {
+
+        private FullscreenDrawParams mFullscreenDrawParams;
+        private int mVerticalOffset;
+        private final Rect mOutlineRect = new Rect();
+
+        FooterOutlineProvider(FullscreenDrawParams params) {
+            mFullscreenDrawParams = params;
+        }
+
+        void setFullscreenDrawParams(FullscreenDrawParams params, int verticalOffset) {
+            mFullscreenDrawParams = params;
+            mVerticalOffset = verticalOffset;
+        }
+
+        @Override
+        public void getOutline(View view, Outline outline) {
+            mOutlineRect.set(0, 0, view.getWidth(), view.getHeight());
+            mOutlineRect.offset(0, -mVerticalOffset);
+            outline.setRoundRect(mOutlineRect, mFullscreenDrawParams.mCurrentDrawnCornerRadius);
+        }
+    }
+
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
@@ -639,7 +687,6 @@
         }
         mFullscreenProgress = progress;
         boolean isFullscreen = mFullscreenProgress > 0;
-        setIconScaleAndDim(progress, true /* invert */);
         mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
         setClipChildren(!isFullscreen);
         setClipToPadding(!isFullscreen);
@@ -663,6 +710,9 @@
                     / (getWidth() + currentInsetsLeft + currentInsetsRight));
         }
 
+        // Some of the items in here are dependent on the current fullscreen params
+        setIconScaleAndDim(progress, true /* invert */);
+
         thumbnail.setFullscreenParams(mCurrentFullscreenParams);
         mOutlineProvider.setFullscreenParams(mCurrentFullscreenParams);
         invalidateOutline();
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 95ae312..79540c1 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -278,7 +278,7 @@
         if (launcherClosing) {
             Pair<AnimatorSet, Runnable> launcherContentAnimator =
                     getLauncherContentAnimator(true /* isAppOpening */,
-                            new float[] {0, mContentTransY});
+                            new float[] {0, -mContentTransY});
             anim.play(launcherContentAnimator.first);
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index b0acd9b..279a946 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -143,5 +143,9 @@
         @NonNull RectF getWindowTargetRect();
 
         @NonNull AnimatorPlaybackController createActivityAnimationToHome();
+
+        default void playAtomicAnimation(float velocity) {
+            // No-op
+        }
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index e552f56..c3e46ea 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -133,7 +133,7 @@
 
                     for (int i = 0; i != 100; ++i) {
                         if (mLauncher.getNavigationModel() == expectedMode) {
-                            Thread.sleep(1000);
+                            Thread.sleep(5000);
                             return;
                         }
                         Thread.sleep(100);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 8a8a2fb..bde87cb 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -288,7 +288,9 @@
         InvariantDeviceProfile oldProfile = new InvariantDeviceProfile(this);
 
         // Re-init grid
-        initGrid(context, Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null));
+        // TODO(b/131867841): We pass in null here so that we can calculate the closest profile
+        // without the bias of the grid name.
+        initGrid(context, null);
 
         int changeFlags = 0;
         if (numRows != oldProfile.numRows ||
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 711cfd2..ed0b90f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -490,9 +490,7 @@
             mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
         }
 
-        if (supportsFakeLandscapeUI()
-                && mDeviceProfile.isVerticalBarLayout()
-                && !mDeviceProfile.isMultiWindowMode) {
+        if (supportsFakeLandscapeUI() && mDeviceProfile.isVerticalBarLayout()) {
             mStableDeviceProfile = mDeviceProfile.inv.portraitProfile;
             mRotationMode = UiFactory.getRotationMode(mDeviceProfile);
         } else {
@@ -500,6 +498,7 @@
             mRotationMode = RotationMode.NORMAL;
         }
 
+        mRotationHelper.updateRotationAnimation();
         onDeviceProfileInitiated();
         mModelWriter = mModel.getWriter(getWallpaperDeviceProfile().isVerticalBarLayout(), true);
     }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index e7b4ff4..ac392a6 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -165,17 +165,6 @@
         mBgAllAppsList = new AllAppsList(iconCache, appFilter);
     }
 
-    /** Runs the specified runnable immediately if called from the worker thread, otherwise it is
-     * posted on the worker thread handler. */
-    private static void runOnWorkerThread(Runnable r) {
-        if (sWorkerThread.getThreadId() == Process.myTid()) {
-            r.run();
-        } else {
-            // If we are not on the worker thread, then post to the worker handler
-            sWorker.post(r);
-        }
-    }
-
     public void setPackageState(PackageInstallInfo installInfo) {
         enqueueModelUpdateTask(new PackageInstallStateChangedTask(installInfo));
     }
@@ -400,7 +389,10 @@
         synchronized (mLock) {
             stopLoader();
             mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);
-            runOnWorkerThread(mLoaderTask);
+
+            // Always post the loader task, instead of running directly (even on same thread) so
+            // that we exit any nested synchronized blocks
+            sWorker.post(mLoaderTask);
         }
     }
 
@@ -505,7 +497,13 @@
 
     public void enqueueModelUpdateTask(ModelUpdateTask task) {
         task.init(mApp, this, sBgDataModel, mBgAllAppsList, mUiExecutor);
-        runOnWorkerThread(task);
+
+        if (sWorkerThread.getThreadId() == Process.myTid()) {
+            task.run();
+        } else {
+            // If we are not on the worker thread, then post to the worker handler
+            sWorker.post(task);
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 434918d..2ad92e1 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.AlphabeticIndexCompat;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LabelComparator;
@@ -300,6 +301,11 @@
     }
 
     private void refreshRecyclerView() {
+        if (TestProtocol.sDebugTracing) {
+            android.util.Log.d(TestProtocol.NO_START_TAG,
+                    "refreshRecyclerView @ " + android.util.Log.getStackTraceString(
+                            new Throwable()));
+        }
         if (mAdapter != null) {
             mAdapter.notifyDataSetChanged();
         }
diff --git a/src/com/android/launcher3/anim/SpringObjectAnimator.java b/src/com/android/launcher3/anim/SpringObjectAnimator.java
index f74590b..b1395af 100644
--- a/src/com/android/launcher3/anim/SpringObjectAnimator.java
+++ b/src/com/android/launcher3/anim/SpringObjectAnimator.java
@@ -22,6 +22,8 @@
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.Log;
 import android.util.Property;
 
@@ -139,7 +141,7 @@
     /**
      * Initializes and sets up the spring to take over controlling the object.
      */
-    void startSpring(float end, float velocity, OnAnimationEndListener endListener) {
+    public void startSpring(float end, float velocity, OnAnimationEndListener endListener) {
         // Cancel the spring so we can set new start velocity and final position. We need to remove
         // the listener since the spring is not actually ending.
         mSpring.removeEndListener(endListener);
@@ -149,7 +151,13 @@
         mProperty.switchToSpring();
 
         mSpring.setStartVelocity(velocity);
-        mSpring.animateToFinalPosition(end == 0 ? mValues[0] : mValues[1]);
+
+        float startValue = end == 0 ? mValues[1] : mValues[0];
+        float endValue = end == 0 ? mValues[0] : mValues[1];
+        mSpring.setStartValue(startValue);
+        new Handler(Looper.getMainLooper()).postDelayed(() -> {
+            mSpring.animateToFinalPosition(endValue);
+        }, getStartDelay());
     }
 
     @Override
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 81c95cb..43ae651 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -53,6 +53,9 @@
     }
 
     public static void sendStateEventToTest(Context context, int stateOrdinal) {
+        if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+            android.util.Log.e(TestProtocol.NO_ALLAPPS_EVENT_TAG, "sendStateEventToTest");
+        }
         final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
         if (accessibilityManager == null) return;
 
diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java
index f8b6242..41ab4df 100644
--- a/src/com/android/launcher3/popup/RemoteActionShortcut.java
+++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java
@@ -33,6 +33,7 @@
 
 public class RemoteActionShortcut extends SystemShortcut<BaseDraggingActivity> {
     private static final String TAG = "RemoteActionShortcut";
+    private static final boolean DEBUG = false;
 
     private final RemoteAction mAction;
 
@@ -48,7 +49,10 @@
         return view -> {
             AbstractFloatingView.closeAllOpenViews(activity);
 
+            final String actionIdentity = mAction.getTitle() + ", " +
+                    itemInfo.getTargetComponent().getPackageName();
             try {
+                if (DEBUG) Log.d(TAG, "Sending action: " + actionIdentity);
                 mAction.getActionIntent().send(
                         activity,
                         0,
@@ -56,15 +60,16 @@
                                 Intent.EXTRA_PACKAGE_NAME,
                                 itemInfo.getTargetComponent().getPackageName()),
                         (pendingIntent, intent, resultCode, resultData, resultExtras) -> {
+                            if (DEBUG) Log.d(TAG, "Action is complete: " + actionIdentity);
                             if (resultData != null && !resultData.isEmpty()) {
-                                Log.e(TAG, "Remote action returned result: " + mAction.getTitle()
+                                Log.e(TAG, "Remote action returned result: " + actionIdentity
                                         + " : " + resultData);
                                 Toast.makeText(activity, resultData, Toast.LENGTH_SHORT).show();
                             }
                         },
                         new Handler(Looper.getMainLooper()));
             } catch (PendingIntent.CanceledException e) {
-                Log.e(TAG, "Remote action canceled: " + mAction.getTitle(), e);
+                Log.e(TAG, "Remote action canceled: " + actionIdentity, e);
                 Toast.makeText(activity, activity.getString(
                         R.string.remote_action_failed,
                         mAction.getTitle()),
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index b6c3c35..cd96d6e 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -94,16 +94,20 @@
 
     public boolean homeScreenCanRotate() {
         return mIgnoreAutoRotateSettings || mAutoRotateEnabled
-                || mStateHandlerRequest != REQUEST_NONE;
+                || mStateHandlerRequest != REQUEST_NONE
+                || mLauncher.getDeviceProfile().isMultiWindowMode;
     }
 
-    private void updateRotationAnimation() {
+    public void updateRotationAnimation() {
         if (FeatureFlags.FAKE_LANDSCAPE_UI.get()) {
             WindowManager.LayoutParams lp = mLauncher.getWindow().getAttributes();
+            int oldAnim = lp.rotationAnimation;
             lp.rotationAnimation = homeScreenCanRotate()
                     ? WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE
                     : WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
-            mLauncher.getWindow().setAttributes(lp);
+            if (oldAnim != lp.rotationAnimation) {
+                mLauncher.getWindow().setAttributes(lp);
+            }
         }
     }
 
@@ -123,6 +127,7 @@
     public void setStateHandlerRequest(int request) {
         if (mStateHandlerRequest != request) {
             mStateHandlerRequest = request;
+            updateRotationAnimation();
             notifyChange();
         }
     }
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index a678ef2..99efb22 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -68,6 +68,8 @@
     public static boolean sDebugTracing = false;
     public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
     public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
+    public static final String NO_ALLAPPS_EVENT_TAG = "b/133867119";
     public static final String NO_DRAG_TAG = "b/133009122";
     public static final String NO_START_TAG = "b/132900132";
+    public static final String NO_START_TASK_TAG = "b/133765434";
 }
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 35fc873..9703aa6 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -43,6 +43,7 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -363,6 +364,9 @@
 
     @Override
     public void onDragEnd(float velocity, boolean fling) {
+        if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+            android.util.Log.e(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onDragEnd");
+        }
         final int logAction = fling ? Touch.FLING : Touch.SWIPE;
 
         boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
@@ -499,6 +503,9 @@
     }
 
     protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+        if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+            android.util.Log.e(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onSwipeInteractionCompleted 1");
+        }
         if (mAtomicComponentsController != null) {
             mAtomicComponentsController.getAnimationPlayer().end();
             mAtomicComponentsController = null;
@@ -517,6 +524,10 @@
             }
             mLauncher.getStateManager().goToState(targetState, false /* animated */);
 
+            if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+                android.util.Log.e(
+                        TestProtocol.NO_ALLAPPS_EVENT_TAG, "onSwipeInteractionCompleted 2");
+            }
             AccessibilityManagerCompat.sendStateEventToTest(mLauncher, targetState.ordinal);
         }
     }
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index 4e3dcf8..4616e58 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -25,6 +25,7 @@
 import android.view.ViewConfiguration;
 
 import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.TestProtocol;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
@@ -174,6 +175,11 @@
         }
 
         mState = newState;
+        if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
+            android.util.Log.e(TestProtocol.NO_ALLAPPS_EVENT_TAG,
+                    "setState: " + newState + " @ " + android.util.Log.getStackTraceString(
+                            new Throwable()));
+        }
     }
 
     public boolean isDraggingOrSettling() {
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 95b37bd..5f626a3 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -229,7 +229,7 @@
 
         mTaskCornerRadius = cornerRadius / scale;
         if (mIsAdaptiveIcon) {
-            if (!isOpening && shapeRevealProgress >= 0) {
+            if (!isOpening && progress >= shapeProgressStart) {
                 if (mRevealAnimator == null) {
                     mRevealAnimator = (ValueAnimator) IconShape.getShape().createRevealAnimator(
                             this, mStartRevealRect, mOutline, mTaskCornerRadius, !isOpening);
diff --git a/tests/Android.mk b/tests/Android.mk
index 978209f..0c41241 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -69,3 +69,5 @@
 LOCAL_INSTRUMENTATION_FOR := Launcher3
 
 include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/res/raw/aardwolf_dummy_app.apk b/tests/res/raw/aardwolf_dummy_app.apk
index 39fb368..c10732d 100644
--- a/tests/res/raw/aardwolf_dummy_app.apk
+++ b/tests/res/raw/aardwolf_dummy_app.apk
Binary files differ
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 44401c7..c7c36b0 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -192,6 +192,14 @@
                     ", track trace is below, UI object dump is further below:\n" +
                     Log.getStackTraceString(e));
             dumpViewHierarchy();
+
+            try {
+                final String dumpsysResult = mDevice.executeShellCommand(
+                                "dumpsys activity service TouchInteractionService");
+                Log.d(TAG, "TouchInteractionService: " + dumpsysResult);
+            } catch (IOException ex) {
+            }
+
             mDevice.takeScreenshot(new File(pathname));
         }
     };
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 4261988..5190f00 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -53,7 +53,7 @@
 
     private Background launch(BySelector selector) {
         LauncherInstrumentation.log("Launchable.launch before click " +
-                mObject.getVisibleCenter());
+                mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
         mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
         mLauncher.assertTrue(
                 "Launching an app didn't open a new window: " + mObject.getText(),
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 2ea7618..8b12464 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -20,6 +20,8 @@
 import androidx.test.uiautomator.UiObject2;
 import androidx.test.uiautomator.Until;
 
+import com.android.launcher3.testing.TestProtocol;
+
 /**
  * A recent task in the overview panel carousel.
  */
@@ -59,9 +61,14 @@
      */
     public Background open() {
         verifyActiveContainer();
-        mLauncher.assertTrue("Launching task didn't open a new window: " +
-                        mTask.getParent().getContentDescription(),
-                mTask.clickAndWait(Until.newWindow(), WAIT_TIME_MS));
+        mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "clicking an overview task")) {
+            mLauncher.assertTrue("Launching task didn't open a new window: " +
+                            mTask.getParent().getContentDescription(),
+                    mTask.clickAndWait(Until.newWindow(), WAIT_TIME_MS));
+        }
+        mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
         return new Background(mLauncher);
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 7dcc426..33754c1 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -66,6 +66,7 @@
                     "switchToAllApps: swipeHeight = " + swipeHeight + ", slop = "
                             + mLauncher.getTouchSlop());
 
+            mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
             mLauncher.swipeToState(
                     start.x,
                     start.y,
@@ -73,6 +74,7 @@
                     start.y - swipeHeight - mLauncher.getTouchSlop(),
                     60,
                     ALL_APPS_STATE_ORDINAL);
+            mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "swiped to all apps")) {