Snap for 11224086 from af26e5d2981417111779a9a05d645cbd1c6b695c to mainline-tzdata5-release

Change-Id: I64860fc034d7174fcf128ffa58cecc721b0bc450
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index ca9c577..f3e62c1 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -158,6 +158,7 @@
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.wm.shell.startingsurface.IStartingWindowListener;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -477,6 +478,9 @@
         });
     }
 
+    /** Dump debug logs to bug report. */
+    public void dump(@NonNull String prefix, @NonNull PrintWriter printWriter) {}
+
     /**
      * Content is everything on screen except the background and the floating view (if any).
      *
@@ -1046,7 +1050,7 @@
         boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW
                 && BlurUtils.supportsBlursOnWindows();
 
-        MyDepthController depthController = new MyDepthController(mLauncher);
+        LaunchDepthController depthController = new LaunchDepthController(mLauncher);
         ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController.stateDepth,
                         MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mLauncher))
                 .setDuration(APP_LAUNCH_DURATION);
@@ -2047,11 +2051,14 @@
         }
     }
 
-    private static class MyDepthController extends DepthController {
-        MyDepthController(Launcher l) {
-            super(l);
+    private static class LaunchDepthController extends DepthController {
+        LaunchDepthController(QuickstepLauncher launcher) {
+            super(launcher);
             setCrossWindowBlursEnabled(
                     CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled());
+            // Make sure that the starting value matches the current depth set by the main
+            // controller.
+            stateDepth.setValue(launcher.getDepthController().stateDepth.getValue());
         }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index ba6f165..abf49eb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -50,6 +50,7 @@
 import com.android.quickstep.views.RecentsView;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 
 /**
  * A data source which integrates with a Launcher instance
@@ -105,6 +106,10 @@
 
         // Restore the in-app display progress from before Taskbar was recreated.
         float[] prevProgresses = mControllers.getSharedState().inAppDisplayProgressMultiPropValues;
+        // Make a copy of the previous progress to set since updating the multiprop will update
+        // the property which also calls onInAppDisplayProgressChanged() which writes the current
+        // values into the shared state
+        prevProgresses = Arrays.copyOf(prevProgresses, prevProgresses.length);
         for (int i = 0; i < prevProgresses.length; i++) {
             mTaskbarInAppDisplayProgressMultiProp.get(i).setValue(prevProgresses[i]);
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 9a9e0ba..9c463cb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -923,6 +923,15 @@
         insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
     }
 
+    /**
+     * Called whenever a new ui controller is set, and should update anything that depends on the
+     * ui controller.
+     */
+    public void onUiControllerChanged() {
+        updateNavButtonInAppDisplayProgressForSysui();
+        updateNavButtonTranslationY();
+    }
+
     @Override
     public void dumpLogs(String prefix, PrintWriter pw) {
         pw.println(prefix + "NavbarButtonsViewController:");
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 43feec7..a1390ae 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -591,9 +591,7 @@
      * Sets a new data-source for this taskbar instance
      */
     public void setUIController(@NonNull TaskbarUIController uiController) {
-        mControllers.uiController.onDestroy();
-        mControllers.uiController = uiController;
-        mControllers.uiController.init(mControllers);
+        mControllers.setUiController(uiController);
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 66c2eb3..d3f80e3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -196,6 +196,19 @@
         mPostInitCallbacks.clear();
     }
 
+    /**
+     * Sets the ui controller.
+     */
+    public void setUiController(@NonNull TaskbarUIController newUiController) {
+        uiController.onDestroy();
+        uiController = newUiController;
+        uiController.init(this);
+        uiController.updateStateForSysuiFlags(mSharedState.sysuiStateFlags);
+
+        // Notify that the ui controller has changed
+        navbarButtonsViewController.onUiControllerChanged();
+    }
+
     @Nullable
     public TaskbarSharedState getSharedState() {
         // This should only be null if called before init() and after destroy().
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 2f13c5d..b621a28 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -204,6 +204,8 @@
 
     public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false;
 
+    protected static final String RING_APPEAR_ANIMATION_PREFIX = "RingAppearAnimation\t";
+
     private FixedContainerItems mAllAppsPredictions;
     private HotseatPredictionController mHotseatPredictionController;
     private DepthController mDepthController;
@@ -472,6 +474,10 @@
     public void onDestroy() {
         mAppTransitionManager.onActivityDestroyed();
         if (mUnfoldTransitionProgressProvider != null) {
+            if (FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) {
+                SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
+            }
+
             mUnfoldTransitionProgressProvider.destroy();
         }
 
@@ -1332,5 +1338,8 @@
         if (recentsView != null) {
             recentsView.getSplitSelectController().dump(prefix, writer);
         }
+        if (mAppTransitionManager != null) {
+            mAppTransitionManager.dump(prefix + "\t" + RING_APPEAR_ANIMATION_PREFIX, writer);
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 1913091..eff53f3 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -139,6 +139,7 @@
         mTmpMatrix.setScale(scale, scale,
                 app.localBounds.exactCenterX(), app.localBounds.exactCenterY());
         builder.setMatrix(mTmpMatrix).setAlpha(alpha);
+        builder.setShow();
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 523a98e..2256cbf 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -15,6 +15,7 @@
  */
 package com.android.quickstep;
 
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -37,6 +38,7 @@
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Set;
 
@@ -101,9 +103,22 @@
             RemoteAnimationTarget[] appTargets,
             RemoteAnimationTarget[] wallpaperTargets,
             Rect homeContentInsets, Rect minimizedHomeBounds) {
+        long appCount = Arrays.stream(appTargets)
+                .filter(app -> app.mode == MODE_CLOSING)
+                .count();
+        if (appCount == 0) {
+            // Edge case, if there are no closing app targets, then Launcher has nothing to handle
+            ActiveGestureLog.INSTANCE.addLog(
+                    /* event= */ "RecentsAnimationCallbacks.onAnimationStart (canceled)",
+                    /* extras= */ 0,
+                    /* gestureEvent= */ START_RECENTS_ANIMATION);
+            notifyAnimationCanceled();
+            animationController.finish(false /* toHome */, false /* sendUserLeaveHint */);
+            return;
+        }
+
         mController = new RecentsAnimationController(animationController,
                 mAllowMinimizeSplitScreen, this::onAnimationFinished);
-
         if (mCancelled) {
             Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
                     mController::finishAnimationToApp);
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 410ba21..eacca0d 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -19,6 +19,7 @@
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
 import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
@@ -37,6 +38,7 @@
 
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.views.DesktopTaskView;
@@ -162,10 +164,16 @@
 
                 for (RemoteAnimationTarget compat : appearedTaskTargets) {
                     if (compat.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME
-                            && activityInterface.getCreatedActivity() instanceof RecentsActivity) {
-                        // When receive opening home activity while recents is running, enter home
-                        // and dismiss recents.
-                        ((RecentsActivity) activityInterface.getCreatedActivity()).startHome();
+                            && activityInterface.getCreatedActivity() instanceof RecentsActivity
+                            && DisplayController.getNavigationMode(mCtx) != NO_BUTTON) {
+                        // The only time we get onTasksAppeared() in button navigation with a
+                        // 3p launcher is if the user goes to overview first, and in this case we
+                        // can immediately finish the transition
+                        RecentsView recentsView =
+                                activityInterface.getCreatedActivity().getOverviewPanel();
+                        if (recentsView != null) {
+                            recentsView.finishRecentsAnimation(true, null);
+                        }
                         return;
                     }
                 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index ab70272..eac09ad 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -103,7 +103,8 @@
         mStateCallback = new MultiStateCallback(STATE_NAMES);
         mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
                 this::endRemoteAnimation);
-        mStateCallback.runOnceAtState(STATE_FLING_FINISHED, this::onFlingFinished);
+        mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_FLING_FINISHED,
+                this::onFlingFinished);
 
         mSwipeDetector = new SingleAxisSwipeDetector(mContext, this, VERTICAL);
         mSwipeDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 2eaff46..6619dd8 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -254,6 +254,9 @@
         mBinder.setSwipeUpProxy(isResumed() ? this::createSwipeUpProxy : null);
         mBinder.setOverviewTargetChangeListener(mBinder::preloadOverviewForSUWAllSet);
         mBinder.preloadOverviewForSUWAllSet();
+        if (mTaskbarManager != null) {
+            mLauncherStartAnim = mTaskbarManager.createLauncherStartFromSuwAnim(MAX_SWIPE_DURATION);
+        }
     }
 
     @Override
@@ -328,12 +331,9 @@
         mRootView.setAlpha(alpha);
         mRootView.setTranslationY((alpha - 1) * mSwipeUpShift);
 
-        if (mLauncherStartAnim == null && mTaskbarManager != null) {
-            mLauncherStartAnim = mTaskbarManager.createLauncherStartFromSuwAnim(MAX_SWIPE_DURATION);
-        }
         if (mLauncherStartAnim != null) {
-            mLauncherStartAnim.setPlayFraction(Utilities.mapBoundToRange(
-                    mSwipeProgress.value, 0, 1, 0, 1, FAST_OUT_SLOW_IN));
+            mLauncherStartAnim.setPlayFraction(
+                    FAST_OUT_SLOW_IN.getInterpolation(mSwipeProgress.value));
         }
         maybeResumeOrPauseBackgroundAnimation();
     }
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index 6d15e8b..e0b5272 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -60,6 +60,8 @@
     private final NaturalRotationUnfoldProgressProvider mNaturalOrientationProgressProvider;
     private final UnfoldMoveFromCenterHotseatAnimator mUnfoldMoveFromCenterHotseatAnimator;
     private final UnfoldMoveFromCenterWorkspaceAnimator mUnfoldMoveFromCenterWorkspaceAnimator;
+    private final TransitionStatusProvider mExternalTransitionStatusProvider =
+            new TransitionStatusProvider();
     private PreemptiveUnfoldTransitionProgressProvider mPreemptiveProgressProvider = null;
     private Boolean mIsTablet = null;
 
@@ -88,6 +90,8 @@
                     unfoldTransitionProgressProvider);
         }
 
