Merge "Add a boolean to track QSB edu card dismissal." into tm-qpr-dev
diff --git a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java b/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
index 2ffb28e..0c1f05f 100644
--- a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
+++ b/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
@@ -25,12 +25,14 @@
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.testing.DebugTestInformationHandler;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.util.TISBindHelper;
 
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
 
 /**
  * Class to handle requests from tests, including debug ones, to Quickstep Launcher builds.
@@ -49,29 +51,26 @@
         Bundle response = new Bundle();
         switch (method) {
             case TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING:
-                runOnUIThread(l -> {
-                    enableManualTaskbarStashing(l, true);
+                runOnTISBinder(tisBinder -> {
+                    enableManualTaskbarStashing(tisBinder, true);
                 });
                 return response;
 
             case TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING:
-                runOnUIThread(l -> {
-                    enableManualTaskbarStashing(l, false);
+                runOnTISBinder(tisBinder -> {
+                    enableManualTaskbarStashing(tisBinder, false);
                 });
                 return response;
 
             case TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED:
-                runOnUIThread(l -> {
-                    enableManualTaskbarStashing(l, true);
-
-                    QuickstepLauncher quickstepLauncher = (QuickstepLauncher) l;
-                    LauncherTaskbarUIController taskbarUIController =
-                            quickstepLauncher.getTaskbarUIController();
+                runOnTISBinder(tisBinder -> {
+                    enableManualTaskbarStashing(tisBinder, true);
 
                     // Allow null-pointer to catch illegal states.
-                    taskbarUIController.unstashTaskbarIfStashed();
+                    tisBinder.getTaskbarManager().getCurrentActivityContext()
+                            .unstashTaskbarIfStashed();
 
-                    enableManualTaskbarStashing(l, false);
+                    enableManualTaskbarStashing(tisBinder, false);
                 });
                 return response;
 
@@ -82,6 +81,11 @@
                 return response;
             }
 
+            case TestProtocol.REQUEST_RECREATE_TASKBAR:
+                // Allow null-pointer to catch illegal states.
+                runOnTISBinder(tisBinder -> tisBinder.getTaskbarManager().recreateTaskbar());
+                return response;
+
             default:
                 response = super.call(method, arg, extras);
                 if (response != null) return response;
@@ -89,24 +93,26 @@
         }
     }
 
-    private void enableManualTaskbarStashing(Launcher launcher, boolean enable) {
-        QuickstepLauncher quickstepLauncher = (QuickstepLauncher) launcher;
-        LauncherTaskbarUIController taskbarUIController =
-                quickstepLauncher.getTaskbarUIController();
-
+    private void enableManualTaskbarStashing(TISBinder tisBinder, boolean enable) {
         // Allow null-pointer to catch illegal states.
-        taskbarUIController.enableManualStashingForTests(enable);
+        tisBinder.getTaskbarManager().getCurrentActivityContext().enableManualStashingForTests(
+                enable);
     }
 
     /**
-     * Runs the given command on the UI thread.
+     * Runs the given command on the UI thread, after ensuring we are connected to
+     * TouchInteractionService.
      */
-    private static void runOnUIThread(UIThreadCommand command) {
+    private void runOnTISBinder(Consumer<TISBinder> connectionCallback) {
         try {
-            MAIN_EXECUTOR.submit(() -> {
-                command.execute(Launcher.ACTIVITY_TRACKER.getCreatedActivity());
-                return null;
-            }).get();
+            CountDownLatch countDownLatch = new CountDownLatch(1);
+            TISBindHelper helper = MAIN_EXECUTOR.submit(() ->
+                    new TISBindHelper(mContext, tisBinder -> {
+                        connectionCallback.accept(tisBinder);
+                        countDownLatch.countDown();
+                    })).get();
+            countDownLatch.await();
+            MAIN_EXECUTOR.submit(helper::onDestroy);
         } catch (ExecutionException | InterruptedException e) {
             throw new RuntimeException(e);
         }
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 770dfb2..de0b14d 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -117,14 +117,15 @@
         // TODO: Implement caching and preloading
         super.loadItems(ums, pinnedShortcuts);
 
-        WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(
-                mApp, ums, pinnedShortcuts, mIDP.numDatabaseAllAppsColumns);
-        FixedContainerItems allAppsItems = new FixedContainerItems(mAllAppsState.containerId,
-                mAllAppsState.storage.read(mApp.getContext(), allAppsFactory, ums.allUsers::get));
-        mDataModel.extraItems.put(mAllAppsState.containerId, allAppsItems);
+        WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
+                mIDP.numDatabaseAllAppsColumns, mAllAppsState.containerId);
+        FixedContainerItems allAppsPredictionItems = new FixedContainerItems(
+                mAllAppsState.containerId, mAllAppsState.storage.read(mApp.getContext(),
+                allAppsFactory, ums.allUsers::get));
+        mDataModel.extraItems.put(mAllAppsState.containerId, allAppsPredictionItems);
 
-        WorkspaceItemFactory hotseatFactory =
-                new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, mIDP.numDatabaseHotseatIcons);
+        WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
+                mIDP.numDatabaseHotseatIcons, mHotseatState.containerId);
         FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId,
                 mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get));
         mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems);