+        unfoldTransitionProgressProvider.addCallback(mExternalTransitionStatusProvider);
+
         mUnfoldMoveFromCenterHotseatAnimator = new UnfoldMoveFromCenterHotseatAnimator(launcher,
                 windowManager, rotationChangeProvider);
         mUnfoldMoveFromCenterWorkspaceAnimator = new UnfoldMoveFromCenterWorkspaceAnimator(launcher,
@@ -166,11 +170,26 @@
         }
 
         if (mIsTablet != null && dp.isTablet != mIsTablet) {
-            if (dp.isTablet && SystemUiProxy.INSTANCE.get(mLauncher).isActive()) {
+            // We should preemptively start the animation only if:
+            // - We changed to the unfolded screen
+            // - SystemUI IPC connection is alive, so we won't end up in a situation that we won't
+            //   receive transition progress events from SystemUI later because there was no
+            //   IPC connection established (e.g. because of SystemUI crash)
+            // - SystemUI has not already sent unfold animation progress events. This might happen
+            //   if Launcher was not open during unfold, in this case we receive the configuration
+            //   change only after we went back to home screen and we don't want to start the
+            //   animation in this case.
+            if (dp.isTablet
+                    && SystemUiProxy.INSTANCE.get(mLauncher).isActive()
+                    && !mExternalTransitionStatusProvider.hasRun()) {
                 // Preemptively start the unfold animation to make sure that we have drawn
                 // the first frame of the animation before the screen gets unblocked
                 preemptivelyStartAnimationOnNextFrame();
             }
+
+            if (!dp.isTablet) {
+                mExternalTransitionStatusProvider.onFolded();
+            }
         }
 
         mIsTablet = dp.isTablet;
@@ -222,4 +241,48 @@
             HOTSEAT_SCALE_PROPERTY.setValue(mLauncher.getHotseat(), value);
         }
     }
+
+    /**
+     * Class to track the current status of the external transition provider (the events are coming
+     * from the SystemUI side through IPC), it allows to check if the transition has already
+     * finished or currently running on the SystemUI side since last unfold.
+     */
+    private static class TransitionStatusProvider implements TransitionProgressListener {
+
+        private boolean mHasRun = false;
+
+        @Override
+        public void onTransitionStarted() {
+            markAsRun();
+        }
+
+        @Override
+        public void onTransitionProgress(float progress) {
+            markAsRun();
+        }
+
+        @Override
+        public void onTransitionFinished() {
+            markAsRun();
+        }
+
+        /**
+         * Called when the device is folded, so we can reset the status of the animation
+         */
+        public void onFolded() {
+            mHasRun = false;
+        }
+
+        /**
+         * Returns true if there was an animation already (or it is currently running) after
+         * unfolding the device
+         */
+        public boolean hasRun() {
+            return mHasRun;
+        }
+
+        private void markAsRun() {
+            mHasRun = true;
+        }
+    }
 }
diff --git a/res/color-v31/surface.xml b/res/color-v31/surface.xml
deleted file mode 100644
index da4571a..0000000
--- a/res/color-v31/surface.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-<selector
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/materialColorSurfaceContainerHighest"/>
-</selector>
-
diff --git a/res/drawable/add_item_dialog_background.xml b/res/drawable/add_item_dialog_background.xml
index c3a8269..e279fa0 100644
--- a/res/drawable/add_item_dialog_background.xml
+++ b/res/drawable/add_item_dialog_background.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle" >
-    <solid android:color="@color/surface" />
+    <solid android:color="@color/material_color_surface_container_highest" />
     <corners
         android:topLeftRadius="?android:attr/dialogCornerRadius"
         android:topRightRadius="?android:attr/dialogCornerRadius" />