@@ -432,15 +433,17 @@
         private final UserManagerState mUMS;
         private final Map<ShortcutKey, ShortcutInfo> mPinnedShortcuts;
         private final int mMaxCount;
+        private final int mContainer;
 
         private int mReadCount = 0;
 
         protected WorkspaceItemFactory(LauncherAppState appState, UserManagerState ums,
-                Map<ShortcutKey, ShortcutInfo> pinnedShortcuts, int maxCount) {
+                Map<ShortcutKey, ShortcutInfo> pinnedShortcuts, int maxCount, int container) {
             mAppState = appState;
             mUMS = ums;
             mPinnedShortcuts = pinnedShortcuts;
             mMaxCount = maxCount;
+            mContainer = container;
         }
 
         @Nullable
@@ -458,6 +461,7 @@
                         return null;
                     }
                     AppInfo info = new AppInfo(lai, user, mUMS.isUserQuiet(user));
+                    info.container = mContainer;
                     mAppState.getIconCache().getTitleAndIcon(info, lai, false);
                     mReadCount++;
                     return info.makeWorkspaceItem(mAppState.getContext());
@@ -472,6 +476,7 @@
                         return null;
                     }
                     WorkspaceItemInfo wii = new WorkspaceItemInfo(si, mAppState.getContext());
+                    wii.container = mContainer;
                     mAppState.getIconCache().getShortcutIcon(wii, si);
                     mReadCount++;
                     return wii;
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 1311b1d..4b8b5f7 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -141,7 +141,7 @@
 
     @Override
     public void setState(LauncherState toState) {
-        if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) {
+        if (mIgnoreStateChangesDuringMultiWindowAnimation) {
             return;
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
index d69b8d2..9393b0f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
@@ -43,8 +43,8 @@
         mLauncher.getHotseat().setIconsAlpha(1f);
     }
 
-    @Override
     /** Disable taskbar stashing in desktop environment. */
+    @Override
     public boolean supportsVisualStashing() {
         return false;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 6c740ba..520487e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_RESUMED;
+import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
 
 import android.animation.Animator;
@@ -30,7 +31,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherState;
@@ -124,24 +124,6 @@
     }
 
     /**
-     * Enables manual taskbar stashing. This method should only be used for tests that need to
-     * stash/unstash the taskbar.
-     */
-    @VisibleForTesting
-    public void enableManualStashingForTests(boolean enableManualStashing) {
-        mControllers.taskbarStashController.enableManualStashingForTests(enableManualStashing);
-    }
-
-    /**
-     * Unstashes the Taskbar if it is stashed. This method should only be used to unstash the
-     * taskbar at the end of a test.
-     */
-    @VisibleForTesting
-    public void unstashTaskbarIfStashed() {
-        mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
-    }
-
-    /**
      * Adds the Launcher resume animator to the given animator set.
      *
      * This should be used to run a Launcher resume animation whose progress matches a
@@ -188,6 +170,13 @@
             }
         }
 
+        if (ENABLE_SHELL_TRANSITIONS
+                && !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) {
+            // Launcher is resumed, but in a state where taskbar is still independent, so
+            // ignore the state change.
+            return null;
+        }
+
         mTaskbarLauncherStateController.updateStateForFlag(FLAG_RESUMED, isResumed);
         return mTaskbarLauncherStateController.applyState(fromInit ? 0 : duration, startAnimation);
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index f1f18c1..4fda50e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar;
 
+import static android.view.View.AccessibilityDelegate;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
@@ -582,6 +583,26 @@
         return mHomeButtonAlpha;
     }
 
+    /**
+     * Sets the AccessibilityDelegate for the home button.
+     */
+    public void setHomeButtonAccessibilityDelegate(AccessibilityDelegate accessibilityDelegate) {
+        if (mHomeButton == null) {
+            return;
+        }
+        mHomeButton.setAccessibilityDelegate(accessibilityDelegate);
+    }
+
+    /**
+     * Sets the AccessibilityDelegate for the back button.
+     */
+    public void setBackButtonAccessibilityDelegate(AccessibilityDelegate accessibilityDelegate) {
+        if (mBackButton == null) {
+            return;
+        }
+        mBackButton.setAccessibilityDelegate(accessibilityDelegate);
+    }
+
     /** Use to set the translationY for the all nav+contextual buttons */
     public AnimatedFloat getTaskbarNavButtonTranslationY() {
         return mTaskbarNavButtonTranslationY;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index e1bcbe2..3b1e677 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -773,6 +773,24 @@
         mControllers.taskbarStashController.startUnstashHint(animateForward);
     }
 
+    /**
+     * Enables manual taskbar stashing. This method should only be used for tests that need to
+     * stash/unstash the taskbar.
+     */
+    @VisibleForTesting
+    public void enableManualStashingForTests(boolean enableManualStashing) {
+        mControllers.taskbarStashController.enableManualStashingForTests(enableManualStashing);
+    }
+
+    /**
+     * Unstashes the Taskbar if it is stashed. This method should only be used to unstash the
+     * taskbar at the end of a test.
+     */
+    @VisibleForTesting
+    public void unstashTaskbarIfStashed() {
+        mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
+    }
+
     protected boolean isUserSetupComplete() {
         return mIsUserSetupComplete;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index c99cebb..6c793a6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -18,13 +18,17 @@
 
 import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
 import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 
 import static com.android.launcher3.taskbar.NavbarButtonsViewController.ALPHA_INDEX_IMMERSIVE_MODE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IMMERSIVE_MODE;
 
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.view.MotionEvent;
+import android.view.View;
 
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -52,6 +56,21 @@
             this::updateIconDimmingAlpha);
     private final Consumer<MultiValueAlpha> mImmersiveModeAlphaUpdater = alpha -> alpha.getProperty(
             ALPHA_INDEX_IMMERSIVE_MODE).setValue(mIconAlphaForDimming.value);
+    private final View.AccessibilityDelegate mKidsModeAccessibilityDelegate =
+            new View.AccessibilityDelegate() {
+                @Override
+                public boolean performAccessibilityAction(View host, int action, Bundle args) {
+                    if (action == ACTION_ACCESSIBILITY_FOCUS || action == ACTION_CLICK) {
+                        // Animate undimming of icons on an a11y event, followed by starting the
+                        // dimming animation (after its timeout has expired). Both can be called in
+                        // succession, as the playing of the two animations in a row is managed by
+                        // mHandler's message queue.
+                        startIconUndimming();
+                        startIconDimming();
+                    }
+                    return super.performAccessibilityAction(host, action, args);
+                }
+            };
 
     // Initialized in init.
     private TaskbarControllers mControllers;
@@ -77,12 +96,21 @@
             } else {
                 startIconUndimming();
             }