diff --git a/res/drawable/button_top_rounded_bordered_ripple.xml b/res/drawable/button_top_rounded_bordered_ripple.xml
index f15a4a0..f5b6886 100644
--- a/res/drawable/button_top_rounded_bordered_ripple.xml
+++ b/res/drawable/button_top_rounded_bordered_ripple.xml
@@ -25,7 +25,7 @@
                     android:topRightRadius="12dp"
                     android:bottomLeftRadius="4dp"
                     android:bottomRightRadius="4dp"  />
-                <solid android:color="@color/surface"/>
+                <solid android:color="@color/material_color_surface_container_highest"/>
                 <stroke
                     android:width="2dp"
                     android:color="@color/button_bg"/>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 25eb160..6669043 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2194,6 +2194,8 @@
 
     /**
      * Returns the CellLayout of the specified container at the specified screen.
+     *
+     * @param screenId must be presenterPos and not modelPos.
      */
     public CellLayout getCellLayout(int container, int screenId) {
         return (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 8b124dc..6097fb1 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -331,8 +331,7 @@
      * Gets the translation provider for workspace pages.
      */
     public PageTranslationProvider getWorkspacePageTranslationProvider(Launcher launcher) {
-        if (this != SPRING_LOADED
-                || this != EDIT_MODE
+        if (!(this == SPRING_LOADED || this == EDIT_MODE)
                 || !launcher.getDeviceProfile().isTwoPanels) {
             return DEFAULT_PAGE_TRANSLATION_PROVIDER;
         }
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index d4140d8..1977704 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -43,7 +43,6 @@
 import android.util.FloatProperty;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.TypedValue;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -272,9 +271,8 @@
                 0,
                 0 // Bottom left
         };
-        final TypedValue value = new TypedValue();
-        getContext().getTheme().resolveAttribute(android.R.attr.colorBackground, value, true);
-        mBottomSheetBackgroundColor = value.data;
+        mBottomSheetBackgroundColor =
+                Themes.getAttrColor(getContext(), R.attr.materialColorSurfaceDim);
         updateBackgroundVisibility(mActivityContext.getDeviceProfile());
         mSearchUiManager.initializeSearch(this);
     }
diff --git a/src/com/android/launcher3/celllayout/MulticellReorderAlgorithm.java b/src/com/android/launcher3/celllayout/MulticellReorderAlgorithm.java
index cb12161..a2e26b3 100644
--- a/src/com/android/launcher3/celllayout/MulticellReorderAlgorithm.java
+++ b/src/com/android/launcher3/celllayout/MulticellReorderAlgorithm.java
@@ -19,8 +19,10 @@
 
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.MultipageCellLayout;
+import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.util.GridOccupancy;
 
+import java.util.Arrays;
 import java.util.function.Supplier;
 
 /**
@@ -79,7 +81,7 @@
         lp.canReorder = false;
         mcl.setCountX(mcl.getCountX() + 1);
         mcl.getShortcutsAndWidgets().addViewInLayout(mSeam, lp);
-        mcl.setOccupied(createGridOccupancyWithSeam(mcl.getOccupied()));
+        mcl.setOccupied(createGridOccupancyWithSeam());
         mcl.mTmpOccupied = new GridOccupancy(mcl.getCountX(), mcl.getCountY());
     }
 
@@ -93,7 +95,8 @@
 
     /**
      * The function supplied here will execute while the CellLayout has a simulated seam added.
-     * @param f function to run under simulation
+     *
+     * @param f   function to run under simulation
      * @param <T> return value of the supplied function
      * @return Value of supplied function
      */
@@ -110,18 +113,17 @@
         return res;
     }
 
-    GridOccupancy createGridOccupancyWithSeam(GridOccupancy gridOccupancy) {
+    GridOccupancy createGridOccupancyWithSeam() {
+        ShortcutAndWidgetContainer shortcutAndWidgets = mCellLayout.getShortcutsAndWidgets();
         GridOccupancy grid = new GridOccupancy(mCellLayout.getCountX(), mCellLayout.getCountY());
-        for (int x = 0; x < mCellLayout.getCountX(); x++) {
-            for (int y = 0; y < mCellLayout.getCountY(); y++) {
-                int offset = x >= mCellLayout.getCountX() / 2 ? 1 : 0;
-                if (x == mCellLayout.getCountX() / 2) {
-                    grid.cells[x][y] = true;
-                } else {
-                    grid.cells[x][y] = gridOccupancy.cells[x - offset][y];
-                }
-            }
+        for (int i = 0; i < shortcutAndWidgets.getChildCount(); i++) {
+            View view = shortcutAndWidgets.getChildAt(i);
+            CellLayoutLayoutParams lp = (CellLayoutLayoutParams) view.getLayoutParams();
+            int seamOffset = lp.getCellX() >= mCellLayout.getCountX() / 2 && lp.canReorder ? 1 : 0;
+            grid.markCells(lp.getCellX() + seamOffset, lp.getCellY(), lp.cellHSpan, lp.cellVSpan,
+                    true);
         }
+        Arrays.fill(grid.cells[mCellLayout.getCountX() / 2], true);
         return grid;
     }
 }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index f5f6769..76574b6 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -194,7 +194,7 @@
             "In foldables, when reordering the icons and widgets, is now going to use both sides");
 
     public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
-            "FOLDABLE_SINGLE_PAGE", ENABLED, "Use a single page for the workspace");
+            "FOLDABLE_SINGLE_PAGE", DISABLED, "Use a single page for the workspace");
 
     // TODO(Block 12): Clean up flags
     public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680,