+            mControllers.navbarButtonsViewController.setHomeButtonAccessibilityDelegate(
+                    mKidsModeAccessibilityDelegate);
+            mControllers.navbarButtonsViewController.setBackButtonAccessibilityDelegate(
+                    mKidsModeAccessibilityDelegate);
+        } else {
+            mControllers.navbarButtonsViewController.setHomeButtonAccessibilityDelegate(null);
+            mControllers.navbarButtonsViewController.setBackButtonAccessibilityDelegate(null);
         }
     }
 
     /** Clean up animations. */
     public void onDestroy() {
         startIconUndimming();
+        mControllers.navbarButtonsViewController.setHomeButtonAccessibilityDelegate(null);
+        mControllers.navbarButtonsViewController.setBackButtonAccessibilityDelegate(null);
     }
 
     private void startIconUndimming() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 35c5b96..80b3c1d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -36,6 +36,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherAppState;
@@ -277,7 +278,8 @@
      * we fully want to destroy an existing taskbar and create a new one.
      * In other case (folding/unfolding) we don't need to remove and add window.
      */
-    private void recreateTaskbar() {
+    @VisibleForTesting
+    public void recreateTaskbar() {
         DeviceProfile dp = mUserUnlocked ?
                 LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 3ea9173..d9d55e7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -210,7 +210,10 @@
                 StashedHandleViewController.ALPHA_INDEX_STASHED);
         mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale();
 
-        boolean isManuallyStashedInApp = supportsManualStashing()
+        // We use supportsVisualStashing() here instead of supportsManualStashing() because we want
+        // it to work properly for tests that recreate taskbar. This check is here just to ensure
+        // that taskbar unstashes when going to 3 button mode (supportsVisualStashing() false).
+        boolean isManuallyStashedInApp = supportsVisualStashing()
                 && mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
         boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
         updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
@@ -218,7 +221,10 @@
         updateStateForFlag(FLAG_IN_SETUP, isInSetup);
         updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, isPhoneMode()
                 && !mActivity.isThreeButtonNav());
-        applyState();
+        // For now, assume we're in an app, since LauncherTaskbarUIController won't be able to tell
+        // us that we're paused until a bit later. This avoids flickering upon recreating taskbar.
+        updateStateForFlag(FLAG_IN_APP, true);
+        applyState(/* duration = */ 0);
 
         notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
     }
@@ -228,8 +234,7 @@
      * state.
      */
     public boolean supportsVisualStashing() {
-        return mControllers.uiController.supportsVisualStashing() ||
-                (isPhoneMode() && !mActivity.isThreeButtonNav());
+        return !mActivity.isThreeButtonNav() && mControllers.uiController.supportsVisualStashing();
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index fcc34c6..114bfec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -49,9 +49,13 @@
         return true;
     }
 