@@ -302,7 +302,7 @@
             "Enable widget transition animation when resizing the widgets");
 
     public static final BooleanFlag PREEMPTIVE_UNFOLD_ANIMATION_START = getDebugFlag(270397209,
-            "PREEMPTIVE_UNFOLD_ANIMATION_START", DISABLED,
+            "PREEMPTIVE_UNFOLD_ANIMATION_START", ENABLED,
             "Enables starting the unfold animation preemptively when unfolding, without"
                     + "waiting for SystemUI and then merging the SystemUI progress whenever we "
                     + "start receiving the events");
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
index f15dc83..7ac2472 100644
--- a/src/com/android/launcher3/folder/LauncherDelegate.java
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -93,7 +93,7 @@
                         // Move the item from the folder to the workspace, in the position of the
                         // folder
                         CellLayout cellLayout = mLauncher.getCellLayout(info.container,
-                                info.screenId);
+                                mLauncher.getCellPosMapper().mapModelToPresenter(info).screenId);
                         if (cellLayout == null) {
                             return;
                         }
diff --git a/src/com/android/launcher3/util/EventLogArray.kt b/src/com/android/launcher3/util/EventLogArray.kt
new file mode 100644
index 0000000..a17d650
--- /dev/null
+++ b/src/com/android/launcher3/util/EventLogArray.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2023 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.launcher3.util
+
+import java.io.PrintWriter
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+/**
+ * A utility class to record and log events. Events are stored in a fixed size array and old logs
+ * are purged as new events come.
+ */
+class EventLogArray(private val name: String, size: Int) {
+
+    companion object {
+        private const val TYPE_ONE_OFF = 0
+        private const val TYPE_FLOAT = 1
+        private const val TYPE_INTEGER = 2
+        private const val TYPE_BOOL_TRUE = 3
+        private const val TYPE_BOOL_FALSE = 4
+        private fun isEntrySame(entry: EventEntry?, type: Int, event: String): Boolean {
+            return entry != null && entry.type == type && entry.event == event
+        }
+    }
+
+    private val logs: Array<EventEntry?>
+    private var nextIndex = 0
+
+    init {
+        logs = arrayOfNulls(size)
+    }
+
+    fun addLog(event: String) {
+        addLog(TYPE_ONE_OFF, event, 0f)
+    }
+
+    fun addLog(event: String, extras: Int) {
+        addLog(TYPE_INTEGER, event, extras.toFloat())
+    }
+
+    fun addLog(event: String, extras: Float) {
+        addLog(TYPE_FLOAT, event, extras)
+    }
+
+    fun addLog(event: String, extras: Boolean) {
+        addLog(if (extras) TYPE_BOOL_TRUE else TYPE_BOOL_FALSE, event, 0f)
+    }
+
+    private fun addLog(type: Int, event: String, extras: Float) {
+        // Merge the logs if it's a duplicate
+        val last = (nextIndex + logs.size - 1) % logs.size
+        val secondLast = (nextIndex + logs.size - 2) % logs.size
+        if (isEntrySame(logs[last], type, event) && isEntrySame(logs[secondLast], type, event)) {
+            logs[last]!!.update(type, event, extras)
+            logs[secondLast]!!.duplicateCount++
+            return
+        }
+        if (logs[nextIndex] == null) {
+            logs[nextIndex] = EventEntry()
+        }
+        logs[nextIndex]!!.update(type, event, extras)
+        nextIndex = (nextIndex + 1) % logs.size
+    }
+
+    fun dump(prefix: String, writer: PrintWriter) {
+        writer.println("$prefix$name event history:")
+        val sdf = SimpleDateFormat("  HH:mm:ss.SSSZ  ", Locale.US)
+        val date = Date()
+        for (i in logs.indices) {
+            val log = logs[(nextIndex + logs.size - i - 1) % logs.size] ?: continue
+            date.time = log.time
+            val msg = StringBuilder(prefix).append(sdf.format(date)).append(log.event)
+            when (log.type) {
+                TYPE_BOOL_FALSE -> msg.append(": false")
+                TYPE_BOOL_TRUE -> msg.append(": true")
+                TYPE_FLOAT -> msg.append(": ").append(log.extras)
+                TYPE_INTEGER -> msg.append(": ").append(log.extras.toInt())
+                else -> {}
+            }
+            if (log.duplicateCount > 0) {
+                msg.append(" & ").append(log.duplicateCount).append(" similar events")
+            }
+            writer.println(msg)
+        }
+    }
+
+    /** A single event entry. */
+    private class EventEntry {
+        var type = 0
+        var event: String? = null
+        var extras = 0f
+        var time: Long = 0
+        var duplicateCount = 0
+        fun update(type: Int, event: String, extras: Float) {
+            this.type = type
+            this.event = event
+            this.extras = extras
+            time = System.currentTimeMillis()
+            duplicateCount = 0
+        }
+    }
+}