+    /**
+     * This should only be called by TaskbarStashController so that a TaskbarUIController can
+     * disable stashing. All other controllers should use
+     * {@link TaskbarStashController#supportsVisualStashing()} as the source of truth.
+     */
     public boolean supportsVisualStashing() {
-        if (mControllers == null) return false;
-        return !mControllers.taskbarActivityContext.isThreeButtonNav();
+        return true;
     }
 
     protected void onStashedInAppChanged() { }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index c4837a0..0e62da3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -16,8 +16,7 @@
 package com.android.launcher3.taskbar.allapps;
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
-import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
 
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
@@ -60,7 +59,7 @@
         if (animate) {
             mOpenCloseAnimator.setValues(
                     PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
-            mOpenCloseAnimator.setInterpolator(AGGRESSIVE_EASE);
+            mOpenCloseAnimator.setInterpolator(EMPHASIZED);
             mOpenCloseAnimator.setDuration(
                     ALL_APPS.getTransitionDuration(mActivityContext, true /* isToState */)).start();
         } else {
@@ -87,7 +86,7 @@
 
     @Override
     protected Interpolator getIdleInterpolator() {
-        return EMPHASIZED_ACCELERATE;
+        return EMPHASIZED;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 0f3ea15..c9bc260 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -64,6 +64,7 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.IBinder;
+import android.os.SystemProperties;
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
 import android.view.View;
@@ -159,6 +160,9 @@
 
 public class QuickstepLauncher extends Launcher {
 
+    public static final boolean ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
+            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", false);
+
     public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false;
     /**
      * Reusable command for applying the shelf height on the background thread.
@@ -349,16 +353,18 @@
      */
     private void onStateOrResumeChanging(boolean inTransition) {
         LauncherState state = getStateManager().getState();
-        boolean started = ((getActivityFlags() & ACTIVITY_STATE_STARTED)) != 0;
-        if (started) {
-            DeviceProfile profile = getDeviceProfile();
-            boolean willUserBeActive =
-                    (getActivityFlags() & ACTIVITY_STATE_USER_WILL_BE_ACTIVE) != 0;
-            boolean visible = (state == NORMAL || state == OVERVIEW)
-                    && (willUserBeActive || isUserActive())
-                    && !profile.isVerticalBarLayout();
-            UiThreadHelper.runAsyncCommand(this, SET_SHELF_HEIGHT, visible ? 1 : 0,
-                    profile.hotseatBarSizePx);
+        if (!ENABLE_PIP_KEEP_CLEAR_ALGORITHM) {
+            boolean started = ((getActivityFlags() & ACTIVITY_STATE_STARTED)) != 0;
+            if (started) {
+                DeviceProfile profile = getDeviceProfile();
+                boolean willUserBeActive =
+                        (getActivityFlags() & ACTIVITY_STATE_USER_WILL_BE_ACTIVE) != 0;
+                boolean visible = (state == NORMAL || state == OVERVIEW)
+                        && (willUserBeActive || isUserActive())
+                        && !profile.isVerticalBarLayout();
+                UiThreadHelper.runAsyncCommand(this, SET_SHELF_HEIGHT, visible ? 1 : 0,
+                        profile.hotseatBarSizePx);
+            }
         }
         if (state == NORMAL && !inTransition) {
             ((RecentsView) getOverviewPanel()).setSwipeDownShouldLaunchApp(false);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 9f2efc4..e21f14f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -16,14 +16,17 @@
 package com.android.launcher3.uioverrides.states;
 
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
 
 import android.content.Context;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.util.Themes;
 
 /**
@@ -41,9 +44,9 @@
     @Override
     public <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable>
     int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState) {
-        return !context.getDeviceProfile().isTablet && isToState
-                ? 600
-                : isToState ? 500 : 300;
+        return context.getDeviceProfile().isTablet
+                ? 500
+                :  isToState ? 600 : 300;
     }
 
     @Override
@@ -77,10 +80,23 @@
     }
 
     @Override
-    protected float getDepthUnchecked(Context context) {
-        // The scrim fades in at approximately 50% of the swipe gesture.
-        // This means that the depth should be greater than 1, in order to fully zoom out.
-        return 2f;
+    protected <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+            float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) {
+        if (context.getDeviceProfile().isTablet) {
+            // The goal is to set wallpaper to zoom at workspaceContentScale when in AllApps.
+            // When depth is 0, wallpaper zoom is set to maxWallpaperScale.
+            // When depth is 1, wallpaper zoom is set to 1.
+            // For depth to achieve zoom set to maxWallpaperScale * workspaceContentScale:
+            float maxWallpaperScale = context.getResources().getFloat(
+                    com.android.internal.R.dimen.config_wallpaperMaxScale);
+            return Utilities.mapToRange(
+                    maxWallpaperScale * context.getDeviceProfile().workspaceContentScale,
+                    maxWallpaperScale, 1f, 0f, 1f, LINEAR);
+        } else {
+            // The scrim fades in at approximately 50% of the swipe gesture.
+            // This means that the depth should be greater than 1, in order to fully zoom out.
+            return 2f;
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 2eade67..4150d40 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.uioverrides.states;
 
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
+import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 
 import android.content.Context;
 import android.graphics.Color;
@@ -101,6 +102,12 @@
         return Color.TRANSPARENT;
     }
 
+    @Override
+    public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
+        if (ENABLE_SHELL_TRANSITIONS) return false;
+        return super.isTaskbarAlignedWithHotseat(launcher);
+    }
+
     public static float[] getOverviewScaleAndOffsetForBackgroundState(
             BaseDraggingActivity activity) {
         return new float[] {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6e616f3..1f7b7de 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -33,6 +33,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
+import static com.android.launcher3.uioverrides.QuickstepLauncher.ENABLE_PIP_KEEP_CLEAR_ALGORITHM;
 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.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -1461,12 +1462,13 @@
         homeToWindowPositionMap.invert(windowToHomePositionMap);
         windowToHomePositionMap.mapRect(startRect);
 
+        final Rect hotseatKeepClearArea = getKeepClearAreaForHotseat();
         final Rect destinationBounds = SystemUiProxy.INSTANCE.get(mContext)
                 .startSwipePipToHome(taskInfo.topActivity,
                         taskInfo.topActivityInfo,
                         runningTaskTarget.taskInfo.pictureInPictureParams,
                         homeRotation,
-                        mDp.hotseatBarSizePx);
+                        hotseatKeepClearArea);
         final Rect appBounds = new Rect();
         final WindowConfiguration winConfig = taskInfo.configuration.windowConfiguration;
         // Adjust the appBounds for TaskBar by using the calculated window crop Rect
@@ -1529,6 +1531,35 @@
         return swipePipToHomeAnimator;
     }
 
+    private Rect getKeepClearAreaForHotseat() {
+        Rect keepClearArea;
+        if (!ENABLE_PIP_KEEP_CLEAR_ALGORITHM) {
+            // make the height equal to hotseatBarSizePx only
+            keepClearArea = new Rect(0, 0, mDp.hotseatBarSizePx, 0);
+            return keepClearArea;
+        }
+        // the keep clear area in global screen coordinates, in pixels
+        if (mDp.isPhone) {
+            if (mDp.isSeascape()) {
+                // in seascape the Hotseat is on the left edge of the screen
+                keepClearArea = new Rect(0, 0, mDp.hotseatBarSizePx, mDp.heightPx);
+            } else if (mDp.isLandscape) {
+                // in landscape the Hotseat is on the right edge of the screen
+                keepClearArea = new Rect(mDp.widthPx - mDp.hotseatBarSizePx, 0,
+                        mDp.widthPx, mDp.heightPx);
+            } else {
+                // in portrait mode the Hotseat is at the bottom of the screen
+                keepClearArea = new Rect(0, mDp.heightPx - mDp.hotseatBarSizePx,
+                        mDp.widthPx, mDp.heightPx);
+            }
+        } else {
+            // large screens have Hotseat always at the bottom of the screen
+            keepClearArea = new Rect(0, mDp.heightPx - mDp.hotseatBarSizePx,
+                    mDp.widthPx, mDp.heightPx);
+        }
+        return keepClearArea;
+    }
+
     private void startInterceptingTouchesForGesture() {
         if (mRecentsAnimationController == null) {
             return;
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 0ec7e62..8e9ff2f 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -28,7 +28,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -509,11 +509,12 @@
     }
 
     public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
-            PictureInPictureParams pictureInPictureParams, int launcherRotation, int shelfHeight) {
+            PictureInPictureParams pictureInPictureParams, int launcherRotation,
+            Rect hotseatKeepClearArea) {
         if (mPip != null) {
             try {
                 return mPip.startSwipePipToHome(componentName, activityInfo,
-                        pictureInPictureParams, launcherRotation, shelfHeight);
+                        pictureInPictureParams, launcherRotation, hotseatKeepClearArea);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call startSwipePipToHome", e);
             }
@@ -602,7 +603,21 @@
                 mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent,
                         taskId, mainOptions, sideOptions, sidePosition, splitRatio, adapter);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed call startTasksWithLegacyTransition");
+                Log.w(TAG, "Failed call startIntentAndTaskWithLegacyTransition");
+            }
+        }
+    }
+
+    public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, int taskId,
+            Bundle mainOptions, Bundle sideOptions,
+            @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio,
+            RemoteAnimationAdapter adapter) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, taskId,
+                        mainOptions, sideOptions, sidePosition, splitRatio, adapter);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startShortcutAndTaskWithLegacyTransition");
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index a809c9c..93170cb 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -195,7 +195,8 @@
 
         int taskIndex = recentsView.indexOfChild(v);
         Context context = v.getContext();
-        DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
+        BaseActivity baseActivity = BaseActivity.fromContext(context);
+        DeviceProfile dp = baseActivity.getDeviceProfile();
         boolean showAsGrid = dp.isTablet;
         boolean parallaxCenterAndAdjacentTask =
                 taskIndex != recentsView.getCurrentPage() && !showAsGrid;
@@ -368,7 +369,7 @@
         });
 
         if (depthController != null) {
-            out.setFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(context),
+            out.setFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(baseActivity),
                     TOUCH_RESPONSE_INTERPOLATOR);
         }
     }
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 8f32214..7efb1a5 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -31,16 +31,20 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.RemoteAnimationAdapter;
 import android.view.SurfaceControl;
 import android.window.TransitionInfo;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.testing.TestLogging;
@@ -66,6 +70,7 @@
  * and is in the process of either a) selecting a second app or b) exiting intention to invoke split
  */
 public class SplitSelectStateController {
+    private static final String TAG = "SplitSelectStateCtor";
 
     private final Context mContext;
     private final Handler mHandler;
@@ -196,7 +201,7 @@
                     null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio,
                     new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR,
                             ActivityThread.currentActivityThread().getApplicationThread()));
-            // TODO: handle intent + task with shell transition
+            // TODO(b/237635859): handle intent/shortcut + task with shell transition
         } else {
             RemoteSplitLaunchAnimationRunner animationRunner =
                     new RemoteSplitLaunchAnimationRunner(taskId1, taskPendingIntent, taskId2,
@@ -215,9 +220,17 @@
                         taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
                         splitRatio, adapter);
             } else {
-                mSystemUiProxy.startIntentAndTaskWithLegacyTransition(taskPendingIntent,
-                        fillInIntent, taskId2, mainOpts.toBundle(), null /* sideOptions */,
-                        stagePosition, splitRatio, adapter);
+                final ShortcutInfo shortcutInfo = getShortcutInfo(mInitialTaskIntent,
+                        taskPendingIntent.getCreatorUserHandle());
+                if (shortcutInfo != null) {
+                    mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(shortcutInfo, taskId2,
+                            mainOpts.toBundle(), null /* sideOptions */, stagePosition, splitRatio,
+                            adapter);
+                } else {
+                    mSystemUiProxy.startIntentAndTaskWithLegacyTransition(taskPendingIntent,
+                            fillInIntent, taskId2, mainOpts.toBundle(), null /* sideOptions */,
+                            stagePosition, splitRatio, adapter);
+                }
             }
         }
     }
@@ -230,6 +243,28 @@
         this.mRecentsAnimationRunning = running;
     }
 
+    @Nullable
+    private ShortcutInfo getShortcutInfo(Intent intent, UserHandle userHandle) {
+        if (intent == null || intent.getPackage() == null) {
+            return null;
+        }
+
+        final String shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID);
+        if (shortcutId == null) {
+            return null;
+        }
+
+        try {
+            final Context context = mContext.createPackageContextAsUser(
+                    intent.getPackage(), 0 /* flags */, userHandle);
+            return new ShortcutInfo.Builder(context, shortcutId).build();
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Failed to create a ShortcutInfo for " + intent.getPackage());
+        }
+
+        return null;
+    }
+
     /**
      * Requires Shell Transitions
      */
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index f718be8..a870f9c 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -1,6 +1,5 @@
 package com.android.quickstep.views;
 
-import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -318,7 +317,6 @@
     @Override
     protected void applyThumbnailSplashAlpha() {
         super.applyThumbnailSplashAlpha();
-        mSnapshotView2.setSplashAlpha(
-                Utilities.mapToRange(mTaskThumbnailSplashAlpha, 0f, 1f, 1f, 0f, LINEAR));
+        mSnapshotView2.setSplashAlpha(mTaskThumbnailSplashAlpha);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 1e78377..34c2021 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -1064,7 +1064,7 @@
     }
 
     protected void applyThumbnailSplashAlpha() {
-        mSnapshotView.setSplashAlpha(Utilities.boundToRange(mTaskThumbnailSplashAlpha, 0f, 1f));
+        mSnapshotView.setSplashAlpha(mTaskThumbnailSplashAlpha);
     }
 
     private void setSplitSelectTranslationX(float x) {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index 1df9c02..9337cb5 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -68,6 +68,13 @@
     }
 
     @Test
+    public void testHideTaskbarPersistsOnRecreate() {
+        getTaskbar().hide();
+        mLauncher.recreateTaskbar();
+        mLauncher.getLaunchedAppState().assertTaskbarHidden();
+    }
+
+    @Test
     public void testLaunchApp() throws Exception {
         getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
     }
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
index 82b0b8d..95ebd94 100644
--- a/res/layout/hotseat.xml
+++ b/res/layout/hotseat.xml
@@ -21,4 +21,5 @@
     android:layout_height="match_parent"
     android:theme="@style/HomeScreenElementTheme"
     android:importantForAccessibility="no"
+    android:preferKeepClear="true"
     launcher:containerType="hotseat" />
\ No newline at end of file
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 448a56b..8669949 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -106,13 +106,13 @@
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Funkcja wyłączona przez administratora"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"Zezwalaj na obrót ekranu głównego"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Po obróceniu telefonu"</string>
-    <string name="notification_dots_title" msgid="9062440428204120317">"Plakietki z powiadomieniami"</string>
+    <string name="notification_dots_title" msgid="9062440428204120317">"Kropki powiadomień"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"Włączono"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Wyłączono"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Wymagany jest dostęp do powiadomień"</string>
-    <string name="msg_missing_notification_access" msgid="281113995110910548">"Aby pokazać plakietki z powiadomieniami, włącz powiadomienia aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Aby pokazywać kropki powiadomień, włącz powiadomienia aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Zmień ustawienia"</string>
-    <string name="notification_dots_service_title" msgid="4284221181793592871">"Pokaż plakietki z powiadomieniami"</string>
+    <string name="notification_dots_service_title" msgid="4284221181793592871">"Pokaż kropki powiadomień"</string>
     <string name="developer_options_title" msgid="700788437593726194">"Opcje programisty"</string>
     <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Dodawaj ikony aplikacji do ekranu głównego"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"W przypadku nowych aplikacji"</string>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 14a467a..a330fb3 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -513,7 +513,7 @@
     private int getIconToIconWidthForColumns(int columns) {
         return columns * getCellSize().x
                 + (columns - 1) * cellLayoutBorderSpacePx.x
-                - (getCellSize().x - iconSizePx);  // left and right cell space
+                - getCellHorizontalSpace();
     }
 
     private int getHorizontalMarginPx(InvariantDeviceProfile idp, Resources res) {
@@ -985,6 +985,13 @@
     }
 
     /**
+     * Returns the left and right space on the cell, which is the cell width - icon size
+     */
+    public int getCellHorizontalSpace() {
+        return getCellSize().x - iconSizePx;
+    }
+
+    /**
      * Gets the number of panels within the workspace.
      */
     public int getPanelCount() {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 4532ed4..c3b5392 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -265,7 +265,8 @@
      *
      * 0 means completely zoomed in, without blurs. 1 is zoomed out, with blurs.
      */
-    public final float getDepth(Context context) {
+    public final  <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+            float getDepth(DEVICE_PROFILE_CONTEXT context) {
         return getDepth(context,
                 BaseDraggingActivity.fromContext(context).getDeviceProfile().isMultiWindowMode);
     }
@@ -275,14 +276,16 @@
      *
      * @see #getDepth(Context).
      */
-    public final float getDepth(Context context, boolean isMultiWindowMode) {
+    public final <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+            float getDepth(DEVICE_PROFILE_CONTEXT context, boolean isMultiWindowMode) {
         if (isMultiWindowMode) {
             return 0;
         }
         return getDepthUnchecked(context);
     }
 
-    protected float getDepthUnchecked(Context context) {
+    protected <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+            float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) {
         return 0f;
     }
 
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 0a77aa7..12b4223 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -57,6 +57,10 @@
     public static final Interpolator DECELERATED_EASE = new PathInterpolator(0, 0, .2f, 1f);
     public static final Interpolator ACCELERATED_EASE = new PathInterpolator(0.4f, 0, 1f, 1f);
 
+    /**
+     * The default emphasized interpolator. Used for hero / emphasized movement of content.
+     */
+    public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
     public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
             0.3f, 0f, 0.8f, 0.15f);
     public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
@@ -87,7 +91,6 @@
     public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL =
             v -> ACCEL_DEACCEL.getInterpolation(TOUCH_RESPONSE_INTERPOLATOR.getInterpolation(v));
 
-
     /**
      * Inversion of ZOOM_OUT, compounded with an ease-out.
      */
@@ -218,4 +221,14 @@
     public static Interpolator reverse(Interpolator interpolator) {
         return t -> 1 - interpolator.getInterpolation(1 - t);
     }
+
+    // Create the default emphasized interpolator
+    private static PathInterpolator createEmphasizedInterpolator() {
+        Path path = new Path();
+        // Doing the same as fast_out_extra_slow_in
+        path.moveTo(0f, 0f);
+        path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
+        path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
+        return new PathInterpolator(path);
+    }
 }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 82a47b0..ff40712 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -274,6 +274,10 @@
             "USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", false,
             "Use local overrides for search request timeout");
 
+    public static final BooleanFlag USE_APP_SEARCH_FOR_WEB = getDebugFlag(
+            "USE_APP_SEARCH_FOR_WEB", false,
+            "Use app search to request zero state web suggestions");
+
     public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(
             "CONTINUOUS_VIEW_TREE_CAPTURE", false, "Capture View tree every frame");
 
diff --git a/src/com/android/launcher3/testing/shared/TestProtocol.java b/src/com/android/launcher3/testing/shared/TestProtocol.java
index 67efb58..5116b01 100644
--- a/src/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/src/com/android/launcher3/testing/shared/TestProtocol.java
@@ -86,6 +86,7 @@
     public static final String REQUEST_DISABLE_MANUAL_TASKBAR_STASHING = "disable-taskbar-stashing";
     public static final String REQUEST_UNSTASH_TASKBAR_IF_STASHED = "unstash-taskbar-if-stashed";
     public static final String REQUEST_STASHED_TASKBAR_HEIGHT = "stashed-taskbar-height";
+    public static final String REQUEST_RECREATE_TASKBAR = "recreate-taskbar";
     public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
     public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y";
     public static final String REQUEST_WIDGETS_SCROLL_Y = "widgets-scroll-y";
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 37b76fb..5279dec 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
 import static com.android.launcher3.anim.Interpolators.EMPHASIZED_ACCELERATE;
 import static com.android.launcher3.anim.Interpolators.EMPHASIZED_DECELERATE;
 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
@@ -199,8 +200,10 @@
                     Interpolators.reverse(ALL_APPS_SCRIM_RESPONDER));
             config.setInterpolator(ANIM_ALL_APPS_FADE, FINAL_FRAME);
             if (!config.userControlled) {
-                config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED_ACCELERATE);
+                config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED);
             }
+            config.setInterpolator(ANIM_WORKSPACE_SCALE, EMPHASIZED);
+            config.setInterpolator(ANIM_DEPTH, EMPHASIZED);
         } else {
             if (config.userControlled) {
                 config.setInterpolator(ANIM_DEPTH, Interpolators.reverse(BLUR_MANUAL));
@@ -238,8 +241,10 @@
             config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
             config.setInterpolator(ANIM_SCRIM_FADE, ALL_APPS_SCRIM_RESPONDER);
             if (!config.userControlled) {
-                config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED_DECELERATE);
+                config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED);
             }
+            config.setInterpolator(ANIM_WORKSPACE_SCALE, EMPHASIZED);
+            config.setInterpolator(ANIM_DEPTH, EMPHASIZED);
         } else {
             config.setInterpolator(ANIM_DEPTH, config.userControlled ? BLUR_MANUAL : BLUR_ATOMIC);
             config.setInterpolator(ANIM_WORKSPACE_FADE,
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index bf35dd8..9daea94 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -32,7 +32,6 @@
 public class AllAppsState extends LauncherState {
 
     private static final float PARALLAX_COEFFICIENT = .125f;
-    private static final float WORKSPACE_SCALE_FACTOR = 0.97f;
 
     private static final int STATE_FLAGS = FLAG_WORKSPACE_INACCESSIBLE;
 
@@ -60,7 +59,8 @@
 
     @Override
     public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
-        return new ScaleAndTranslation(WORKSPACE_SCALE_FACTOR, NO_OFFSET, NO_OFFSET);
+        return new ScaleAndTranslation(launcher.getDeviceProfile().workspaceContentScale, NO_OFFSET,
+                NO_OFFSET);
     }
 
     @Override
@@ -71,7 +71,7 @@
             ScaleAndTranslation overviewScaleAndTranslation = LauncherState.OVERVIEW
                     .getWorkspaceScaleAndTranslation(launcher);
             return new ScaleAndTranslation(
-                    WORKSPACE_SCALE_FACTOR,
+                    launcher.getDeviceProfile().workspaceContentScale,
                     overviewScaleAndTranslation.translationX,
                     overviewScaleAndTranslation.translationY);
         }
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 04167839..a17651b 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT;
@@ -54,13 +55,23 @@
     public Taskbar getTaskbar() {
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to get the taskbar")) {
-            mLauncher.waitForLauncherObject("taskbar_view");
+            mLauncher.waitForLauncherObject(TASKBAR_RES_ID);
 
             return new Taskbar(mLauncher);
         }
     }
 
     /**
+     * Waits for the taskbar to be hidden, or fails.
+     */
+    public void assertTaskbarHidden() {
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "waiting for taskbar to be hidden")) {
+            mLauncher.waitUntilLauncherObjectGone(TASKBAR_RES_ID);
+        }
+    }
+
+    /**
      * Returns the Taskbar in a visible state.
      *
      * The taskbar must already be hidden when calling this method.
@@ -71,7 +82,7 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                      "want to show the taskbar")) {
-            mLauncher.waitUntilLauncherObjectGone("taskbar_view");
+            mLauncher.waitUntilLauncherObjectGone(TASKBAR_RES_ID);
 
             final long downTime = SystemClock.uptimeMillis();
             final int unstashTargetY = mLauncher.getRealDisplaySize().y
@@ -85,7 +96,7 @@
             LauncherInstrumentation.log("showTaskbar: sent down");
 
             try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
-                mLauncher.waitForLauncherObject("taskbar_view");
+                mLauncher.waitForLauncherObject(TASKBAR_RES_ID);
                 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget,
                         LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER);
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index fa7e8e9..1fb8cc7 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -168,7 +168,7 @@
     private static final String OVERVIEW_RES_ID = "overview_panel";
     private static final String WIDGETS_RES_ID = "primary_widgets_list_view";
     private static final String CONTEXT_MENU_RES_ID = "popup_container";
-    private static final String TASKBAR_RES_ID = "taskbar_view";
+    static final String TASKBAR_RES_ID = "taskbar_view";
     private static final String SPLIT_PLACEHOLDER_RES_ID = "split_placeholder";
     public static final int WAIT_TIME_MS = 30000;
     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
@@ -1755,6 +1755,15 @@
         getTestInfo(TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED);
     }
 
+    /**
+     * Recreates the taskbar (outside of tests this is done for certain configuration changes).
+     * The expected behavior is that the taskbar retains its current state after being recreated.
+     * For example, if taskbar is currently stashed, it should still be stashed after recreating.
+     */
+    public void recreateTaskbar() {
+        getTestInfo(TestProtocol.REQUEST_RECREATE_TASKBAR);
+    }
+
     public List<String> getHotseatIconNames() {
         return getTestInfo(TestProtocol.REQUEST_HOTSEAT_ICON_NAMES)
                 .getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD);
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index 5d9be36..0f9d5f5 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
 
@@ -51,7 +52,7 @@
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to get a taskbar icon")) {
             return new TaskbarAppIcon(mLauncher, mLauncher.waitForObjectInContainer(
-                    mLauncher.waitForLauncherObject("taskbar_view"),
+                    mLauncher.waitForLauncherObject(TASKBAR_RES_ID),
                     AppIcon.getAppIconSelector(appName, mLauncher)));
         }
     }
@@ -67,7 +68,7 @@
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to hide the taskbar");
              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
-            mLauncher.waitForLauncherObject("taskbar_view");
+            mLauncher.waitForLauncherObject(TASKBAR_RES_ID);
 
             final long downTime = SystemClock.uptimeMillis();
             Point stashTarget = new Point(
@@ -96,7 +97,7 @@
              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
 
             mLauncher.clickLauncherObject(mLauncher.waitForObjectInContainer(
-                    mLauncher.waitForLauncherObject("taskbar_view"), getAllAppsButtonSelector()));
+                    mLauncher.waitForLauncherObject(TASKBAR_RES_ID), getAllAppsButtonSelector()));
 
             return new AllAppsFromTaskbar(mLauncher);
         }
@@ -107,7 +108,7 @@
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to get all taskbar icons")) {
             return mLauncher.waitForObjectsInContainer(
-                    mLauncher.waitForLauncherObject("taskbar_view"),
+                    mLauncher.waitForLauncherObject(TASKBAR_RES_ID),
                     AppIcon.getAnyAppIconSelector())
                     .stream()
                     .map(UiObject2::getText)