Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 5101851..ee7e975 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -311,6 +311,13 @@
 }
 
 flag {
+    name: "all_apps_sheet_for_handheld"
+    namespace: "launcher"
+    description: "All Apps will be presented on a bottom sheet in handheld mode"
+    bug: "374186088"
+}
+
+flag {
     name: "multiline_search_bar"
     namespace: "launcher"
     description: "Search bar can wrap to multi-line"
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index a87ed44..6c5748d 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -69,7 +69,7 @@
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Əsas səhifəyə keçmək üçün sürüşdürün"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Ekranın aşağısından yuxarısına sürüşdürün. Bu jest həmişə Əsas səhifəyə aparır."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 barmaqla ekranın aşağısından yuxarısına sürüşdürün. Bu jest həmişə Əsas səhifəyə aparır."</string>
-    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Əsas səhifəyə qayıdın"</string>
+    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Əsas səhifəyə keçin"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Ekranın aşağısından yuxarı sürüşdürün"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Əla!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Ekranın aşağı kənarından yuxarı sürüşdürün"</string>
diff --git a/quickstep/res/values-night/colors.xml b/quickstep/res/values-night/colors.xml
index 98e4871..a1e9c70 100644
--- a/quickstep/res/values-night/colors.xml
+++ b/quickstep/res/values-night/colors.xml
@@ -26,6 +26,4 @@
 
     <!-- Turn on work apps button -->
     <color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
-    <color name="work_fab_bg_color">?attr/materialColorPrimaryFixedDim</color>
-    <color name="work_fab_icon_color">?attr/materialColorOnPrimaryFixed</color>
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index eee46bb..dc16036 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -140,7 +140,7 @@
     <string name="always_show_taskbar" msgid="3608801276107751229">"始终显示任务栏"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"更改导航模式"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"任务栏分隔线"</string>
-    <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"溢出式任务栏"</string>
+    <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"任务栏溢出图标"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string>
     <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{多个应用}other{多个应用}}"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 62873d6..668bce7 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -94,6 +94,4 @@
 
     <!-- Turn on work apps button -->
     <color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
-    <color name="work_fab_bg_color">?attr/materialColorPrimaryFixedDim</color>
-    <color name="work_fab_icon_color">?attr/materialColorOnPrimaryFixed</color>
 </resources>
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index 711a49a..23a5a27 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -54,6 +54,8 @@
     public static final int MAX_TASKS = 6;
 
     @NonNull private final ControllerCallbacks mControllerCallbacks = new ControllerCallbacks();
+    // Callback used to notify when the KQS view is closed.
+    @Nullable private Runnable mOnClosed;
 
     // Initialized on init
     @Nullable private RecentsModel mModel;
@@ -112,8 +114,12 @@
      * Opens or closes the view in response to taskbar action. The view shows a filtered list of
      * tasks.
      * @param taskIdsToExclude A list of tasks to exclude in the opened view.
+     * @param onClosed A callback used to notify when the KQS view is closed.
      */
-    void toggleQuickSwitchViewForTaskbar(@NonNull Set<Integer> taskIdsToExclude) {
+    void toggleQuickSwitchViewForTaskbar(@NonNull Set<Integer> taskIdsToExclude,
+            @NonNull Runnable onClosed) {
+        mOnClosed = onClosed;
+
         // Close the view if its shown, and was opened from the taskbar.
         if (mQuickSwitchViewController != null
                 && !mQuickSwitchViewController.isCloseAnimationRunning()
@@ -264,6 +270,10 @@
             return;
         }
         mQuickSwitchViewController.closeQuickSwitchView(animate);
+        if (mOnClosed != null) {
+            mOnClosed.run();
+            mOnClosed = null;
+        }
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index ab4b1b6..0807ee9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -175,6 +175,9 @@
                                 + "onActivityDestroyed.");
                 mActivity.removeEventCallback(EVENT_DESTROYED, this);
             }
+            if (mActivity == mRecentsViewContainer) {
+                mRecentsViewContainer = null;
+            }
             mActivity = null;
             debugWhyTaskbarNotDestroyed("clearActivity");
             if (mTaskbarActivityContext != null) {
@@ -560,25 +563,25 @@
         }
     }
 
-    public void checkNavBarModes() {
+    public void checkNavBarModes(int displayId) {
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.checkNavBarModes();
         }
     }
 
-    public void finishBarAnimations() {
+    public void finishBarAnimations(int displayId) {
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.finishBarAnimations();
         }
     }
 
-    public void touchAutoDim(boolean reset) {
+    public void touchAutoDim(int displayId, boolean reset) {
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.touchAutoDim(reset);
         }
     }
 
-    public void transitionTo(@BarTransitions.TransitionMode int barMode,
+    public void transitionTo(int displayId, @BarTransitions.TransitionMode int barMode,
             boolean animate) {
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.transitionTo(barMode, animate);
@@ -659,6 +662,7 @@
      * Called when the manager is no longer needed
      */
     public void destroy() {
+        mRecentsViewContainer = null;
         debugWhyTaskbarNotDestroyed("TaskbarManager#destroy()");
         removeActivityCallbacksAndListeners();
         mTaskbarBroadcastReceiver.unregisterReceiverSafely(mContext);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
index fad5ca3..126e9bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
@@ -25,10 +25,13 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.R;
 import com.android.launcher3.Reorderable;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.MultiTranslateDelegate;
+import com.android.launcher3.util.Themes;
 import com.android.systemui.shared.recents.model.Task;
 
 import java.util.ArrayList;
@@ -42,12 +45,22 @@
  * each other in counter clockwise manner (icons of tasks partially overlapping with each other).
  */
 public class TaskbarOverflowView extends FrameLayout implements Reorderable {
+    private static final int MAX_ITEMS_IN_PREVIEW = 4;
+
+    private boolean mIsRtlLayout;
     private final List<Task> mItems = new ArrayList<Task>();
     private int mIconSize;
     private int mPadding;
     private Paint mItemBackgroundPaint;
     private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
     private float mScaleForReorderBounce = 1f;
+    private int mItemBackgroundColor;
+    private int mLeaveBehindColor;
+    private float mItemPreviewStrokeWidth;
+
+    // Active means the overflow icon has been pressed, which replaces the app icons with the
+    // leave-behind circle and shows the KQS UI.
+    private boolean mIsActive = false;
 
     public TaskbarOverflowView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -78,22 +91,32 @@
     }
 
     private void init() {
+        mIsRtlLayout = Utilities.isRtl(getResources());
         mItemBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mItemBackgroundPaint.setColor(getContext().getColor(R.color.taskbar_background));
+        mItemBackgroundColor = getContext().getColor(R.color.taskbar_background);
+        mLeaveBehindColor = Themes.getAttrColor(getContext(), android.R.attr.textColorTertiary);
+        mItemPreviewStrokeWidth = getResources().getDimension(
+                R.dimen.taskbar_overflow_button_preview_stroke);
 
         setWillNotDraw(false);
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    protected void onDraw(@NonNull Canvas canvas) {
         super.onDraw(canvas);
 
-        boolean isRtlLayout = Utilities.isRtl(getResources());
-        float radius = mIconSize / 2.0f - mPadding;
-        float itemPreviewStrokeWidth =
-                getResources().getDimension(R.dimen.taskbar_overflow_button_preview_stroke);
+        if (mIsActive) {
+            drawLeaveBehindCircle(canvas);
+        } else {
+            drawAppIcons(canvas);
+        }
+    }
 
-        int itemsToShow = Math.min(mItems.size(), 4);
+    private void drawAppIcons(@NonNull Canvas canvas) {
+        mItemBackgroundPaint.setColor(mItemBackgroundColor);
+        float radius = mIconSize / 2f - mPadding;
+
+        int itemsToShow = Math.min(mItems.size(), MAX_ITEMS_IN_PREVIEW);
         for (int i = itemsToShow - 1; i >= 0; --i) {
             Drawable icon = mItems.get(mItems.size() - i - 1).icon;
             if (icon == null) {
@@ -103,11 +126,11 @@
             // Set the item icon size so two items fit within the overflow icon with stroke width
             // included, and overlap of 4 stroke width sizes between base item preview items.
             // 2 * strokeWidth + 2 * itemIconSize - 4 * strokeWidth = iconSize = 2 * radius.
-            float itemIconSize = radius + itemPreviewStrokeWidth;
-            // Offset item icon from center so item icon stroke edge mateches the parent icon edge.
-            float itemCenterOffset = radius - itemIconSize / 2 - itemPreviewStrokeWidth;
+            float itemIconSize = radius + mItemPreviewStrokeWidth;
+            // Offset item icon from center so item icon stroke edge matches the parent icon edge.
+            float itemCenterOffset = radius - itemIconSize / 2 - mItemPreviewStrokeWidth;
 
-            float itemCenterX = getItemXOffset(itemCenterOffset, isRtlLayout, i, itemsToShow);
+            float itemCenterX = getItemXOffset(itemCenterOffset, mIsRtlLayout, i, itemsToShow);
             float itemCenterY = getItemYOffset(itemCenterOffset, i, itemsToShow);
 
             Drawable iconCopy = icon.getConstantState().newDrawable().mutate();
@@ -119,12 +142,19 @@
                     mPadding + itemCenterX + radius - itemIconRadius,
                     mPadding + itemCenterY + radius - itemIconRadius);
             canvas.drawCircle(itemIconRadius, itemIconRadius,
-                    itemIconRadius + itemPreviewStrokeWidth, mItemBackgroundPaint);
+                    itemIconRadius + mItemPreviewStrokeWidth, mItemBackgroundPaint);
             iconCopy.draw(canvas);
             canvas.restore();
         }
     }
 
+    private void drawLeaveBehindCircle(@NonNull Canvas canvas) {
+        mItemBackgroundPaint.setColor(mLeaveBehindColor);
+
+        final var xyCenter = mIconSize / 2f;
+        canvas.drawCircle(xyCenter, xyCenter, mIconSize / 4f, mItemBackgroundPaint);
+    }
+
     /**
      * Clears the list of tasks tracked by the view.
      */
@@ -153,7 +183,7 @@
         for (int i = 0; i < mItems.size(); ++i) {
             if (mItems.get(i).key.id == task.key.id) {
                 mItems.set(i, task);
-                if (i >= mItems.size() - 4) {
+                if (i >= mItems.size() - MAX_ITEMS_IN_PREVIEW) {
                     invalidate();
                 }
                 break;
@@ -161,6 +191,24 @@
         }
     }
 
+    /**
+     * Returns the view's state (whether it shows a set of app icons or a leave-behind circle).
+     */
+    public boolean getIsActive() {
+        return mIsActive;
+    }
+
+    /**
+     * Updates the view's state to draw either a set of app icons or a leave-behind circle.
+     * @param isActive The next state of the view.
+     */
+    public void setIsActive(boolean isActive) {
+        if (mIsActive != isActive) {
+            mIsActive = isActive;
+            invalidate();
+        }
+    }
+
     @Override
     public MultiTranslateDelegate getTranslateDelegate() {
         return mTranslateDelegate;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index 5d769d2..834f92e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -148,8 +148,7 @@
         return new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                mControllers.keyboardQuickSwitchController.toggleQuickSwitchViewForTaskbar(
-                        mControllers.taskbarViewController.getTaskIdsForPinnedApps());
+                toggleKeyboardQuickSwitchView();
             }
         };
     }
@@ -159,13 +158,28 @@
         return new View.OnLongClickListener() {
             @Override
             public boolean onLongClick(View v) {
-                mControllers.keyboardQuickSwitchController.toggleQuickSwitchViewForTaskbar(
-                        mControllers.taskbarViewController.getTaskIdsForPinnedApps());
+                toggleKeyboardQuickSwitchView();
                 return true;
             }
         };
     }
 
+    private void toggleKeyboardQuickSwitchView() {
+        if (mTaskbarView.getTaskbarOverflowView() != null) {
+            mTaskbarView.getTaskbarOverflowView().setIsActive(
+                    !mTaskbarView.getTaskbarOverflowView().getIsActive());
+        }
+        mControllers.keyboardQuickSwitchController.toggleQuickSwitchViewForTaskbar(
+                mControllers.taskbarViewController.getTaskIdsForPinnedApps(),
+                this::onKeyboardQuickSwitchViewClosed);
+    }
+
+    private void onKeyboardQuickSwitchViewClosed() {
+        if (mTaskbarView.getTaskbarOverflowView() != null) {
+            mTaskbarView.getTaskbarOverflowView().setIsActive(false);
+        }
+    }
+
     private float getDividerCenterX() {
         View divider = mTaskbarView.getTaskbarDividerViewContainer();
         if (divider == null) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 030a7ac..d387794 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -118,7 +118,7 @@
 
     @Override
     public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
-        if (launcher.getDeviceProfile().isTablet) {
+        if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
             return getWorkspaceScaleAndTranslation(launcher);
         } else {
             ScaleAndTranslation overviewScaleAndTranslation = LauncherState.OVERVIEW
@@ -133,7 +133,7 @@
     @Override
     protected <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
             float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) {
-        if (context.getDeviceProfile().isTablet) {
+        if (context.getDeviceProfile().shouldShowAllAppsOnSheet()) {
             return context.getDeviceProfile().bottomSheetDepth;
         } else {
             // The scrim fades in at approximately 50% of the swipe gesture.
@@ -154,7 +154,7 @@
         return new PageAlphaProvider(DECELERATE_2) {
             @Override
             public float getPageAlpha(int pageIndex) {
-                return launcher.getDeviceProfile().isTablet
+                return launcher.getDeviceProfile().shouldShowAllAppsOnSheet()
                         ? superPageAlphaProvider.getPageAlpha(pageIndex)
                         : 0;
             }
@@ -164,8 +164,8 @@
     @Override
     public int getVisibleElements(Launcher launcher) {
         int elements = ALL_APPS_CONTENT | FLOATING_SEARCH_BAR;
-        // Only add HOTSEAT_ICONS for tablets in ALL_APPS state.
-        if (launcher.getDeviceProfile().isTablet) {
+        // When All Apps is presented on a bottom sheet, HOTSEAT_ICONS are visible.
+        if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
             elements |= HOTSEAT_ICONS;
         }
         return elements;
@@ -202,7 +202,7 @@
 
     @Override
     public int getWorkspaceScrimColor(Launcher launcher) {
-        return launcher.getDeviceProfile().isTablet
+        return launcher.getDeviceProfile().shouldShowAllAppsOnSheet()
                 ? launcher.getResources().getColor(R.color.widgets_picker_scrim)
                 : Themes.getAttrColor(launcher, R.attr.allAppsScrimColor);
     }
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 0b6794c..0ea128a 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -201,8 +201,7 @@
                         // Only finish if the end target is RECENTS. Otherwise, if the target is
                         // NEW_TASK, startActivityFromRecents will be skipped.
                         if (mLastGestureState.getEndTarget() == RECENTS) {
-                            finishRunningRecentsAnimation(false /* toHome */,
-                                    true /* forceFinish */, null /* forceFinishCb */);
+                            finishRunningRecentsAnimation(false /* toHome */);
                         }
                     });
                 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index e8f38be..5b085d2 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -342,36 +342,36 @@
 
         @BinderThread
         @Override
-        public void checkNavBarModes() {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
-                    executeForTaskbarManager(TaskbarManager::checkNavBarModes)
-            ));
-        }
-
-        @BinderThread
-        @Override
-        public void finishBarAnimations() {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
-                    executeForTaskbarManager(TaskbarManager::finishBarAnimations)
-            ));
-        }
-
-        @BinderThread
-        @Override
-        public void touchAutoDim(boolean reset) {
-            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
-                    executeForTaskbarManager(taskbarManager -> taskbarManager.touchAutoDim(reset))
-            ));
-        }
-
-        @BinderThread
-        @Override
-        public void transitionTo(@BarTransitions.TransitionMode int barMode,
-                boolean animate) {
+        public void checkNavBarModes(int displayId) {
             MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
                     executeForTaskbarManager(
-                            taskbarManager -> taskbarManager.transitionTo(barMode, animate))
-            ));
+                            taskbarManager -> taskbarManager.checkNavBarModes(displayId))));
+        }
+
+        @BinderThread
+        @Override
+        public void finishBarAnimations(int displayId) {
+            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(
+                    tis -> executeForTaskbarManager(
+                            taskbarManager -> taskbarManager.finishBarAnimations(displayId))));
+        }
+
+        @BinderThread
+        @Override
+        public void touchAutoDim(int displayId, boolean reset) {
+            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(
+                    tis -> executeForTaskbarManager(
+                            taskbarManager -> taskbarManager.touchAutoDim(displayId, reset))));
+        }
+
+        @BinderThread
+        @Override
+        public void transitionTo(int displayId, @BarTransitions.TransitionMode int barMode,
+                boolean animate) {
+            MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(
+                    tis -> executeForTaskbarManager(
+                            taskbarManager -> taskbarManager.transitionTo(displayId, barMode,
+                                    animate))));
         }
 
         @BinderThread
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
index 78224ae..843ef6c 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
@@ -218,6 +218,11 @@
             )
         }
 
+    private val onBackInvokedCallback: () -> Unit = {
+        // If we are in live tile mode, launch the live task, otherwise return home
+        recentsView?.runningTaskView?.launchWithAnimation() ?: startHome()
+    }
+
     private fun cleanupRecentsWindow() {
         RecentsWindowProtoLogProxy.logCleanup(isShowing())
         if (isShowing()) {
@@ -241,6 +246,10 @@
         }
         windowManager.addView(windowView, windowLayoutParams)
 
+        windowView
+            ?.findOnBackInvokedDispatcher()
+            ?.registerSystemOnBackInvokedCallback(onBackInvokedCallback)
+
         windowView?.systemUiVisibility =
             (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
index 2a8afbf..120a89b 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
@@ -104,28 +104,36 @@
 
     @Test
     @PortraitLandscape
-    fun dismissFocusedTask_thenDesktopTask_thenFocusedTaskIsCentered() {
+    fun dismissTasks_whenDesktopTask_IsInTheCenter() {
         // Create extra activity to be DesktopTaskView
         startTestActivity(TEST_ACTIVITY_EXTRA)
         mLauncher.goHome().switchToOverview()
+
         val desktop = moveTaskToDesktop(TEST_ACTIVITY_EXTRA)
+        var overview = desktop.switchToOverview()
 
-        val overview = desktop.switchToOverview()
+        // Open focused task and go back to Overview to validate whether it has adjacent tasks in
+        // its both sides (grid task on left and desktop tasks at its right side)
+        val focusedTaskOpened = overview.getTestActivityTask(TEST_ACTIVITY_2).open()
 
-        // Dismiss focused task
-        val focusedTask1 = overview.getTestActivityTask(TEST_ACTIVITY_2)
-        assertTaskContentDescription(focusedTask1, TEST_ACTIVITY_2)
-        focusedTask1.dismiss()
-
-        // Dismiss DesktopTaskView
+        // Fling to desktop task and dismiss the focused task to check repositioning of
+        // grid tasks.
+        overview = focusedTaskOpened.switchToOverview().apply { flingBackward() }
         val desktopTask = overview.currentTask
         assertWithMessage("The current task is not a Desktop.").that(desktopTask.isDesktop).isTrue()
+
+        // Get focused task (previously opened task) then dismiss this task
+        val focusedTaskInOverview = overview.getTestActivityTask(TEST_ACTIVITY_2)
+        assertTaskContentDescription(focusedTaskInOverview, TEST_ACTIVITY_2)
+        focusedTaskInOverview.dismiss()
+
+        // Dismiss DesktopTask to validate whether the new focused task will take its position
         desktopTask.dismiss()
 
-        // Dismiss focused task
-        val focusedTask2 = overview.currentTask
-        assertTaskContentDescription(focusedTask2, TEST_ACTIVITY_1)
-        focusedTask2.dismiss()
+        // Dismiss last focused task
+        val lastFocusedTask = overview.currentTask
+        assertTaskContentDescription(lastFocusedTask, TEST_ACTIVITY_1)
+        lastFocusedTask.dismiss()
 
         assertWithMessage("Still have tasks after dismissing all the tasks")
             .that(mLauncher.workspace.switchToOverview().hasTasks())
diff --git a/res/drawable/ic_corp_off.xml b/res/drawable/ic_corp_off.xml
index 117258e..d4bb2f3 100644
--- a/res/drawable/ic_corp_off.xml
+++ b/res/drawable/ic_corp_off.xml
@@ -16,9 +16,9 @@
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?android:attr/textColorHint">
+    android:viewportHeight="24">
     <path
-        android:fillColor="@android:color/white"
-        android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v1.17L10.83,8L20,8v9.17l1.98,1.98c0,-0.05 0.02,-0.1 0.02,-0.16L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2zM19,19L8,8 6,6 2.81,2.81 1.39,4.22 3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19c0,1.11 0.89,2 2,2h14.17l1.61,1.61 1.41,-1.41 -0.37,-0.37L19,19zM4,19L4,8h1.17l11,11L4,19z" />
-</vector>
\ No newline at end of file
+        android:pathData="M16,6H20C21.11,6 22,6.89 22,8V18.99C22,19.021 21.994,19.05 21.989,19.077C21.984,19.102 21.98,19.126 21.98,19.15L20,17.17V8H10.83L8,5.17V4C8,2.89 8.89,2 10,2H14C15.11,2 16,2.89 16,4V6ZM10,6H14V4H10V6ZM19,19L8,8L6,6L2.81,2.81L1.39,4.22L3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19C2,20.11 2.89,21 4,21H18.17L19.78,22.61L21.19,21.2L20.82,20.83L19,19ZM4,8V19H16.17L5.17,8H4Z"
+        android:fillColor="?attr/materialColorOnPrimary"
+        android:fillType="evenOdd"/>
+</vector>
diff --git a/res/drawable/ic_schedule.xml b/res/drawable/ic_schedule.xml
new file mode 100644
index 0000000..3eeb6a2
--- /dev/null
+++ b/res/drawable/ic_schedule.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960"
+    android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="?attr/materialColorOnPrimary"
+        android:pathData="M612,668L668,612L520,464L520,280L440,280L440,496L612,668ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
+</vector>
diff --git a/res/drawable/work_mode_fab_background.xml b/res/drawable/work_mode_fab_background.xml
index fd948d1..5bad965 100644
--- a/res/drawable/work_mode_fab_background.xml
+++ b/res/drawable/work_mode_fab_background.xml
@@ -18,7 +18,7 @@
     <item>
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/work_fab_radius" />
-            <solid android:color="@color/work_fab_bg_color" />
+            <solid android:color="?attr/materialColorPrimary" />
             <padding
                 android:left="@dimen/work_mode_fab_background_horizontal_padding"
                 android:right="@dimen/work_mode_fab_background_horizontal_padding"/>
diff --git a/res/drawable/work_scheduler_background.xml b/res/drawable/work_scheduler_background.xml
new file mode 100644
index 0000000..6bbf029
--- /dev/null
+++ b/res/drawable/work_scheduler_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/accent_ripple_color">
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/work_fab_radius" />
+            <solid android:color="?attr/materialColorPrimary" />
+            <padding
+                android:padding="@dimen/work_scheduler_background_padding" />
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index fc59e56..46f2d8a 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -12,11 +12,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.allapps.WorkModeSwitch
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/work_mode_toggle"
-    android:layout_alignParentBottom="true"
-    android:layout_alignParentEnd="true"
     android:layout_height="@dimen/work_fab_height"
     android:layout_width="wrap_content"
     android:minHeight="@dimen/work_fab_height"
@@ -31,7 +29,6 @@
         android:layout_marginVertical="@dimen/work_fab_icon_vertical_margin"
         android:importantForAccessibility="no"
         android:src="@drawable/ic_corp_off"
-        android:tint="@color/work_fab_icon_color"
         android:layout_marginStart="@dimen/work_fab_icon_start_margin_expanded"
         android:scaleType="center"/>
     <TextView
@@ -39,7 +36,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:maxWidth="@dimen/work_fab_width"
-        android:textColor="@color/work_fab_icon_color"
+        android:textColor="?attr/materialColorOnPrimary"
         android:textSize="14sp"
         android:includeFontPadding="false"
         android:textDirection="locale"
@@ -48,4 +45,4 @@
         android:layout_marginEnd="@dimen/work_fab_text_end_margin"
         android:maxLines="1"
         style="@style/TextHeadline"/>
-</com.android.launcher3.allapps.WorkModeSwitch>
+</LinearLayout>
diff --git a/res/layout/work_mode_utility_view.xml b/res/layout/work_mode_utility_view.xml
new file mode 100644
index 0000000..fc112ce
--- /dev/null
+++ b/res/layout/work_mode_utility_view.xml
@@ -0,0 +1,32 @@
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+<com.android.launcher3.allapps.WorkUtilityView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:orientation="vertical"
+    android:layout_alignParentBottom="true"
+    android:layout_alignParentEnd="true">
+    <ImageButton
+        android:id="@+id/work_scheduler"
+        android:layout_width="@dimen/work_scheduler_size"
+        android:layout_height="@dimen/work_scheduler_size"
+        android:layout_marginBottom="@dimen/work_scheduler_bottom_margin"
+        android:contentDescription="@string/work_scheduler_button_content_description"
+        android:src="@drawable/ic_schedule"
+        android:layout_gravity="end"
+        android:background="@drawable/work_scheduler_background" />
+    <include layout="@layout/work_mode_fab" />
+</com.android.launcher3.allapps.WorkUtilityView>
diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml
index 0f630e5..d9f9769 100644
--- a/res/values-night-v31/colors.xml
+++ b/res/values-night-v31/colors.xml
@@ -53,10 +53,5 @@
     <color name="widget_picker_add_button_text_color_dark">
         @android:color/system_accent1_800</color>
 
-    <color name="work_fab_bg_color">
-        @android:color/system_accent1_200</color>
-    <color name="work_fab_icon_color">
-        @android:color/system_accent1_900</color>
-
     <color name="material_color_on_surface">@android:color/system_neutral1_100</color>
 </resources>
\ No newline at end of file
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index a5cdfc7..d74e308 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -104,11 +104,6 @@
     <color name="widget_picker_add_button_text_color_light">
         @android:color/system_accent1_0</color>
 
-    <color name="work_fab_bg_color">
-        @android:color/system_accent1_200</color>
-    <color name="work_fab_icon_color">
-        @android:color/system_accent1_900</color>
-
     <color name="overview_foreground_scrim_color">@android:color/system_neutral1_1000</color>
 
     <color name="material_color_on_surface">@android:color/system_neutral1_900</color>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 16ea0cd..4dddb9a 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -268,6 +268,9 @@
              defaults to @dimen/taskbar_button_margin_default -->
         <attr name="inlineNavButtonsEndSpacing" format="reference" />
 
+        <!-- Grid flips row and column count when rotating the device -->
+        <attr name="isDualGrid" format="boolean" />
+
         <attr name="dbFile" format="string" />
         <attr name="defaultLayoutId" format="reference" />
         <attr name="demoModeLayoutId" format="reference" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 1eca88d..fa1626e 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -98,8 +98,6 @@
     <color name="preload_icon_background_color_dark">#40484D</color>
 
     <color name="work_turn_on_stroke">?android:attr/colorAccent</color>
-    <color name="work_fab_bg_color">#A8C7FA</color>
-    <color name="work_fab_icon_color">#041E49</color>
 
     <color name="widget_picker_primary_surface_color_light">#EFEDED</color>
     <color name="widget_picker_secondary_surface_color_light">#FAF9F8</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 037687d..d4773c3 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -166,6 +166,9 @@
     <dimen name="work_fab_margin">16dp</dimen>
     <dimen name="work_fab_margin_bottom">20dp</dimen>
     <dimen name="work_mode_fab_background_horizontal_padding">16dp</dimen>
+    <dimen name="work_scheduler_background_padding">16dp</dimen>
+    <dimen name="work_scheduler_bottom_margin">8dp</dimen>
+    <dimen name="work_scheduler_size">56dp</dimen>
     <dimen name="work_profile_footer_padding">20dp</dimen>
     <dimen name="work_edu_card_margin">16dp</dimen>
     <dimen name="work_edu_card_radius">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d918698..746bd7e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -466,6 +466,8 @@
     <string name="work_profile_edu_accept">Got it</string>
     <!-- Info icon unicode for alpha scroller when work edu card is present -->
     <string name="work_profile_edu_section" translatable="false">\u24D8</string>
+    <!-- Intent for work profiler scheduler -->
+    <string name="work_profile_scheduler_intent" translatable="false"/>
 
     <!--- heading shown when user opens work apps tab while work apps are paused -->
     <string name="work_apps_paused_title">Work apps are paused</string>
@@ -484,6 +486,8 @@
     <string name="work_apps_pause_btn_text">Pause work apps</string>
     <!-- button string shown enable work profile -->
     <string name="work_apps_enable_btn_text">Unpause</string>
+    <!-- Label for the work profile scheduler button in the work profile screen. [CHAR_LIMIT=40] -->
+    <string name="work_scheduler_button_content_description">Work apps schedule</string>
 
     <!-- A hint shown in launcher settings develop options filter box -->
     <string name="developer_options_filter_hint">Filter</string>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 4305703..c25e8fb 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -827,7 +827,7 @@
             hotseatBorderSpace = cellLayoutBorderSpacePx.y;
         }
 
-        if (isTablet) {
+        if (shouldShowAllAppsOnSheet()) {
             allAppsPadding.top = mInsets.top;
             allAppsShiftRange = heightPx;
         } else {
@@ -1516,6 +1516,11 @@
         }
     }
 
+    /** Whether All Apps should be presented on a bottom sheet. */
+    public boolean shouldShowAllAppsOnSheet() {
+        return isTablet || Flags.allAppsSheetForHandheld();
+    }
+
     private void setupAllAppsStyle(Context context) {
         TypedArray allAppsStyle = context.obtainStyledAttributes(
                 inv.allAppsStyle != INVALID_RESOURCE_HANDLE ? inv.allAppsStyle
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 1b38695..7112a1b 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -510,7 +510,7 @@
         }
     }
 
-    private List<DisplayOption> getPredefinedDeviceProfiles(Context context,
+    private static List<DisplayOption> getPredefinedDeviceProfiles(Context context,
             String gridName, @DeviceType int deviceType, boolean allowDisabledGrid) {
         ArrayList<DisplayOption> profiles = new ArrayList<>();
 
@@ -524,7 +524,7 @@
 
                     GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser));
                     if ((gridOption.isEnabled(deviceType) || allowDisabledGrid)
-                            && (Flags.oneGridSpecs() == gridOption.isNewGridOption())) {
+                            && gridOption.filterByFlag(deviceType)) {
                         final int displayDepth = parser.getDepth();
                         while (((type = parser.next()) != XmlPullParser.END_TAG
                                 || parser.getDepth() > displayDepth)
@@ -680,7 +680,7 @@
         return parseAllDefinedGridOptions(context)
                 .stream()
                 .filter(go -> go.isEnabled(deviceType))
-                .filter(go -> (Flags.oneGridSpecs() == go.isNewGridOption()))
+                .filter(go -> go.filterByFlag(deviceType))
                 .collect(Collectors.toList());
     }
 
@@ -937,6 +937,7 @@
         private final int demoModeLayoutId;
 
         private final boolean isScalable;
+        private final boolean mIsDualGrid;
         private final int devicePaddingId;
         private final int mWorkspaceSpecsId;
         private final int mWorkspaceSpecsTwoPanelId;
@@ -961,6 +962,7 @@
                     DEVICE_CATEGORY_ALL);
             mRowCountSpecsId = a.getResourceId(
                     R.styleable.GridDisplayOption_rowCountSpecsId, INVALID_RESOURCE_HANDLE);
+            mIsDualGrid = a.getBoolean(R.styleable.GridDisplayOption_isDualGrid, false);
             if (mRowCountSpecsId != INVALID_RESOURCE_HANDLE) {
                 ResourceHelper resourceHelper = new ResourceHelper(context, mRowCountSpecsId);
                 NumRows numR = getRowCount(resourceHelper, context, deviceCategory);
@@ -1124,6 +1126,13 @@
         public boolean isNewGridOption() {
             return mRowCountSpecsId != INVALID_RESOURCE_HANDLE;
         }
+
+        public boolean filterByFlag(int deviceType) {
+            if (deviceType == TYPE_TABLET) {
+                return Flags.oneGridRotationHandling() == mIsDualGrid;
+            }
+            return Flags.oneGridSpecs() == isNewGridOption();
+        }
     }
 
     public static final class NumRows {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 102189b..7d5e481 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -375,8 +375,14 @@
     }
 
     public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
-        if ((this != NORMAL && this != HINT_STATE)
-                || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
+        DeviceProfile dp = launcher.getDeviceProfile();
+        boolean shouldFadeAdjacentScreens = (this == NORMAL || this == HINT_STATE)
+                && dp.shouldFadeAdjacentWorkspaceScreens();
+        // Avoid showing adjacent screens behind handheld All Apps sheet.
+        if (Flags.allAppsSheetForHandheld() && dp.isPhone && this == ALL_APPS) {
+            shouldFadeAdjacentScreens = true;
+        }
+        if (!shouldFadeAdjacentScreens) {
             return DEFAULT_ALPHA_PROVIDER;
         }
         final int centerPage = launcher.getWorkspace().getNextPage();
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 0dd2791..fc8465d 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -47,7 +47,6 @@
 import android.os.Process;
 import android.os.UserManager;
 import android.util.AttributeSet;
-import android.util.FloatProperty;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.KeyEvent;
@@ -115,19 +114,6 @@
         ScrimView.ScrimDrawingController {
 
 
-    public static final FloatProperty<ActivityAllAppsContainerView<?>> BOTTOM_SHEET_ALPHA =
-            new FloatProperty<>("bottomSheetAlpha") {
-                @Override
-                public Float get(ActivityAllAppsContainerView<?> containerView) {
-                    return containerView.mBottomSheetAlpha;
-                }
-
-                @Override
-                public void setValue(ActivityAllAppsContainerView<?> containerView, float v) {
-                    containerView.setBottomSheetAlpha(v);
-                }
-            };
-
     public static final float PULL_MULTIPLIER = .02f;
     public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
     protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
@@ -191,8 +177,6 @@
     private ScrimView mScrimView;
     private int mHeaderColor;
     private int mBottomSheetBackgroundColor;
-    private float mBottomSheetAlpha = 1f;
-    private boolean mForceBottomSheetVisible;
     private int mTabsProtectionAlpha;
     @Nullable private AllAppsTransitionController mAllAppsTransitionController;
 
@@ -351,20 +335,6 @@
         return mSearchUiManager;
     }
 
-    public View getBottomSheetBackground() {
-        return mBottomSheetBackground;
-    }
-
-    /**
-     * Temporarily force the bottom sheet to be visible on non-tablets.
-     *
-     * @param force {@code true} means bottom sheet will be visible on phones until {@code reset()}.
-     */
-    public void forceBottomSheetVisible(boolean force) {
-        mForceBottomSheetVisible = force;
-        updateBackgroundVisibility(mActivityContext.getDeviceProfile());
-    }
-
     public View getSearchView() {
         return mSearchContainer;
     }
@@ -496,7 +466,7 @@
         if (mHeader != null && mHeader.getVisibility() == VISIBLE) {
             mHeader.reset(animate);
         }
-        forceBottomSheetVisible(false);
+        updateBackgroundVisibility(mActivityContext.getDeviceProfile());
         // Reset the base recycler view after transitioning home.
         updateHeaderScroll(0);
         if (exitSearch) {
@@ -726,7 +696,7 @@
             post(() -> mAH.get(AdapterHolder.WORK).applyPadding());
 
         } else {
-            mWorkManager.detachWorkModeSwitch();
+            mWorkManager.detachWorkUtilityViews();
             mViewPager = null;
         }
 
@@ -1002,18 +972,13 @@
     }
 
     protected void updateBackgroundVisibility(DeviceProfile deviceProfile) {
-        boolean visible = deviceProfile.isTablet || mForceBottomSheetVisible;
-        mBottomSheetBackground.setVisibility(visible ? View.VISIBLE : View.GONE);
-        // Note: For tablets, the opaque background and header protection are added in drawOnScrim.
+        mBottomSheetBackground.setVisibility(
+                deviceProfile.shouldShowAllAppsOnSheet() ? View.VISIBLE : View.GONE);
+        // Note: The opaque sheet background and header protection are added in drawOnScrim.
         // For the taskbar entrypoint, the scrim is drawn by its abstract slide in view container,
         // so its header protection is derived from this scrim instead.
     }
 
-    private void setBottomSheetAlpha(float alpha) {
-        // Bottom sheet alpha is always 1 for tablets.
-        mBottomSheetAlpha = mActivityContext.getDeviceProfile().isTablet ? 1f : alpha;
-    }
-
     @VisibleForTesting
     public void onAppsUpdated() {
         mHasWorkApps = Stream.of(mAllAppsStore.getApps())
@@ -1151,8 +1116,8 @@
         applyAdapterSideAndBottomPaddings(grid);
 
         MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
-        // Ignore left/right insets on tablet because we are already centered in-screen.
-        if (grid.isTablet) {
+        // Ignore left/right insets on bottom sheet because we are already centered in-screen.
+        if (grid.shouldShowAllAppsOnSheet()) {
             mlp.leftMargin = mlp.rightMargin = 0;
         } else {
             mlp.leftMargin = insets.left;
@@ -1257,8 +1222,8 @@
     /** Called in Launcher#bindStringCache() to update the UI when cache is updated. */
     public void updateWorkUI() {
         setDeviceManagementResources();
-        if (mWorkManager.getWorkModeSwitch() != null) {
-            mWorkManager.getWorkModeSwitch().updateStringFromCache();
+        if (mWorkManager.getWorkUtilityView() != null) {
+            mWorkManager.getWorkUtilityView().updateStringFromCache();
         }
         inflateWorkCardsIfNeeded();
     }
@@ -1398,7 +1363,7 @@
         // Draw full background panel for tablets.
         if (hasBottomSheet) {
             mHeaderPaint.setColor(mBottomSheetBackgroundColor);
-            mHeaderPaint.setAlpha((int) (255 * mBottomSheetAlpha));
+            mHeaderPaint.setAlpha(255);
 
             mTmpRectF.set(
                     leftWithScale,
@@ -1581,8 +1546,8 @@
         void applyPadding() {
             if (mRecyclerView != null) {
                 int bottomOffset = 0;
-                if (isWork() && mWorkManager.getWorkModeSwitch() != null) {
-                    bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
+                if (isWork() && mWorkManager.getWorkUtilityView() != null) {
+                    bottomOffset = mInsets.bottom + mWorkManager.getWorkUtilityView().getHeight();
                 } else if (isMain() && mPrivateProfileManager != null) {
                     Optional<AdapterItem> privateSpaceHeaderItem = mAppsList.getAdapterItems()
                             .stream()
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c6852e0..bd604eb 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.allapps;
 
 import static com.android.app.animation.Interpolators.DECELERATE_1_7;
-import static com.android.app.animation.Interpolators.INSTANT;
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
@@ -28,7 +27,6 @@
 import static com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree;
 import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_BOTTOM_SHEET_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
@@ -106,7 +104,7 @@
 
                 @Override
                 public Float get(AllAppsTransitionController controller) {
-                    if (controller.mIsTablet) {
+                    if (controller.mShouldShowAllAppsOnSheet) {
                         return controller.mAppsView.getActiveRecyclerView().getTranslationY();
                     } else {
                         return controller.getAppsViewPullbackTranslationY().getValue();
@@ -115,7 +113,7 @@
 
                 @Override
                 public void setValue(AllAppsTransitionController controller, float translation) {
-                    if (controller.mIsTablet) {
+                    if (controller.mShouldShowAllAppsOnSheet) {
                         controller.mAppsView.getActiveRecyclerView().setTranslationY(translation);
                         controller.getAppsViewPullbackTranslationY().setValue(
                                 ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT);
@@ -134,7 +132,7 @@
 
                 @Override
                 public Float get(AllAppsTransitionController controller) {
-                    if (controller.mIsTablet) {
+                    if (controller.mShouldShowAllAppsOnSheet) {
                         return controller.mAppsView.getActiveRecyclerView().getAlpha();
                     } else {
                         return controller.getAppsViewPullbackAlpha().getValue();
@@ -143,7 +141,7 @@
 
                 @Override
                 public void setValue(AllAppsTransitionController controller, float alpha) {
-                    if (controller.mIsTablet) {
+                    if (controller.mShouldShowAllAppsOnSheet) {
                         controller.mAppsView.getActiveRecyclerView().setAlpha(alpha);
                         controller.getAppsViewPullbackAlpha().setValue(
                                 ALL_APPS_PULL_BACK_ALPHA_DEFAULT);
@@ -168,6 +166,7 @@
     @Nullable private Animator.AnimatorListener mAllAppsSearchBackAnimationListener;
 
     private boolean mIsVerticalLayout;
+    private boolean mShouldShowAllAppsOnSheet;
 
     // Animation in this class is controlled by a single variable {@link mProgress}.
     // Visually, it represents top y coordinate of the all apps container if multiplied with
@@ -183,8 +182,6 @@
     private MultiValueAlpha mAppsViewAlpha;
     private MultiPropertyFactory<View> mAppsViewTranslationY;
 
-    private boolean mIsTablet;
-
     private boolean mHasScaleEffect;
     private final VibratorWrapper mVibratorWrapper;
 
@@ -193,7 +190,7 @@
         DeviceProfile dp = mLauncher.getDeviceProfile();
         mProgress = 1f;
         mIsVerticalLayout = dp.isVerticalBarLayout();
-        mIsTablet = dp.isTablet;
+        mShouldShowAllAppsOnSheet = dp.shouldShowAllAppsOnSheet();
         mNavScrimFlag = Themes.getAttrBoolean(l, R.attr.isMainColorDark)
                 ? FLAG_DARK_NAV : FLAG_LIGHT_NAV;
 
@@ -217,7 +214,7 @@
             mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
         }
 
-        mIsTablet = dp.isTablet;
+        mShouldShowAllAppsOnSheet = dp.shouldShowAllAppsOnSheet();
     }
 
     /**
@@ -395,10 +392,6 @@
         setter.setFloat(getAppsViewPullbackAlpha(), MultiPropertyFactory.MULTI_PROPERTY_VALUE,
                 hasAllAppsContent ? 1 : 0, allAppsFade);
 
-        setter.setFloat(mLauncher.getAppsView(),
-                ActivityAllAppsContainerView.BOTTOM_SHEET_ALPHA, hasAllAppsContent ? 1 : 0,
-                config.getInterpolator(ANIM_ALL_APPS_BOTTOM_SHEET_FADE, INSTANT));
-
         boolean shouldProtectHeader = !config.hasAnimationFlag(StateAnimationConfig.SKIP_SCRIM)
                 && (ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS);
         mScrimView.setDrawingController(shouldProtectHeader ? mAppsView : null);
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 96998a3..3d0c1d0 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -58,7 +58,7 @@
         implements PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
     private static final String TAG = "WorkProfileManager";
     private final ActivityAllAppsContainerView<?> mAllApps;
-    private WorkModeSwitch mWorkModeSwitch;
+    private WorkUtilityView mWorkUtilityView;
     private final Predicate<UserHandle> mWorkProfileMatcher;
 
     public WorkProfileManager(
@@ -79,15 +79,15 @@
 
     @Override
     public void onActivePageChanged(int page) {
-        updateWorkFAB(page);
+        updateWorkUtilityViews(page);
     }
 
-    private void updateWorkFAB(int page) {
-        if (mWorkModeSwitch != null) {
+    private void updateWorkUtilityViews(int page) {
+        if (mWorkUtilityView != null) {
             if (page == MAIN || page == SEARCH) {
-                mWorkModeSwitch.animateVisibility(false);
+                mWorkUtilityView.animateVisibility(false);
             } else if (page == WORK && getCurrentState() == STATE_ENABLED) {
-                mWorkModeSwitch.animateVisibility(true);
+                mWorkUtilityView.animateVisibility(true);
             }
         }
     }
@@ -104,10 +104,10 @@
         }
         boolean isEnabled = !mAllApps.getAppsStore().hasModelFlag(quietModeFlag);
         updateCurrentState(isEnabled ? STATE_ENABLED : STATE_DISABLED);
-        if (mWorkModeSwitch != null) {
+        if (mWorkUtilityView != null) {
             // reset the position of the button and clear IME insets.
-            mWorkModeSwitch.getImeInsets().setEmpty();
-            mWorkModeSwitch.updateTranslationY();
+            mWorkUtilityView.getImeInsets().setEmpty();
+            mWorkUtilityView.updateTranslationY();
         }
     }
 
@@ -116,54 +116,54 @@
         if (getAH() != null) {
             getAH().mAppsList.updateAdapterItems();
         }
-        if (mWorkModeSwitch != null) {
-            updateWorkFAB(mAllApps.getCurrentPage());
+        if (mWorkUtilityView != null) {
+            updateWorkUtilityViews(mAllApps.getCurrentPage());
         }
         if (getCurrentState() == STATE_ENABLED) {
-            attachWorkModeSwitch();
+            attachWorkUtilityViews();
         } else if (getCurrentState() == STATE_DISABLED) {
-            detachWorkModeSwitch();
+            detachWorkUtilityViews();
         }
     }
 
     /**
      * Creates and attaches for profile toggle button to {@link ActivityAllAppsContainerView}
      */
-    public boolean attachWorkModeSwitch() {
+    public boolean attachWorkUtilityViews() {
         if (!mAllApps.getAppsStore().hasModelFlag(
                 FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION)) {
             Log.e(TAG, "unable to attach work mode switch; Missing required permissions");
             return false;
         }
-        if (mWorkModeSwitch == null) {
-            mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
-                    R.layout.work_mode_fab, mAllApps, false);
+        if (mWorkUtilityView == null) {
+            mWorkUtilityView = (WorkUtilityView) mAllApps.getLayoutInflater().inflate(
+                    R.layout.work_mode_utility_view, mAllApps, false);
         }
-        if (mWorkModeSwitch.getParent() == null) {
-            mAllApps.addView(mWorkModeSwitch);
+        if (mWorkUtilityView.getParent() == null) {
+            mAllApps.addView(mWorkUtilityView);
         }
         if (mAllApps.getCurrentPage() != WORK) {
-            mWorkModeSwitch.animateVisibility(false);
+            mWorkUtilityView.animateVisibility(false);
         }
         if (getAH() != null) {
             getAH().applyPadding();
         }
-        mWorkModeSwitch.setOnClickListener(this::onWorkFabClicked);
+        mWorkUtilityView.setOnClickListener(this::onWorkFabClicked);
         return true;
     }
     /**
      * Removes work profile toggle button from {@link ActivityAllAppsContainerView}
      */
-    public void detachWorkModeSwitch() {
-        if (mWorkModeSwitch != null && mWorkModeSwitch.getParent() == mAllApps) {
-            mAllApps.removeView(mWorkModeSwitch);
+    public void detachWorkUtilityViews() {
+        if (mWorkUtilityView != null && mWorkUtilityView.getParent() == mAllApps) {
+            mAllApps.removeView(mWorkUtilityView);
         }
-        mWorkModeSwitch = null;
+        mWorkUtilityView = null;
     }
 
     @Nullable
-    public WorkModeSwitch getWorkModeSwitch() {
-        return mWorkModeSwitch;
+    public WorkUtilityView getWorkUtilityView() {
+        return mWorkUtilityView;
     }
 
     private ActivityAllAppsContainerView.AdapterHolder getAH() {
@@ -199,7 +199,7 @@
     }
 
     private void onWorkFabClicked(View view) {
-        if (getCurrentState() == STATE_ENABLED && mWorkModeSwitch.isEnabled()) {
+        if (getCurrentState() == STATE_ENABLED && mWorkUtilityView.isEnabled()) {
             logEvents(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
             setWorkProfileEnabled(false);
         }
@@ -216,7 +216,7 @@
             }
             @Override
             public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
-                WorkModeSwitch fab = getWorkModeSwitch();
+                WorkUtilityView fab = getWorkUtilityView();
                 if (fab == null){
                     return;
                 }
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkUtilityView.java
similarity index 65%
rename from src/com/android/launcher3/allapps/WorkModeSwitch.java
rename to src/com/android/launcher3/allapps/WorkUtilityView.java
index f1f72b2..4b58ab0 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkUtilityView.java
@@ -21,11 +21,13 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Rect;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.ViewGroup;
 import android.view.WindowInsets;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -36,6 +38,7 @@
 
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -43,10 +46,13 @@
 import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.views.ActivityContext;
+
+import java.util.ArrayList;
+
 /**
- * Work profile toggle switch shown at the bottom of AllApps work tab
+ * Work profile utility ViewGroup that is shown at the bottom of AllApps work tab
  */
-public class WorkModeSwitch extends LinearLayout implements Insettable,
+public class WorkUtilityView extends LinearLayout implements Insettable,
         KeyboardInsetAnimationCallback.KeyboardInsetListener {
 
     private static final int TEXT_EXPAND_OPACITY_DURATION = 300;
@@ -54,10 +60,14 @@
     private static final int EXPAND_COLLAPSE_DURATION = 300;
     private static final int TEXT_ALPHA_EXPAND_DELAY = 80;
     private static final int TEXT_ALPHA_COLLAPSE_DELAY = 0;
+    private static final int WORK_SCHEDULER_OPACITY_DURATION =
+            (int) (EXPAND_COLLAPSE_DURATION * 0.75f);
     private static final int FLAG_FADE_ONGOING = 1 << 1;
     private static final int FLAG_TRANSLATION_ONGOING = 1 << 2;
     private static final int FLAG_IS_EXPAND = 1 << 3;
     private static final int SCROLL_THRESHOLD_DP = 10;
+    private static final float WORK_SCHEDULER_SCALE_MIN = 0.25f;
+    private static final float WORK_SCHEDULER_SCALE_MAX = 1f;
 
     private final Rect mInsets = new Rect();
     private final Rect mImeInsets = new Rect();
@@ -67,22 +77,25 @@
     private final int mTextMarginStart;
     private final int mTextMarginEnd;
     private final int mIconMarginStart;
+    private final String mWorkSchedulerIntentAction;
 
     // Threshold when user scrolls up/down to determine when should button extend/collapse
     private final int mScrollThreshold;
-    private TextView mTextView;
-    private ImageView mIcon;
     private ValueAnimator mPauseFABAnim;
+    private TextView mPauseText;
+    private ImageView mWorkIcon;
+    private ImageButton mSchedulerButton;
 
-    public WorkModeSwitch(@NonNull Context context) {
+    public WorkUtilityView(@NonNull Context context) {
         this(context, null, 0);
     }
 
-    public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs) {
+    public WorkUtilityView(@NonNull Context context, @NonNull AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
+    public WorkUtilityView(@NonNull Context context, @NonNull AttributeSet attrs,
+            int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mContext = context;
         mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP);
@@ -93,14 +106,17 @@
                 R.dimen.work_fab_text_end_margin);
         mIconMarginStart = mContext.getResources().getDimensionPixelSize(
                 R.dimen.work_fab_icon_start_margin_expanded);
+        mWorkSchedulerIntentAction = mContext.getResources().getString(
+                R.string.work_profile_scheduler_intent);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mTextView = findViewById(R.id.pause_text);
-        mIcon = findViewById(R.id.work_icon);
+        mPauseText = findViewById(R.id.pause_text);
+        mWorkIcon = findViewById(R.id.work_icon);
+        mSchedulerButton = findViewById(R.id.work_scheduler);
         setSelected(true);
         KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
                 new KeyboardInsetAnimationCallback(this);
@@ -109,6 +125,12 @@
         addFlag(FLAG_IS_EXPAND);
         setInsets(mActivityContext.getDeviceProfile().getInsets());
         updateStringFromCache();
+        mSchedulerButton.setVisibility(GONE);
+        if (shouldUseScheduler()) {
+            mSchedulerButton.setVisibility(VISIBLE);
+            mSchedulerButton.setOnClickListener(view ->
+                    mContext.startActivity(new Intent(mWorkSchedulerIntentAction)));
+        }
     }
 
     @Override
@@ -166,8 +188,10 @@
                 WindowInsetsCompat.toWindowInsetsCompat(insets, this);
         if (windowInsetsCompat.isVisible(WindowInsetsCompat.Type.ime())) {
             setInsets(mImeInsets, windowInsetsCompat.getInsets(WindowInsetsCompat.Type.ime()));
+            shrink();
         } else {
             mImeInsets.setEmpty();
+            extend();
         }
         updateTranslationY();
         return super.onApplyWindowInsets(insets);
@@ -183,15 +207,63 @@
         super.setTranslationY(Math.min(translationY, -mInsets.bottom));
     }
 
+    private ValueAnimator animateSchedulerScale(boolean isExpanding) {
+        float scaleFrom = isExpanding ? WORK_SCHEDULER_SCALE_MIN : WORK_SCHEDULER_SCALE_MAX;
+        float scaleTo = isExpanding ? WORK_SCHEDULER_SCALE_MAX : WORK_SCHEDULER_SCALE_MIN;
+        ValueAnimator schedulerScaleAnim = ObjectAnimator.ofFloat(scaleFrom, scaleTo);
+        schedulerScaleAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+        schedulerScaleAnim.setInterpolator(Interpolators.STANDARD);
+        schedulerScaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                float scale = (float) valueAnimator.getAnimatedValue();
+                mSchedulerButton.setScaleX(scale);
+                mSchedulerButton.setScaleY(scale);
+            }
+        });
+        schedulerScaleAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                if (isExpanding) {
+                    mSchedulerButton.setVisibility(VISIBLE);
+                }
+            }
 
-    private void animatePillTransition(boolean isExpanding) {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!isExpanding) {
+                    mSchedulerButton.setVisibility(GONE);
+                }
+            }
+        });
+        return schedulerScaleAnim;
+    }
+
+    private ValueAnimator animateSchedulerAlpha(boolean isExpanding) {
+        float alphaFrom = isExpanding ? 0 : 1;
+        float alphaTo = isExpanding ? 1 : 0;
+        ValueAnimator schedulerAlphaAnim = ObjectAnimator.ofFloat(alphaFrom, alphaTo);
+        schedulerAlphaAnim.setDuration(WORK_SCHEDULER_OPACITY_DURATION);
+        schedulerAlphaAnim.setStartDelay(isExpanding ? 0 :
+                EXPAND_COLLAPSE_DURATION - WORK_SCHEDULER_OPACITY_DURATION);
+        schedulerAlphaAnim.setInterpolator(Interpolators.STANDARD);
+        schedulerAlphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                mSchedulerButton.setAlpha((float) valueAnimator.getAnimatedValue());
+            }
+        });
+        return schedulerAlphaAnim;
+    }
+
+    private void animateWorkUtilityViews(boolean isExpanding) {
         if (!shouldAnimate(isExpanding)) {
             return;
         }
         AnimatorSet animatorSet = new AnimatedPropertySetter().buildAnim();
-        mTextView.measure(0,0);
-        int currentWidth = mTextView.getWidth();
-        int fullWidth = mTextView.getMeasuredWidth();
+        mPauseText.measure(0,0);
+        int currentWidth = mPauseText.getWidth();
+        int fullWidth = mPauseText.getMeasuredWidth();
         float from = isExpanding ? 0 : currentWidth;
         float to = isExpanding ? fullWidth : 0;
         mPauseFABAnim = ObjectAnimator.ofFloat(from, to);
@@ -203,15 +275,15 @@
                 float translation = (float) valueAnimator.getAnimatedValue();
                 float translationFraction = translation / fullWidth;
                 ViewGroup.MarginLayoutParams textViewLayoutParams =
-                        (ViewGroup.MarginLayoutParams) mTextView.getLayoutParams();
+                        (ViewGroup.MarginLayoutParams) mPauseText.getLayoutParams();
                 textViewLayoutParams.width = (int) translation;
                 textViewLayoutParams.setMarginStart((int) (mTextMarginStart * translationFraction));
                 textViewLayoutParams.setMarginEnd((int) (mTextMarginEnd * translationFraction));
-                mTextView.setLayoutParams(textViewLayoutParams);
+                mPauseText.setLayoutParams(textViewLayoutParams);
                 ViewGroup.MarginLayoutParams iconLayoutParams =
-                        (ViewGroup.MarginLayoutParams) mIcon.getLayoutParams();
+                        (ViewGroup.MarginLayoutParams) mWorkIcon.getLayoutParams();
                 iconLayoutParams.setMarginStart((int) (mIconMarginStart * translationFraction));
-                mIcon.setLayoutParams(iconLayoutParams);
+                mWorkIcon.setLayoutParams(iconLayoutParams);
             }
         });
         mPauseFABAnim.addListener(new AnimatorListenerAdapter() {
@@ -220,21 +292,28 @@
                 if (isExpanding) {
                     addFlag(FLAG_IS_EXPAND);
                 } else {
-                    mTextView.setVisibility(GONE);
+                    mPauseText.setVisibility(GONE);
                     removeFlag(FLAG_IS_EXPAND);
                 }
-                mTextView.setHorizontallyScrolling(false);
-                mTextView.setEllipsize(TextUtils.TruncateAt.END);
+                mPauseText.setHorizontallyScrolling(false);
+                mPauseText.setEllipsize(TextUtils.TruncateAt.END);
             }
 
             @Override
             public void onAnimationStart(Animator animator) {
-                mTextView.setHorizontallyScrolling(true);
-                mTextView.setVisibility(VISIBLE);
-                mTextView.setEllipsize(null);
+                mPauseText.setHorizontallyScrolling(true);
+                mPauseText.setVisibility(VISIBLE);
+                mPauseText.setEllipsize(null);
             }
         });
-        animatorSet.playTogether(mPauseFABAnim, updatePauseTextAlpha(isExpanding));
+        ArrayList<Animator> animatorList = new ArrayList<>();
+        animatorList.add(mPauseFABAnim);
+        animatorList.add(updatePauseTextAlpha(isExpanding));
+        if (shouldUseScheduler()) {
+            animatorList.add(animateSchedulerScale(isExpanding));
+            animatorList.add(animateSchedulerAlpha(isExpanding));
+        }
+        animatorSet.playTogether(animatorList);
         animatorSet.start();
     }
 
@@ -250,7 +329,7 @@
         alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator valueAnimator) {
-                mTextView.setAlpha((float) valueAnimator.getAnimatedValue());
+                mPauseText.setAlpha((float) valueAnimator.getAnimatedValue());
             }
         });
         return alphaAnim;
@@ -287,11 +366,11 @@
     }
 
     public void extend() {
-        animatePillTransition(true);
+        animateWorkUtilityViews(true);
     }
 
-    public void shrink(){
-         animatePillTransition(false);
+    public void shrink() {
+        animateWorkUtilityViews(false);
     }
 
     /**
@@ -310,7 +389,11 @@
     public void updateStringFromCache(){
         StringCache cache = mActivityContext.getStringCache();
         if (cache != null) {
-            mTextView.setText(cache.workProfilePauseButton);
+            mPauseText.setText(cache.workProfilePauseButton);
         }
     }
+
+    private boolean shouldUseScheduler() {
+        return Flags.workSchedulerInWorkProfile() && !mWorkSchedulerIntentAction.isEmpty();
+    }
 }
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 8fe0409..0e20f75 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -20,6 +20,7 @@
 
 import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
 import com.android.launcher3.graphics.IconShape;
+import com.android.launcher3.model.ItemInstallQueue;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.DaggerSingletonTracker;
@@ -48,6 +49,7 @@
     CustomWidgetManager getCustomWidgetManager();
     IconShape getIconShape();
     InstallSessionHelper getInstallSessionHelper();
+    ItemInstallQueue getItemInstallQueue();
     RefreshRateTracker getRefreshRateTracker();
     ScreenOnTracker getScreenOnTracker();
     SettingsCache getSettingsCache();
diff --git a/src/com/android/launcher3/icons/MonochromeIconFactory.java b/src/com/android/launcher3/icons/MonochromeIconFactory.java
deleted file mode 100644
index 2854d51..0000000
--- a/src/com/android/launcher3/icons/MonochromeIconFactory.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2022 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.icons;
-
-import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-
-import android.annotation.TargetApi;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BlendMode;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-
-import androidx.annotation.WorkerThread;
-
-import com.android.launcher3.icons.BaseIconFactory.ClippedMonoDrawable;
-
-import java.nio.ByteBuffer;
-
-/**
- * Utility class to generate monochrome icons version for a given drawable.
- */
-@TargetApi(Build.VERSION_CODES.TIRAMISU)
-public class MonochromeIconFactory extends Drawable {
-
-    private final Bitmap mFlatBitmap;
-    private final Canvas mFlatCanvas;
-    private final Paint mCopyPaint;
-
-    private final Bitmap mAlphaBitmap;
-    private final Canvas mAlphaCanvas;
-    private final byte[] mPixels;
-
-    private final int mBitmapSize;
-    private final int mEdgePixelLength;
-
-    private final Paint mDrawPaint;
-    private final Rect mSrcRect;
-
-    MonochromeIconFactory(int iconBitmapSize) {
-        float extraFactor = AdaptiveIconDrawable.getExtraInsetFraction();
-        float viewPortScale = 1 / (1 + 2 * extraFactor);
-        mBitmapSize = Math.round(iconBitmapSize * 2 * viewPortScale);
-        mPixels = new byte[mBitmapSize * mBitmapSize];
-        mEdgePixelLength = mBitmapSize * (mBitmapSize - iconBitmapSize) / 2;
-
-        mFlatBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ARGB_8888);
-        mFlatCanvas = new Canvas(mFlatBitmap);
-
-        mAlphaBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ALPHA_8);
-        mAlphaCanvas = new Canvas(mAlphaBitmap);
-
-        mDrawPaint = new Paint(FILTER_BITMAP_FLAG);
-        mDrawPaint.setColor(Color.WHITE);
-        mSrcRect = new Rect(0, 0, mBitmapSize, mBitmapSize);
-
-        mCopyPaint = new Paint(FILTER_BITMAP_FLAG);
-        mCopyPaint.setBlendMode(BlendMode.SRC);
-
-        // Crate a color matrix which converts the icon to grayscale and then uses the average
-        // of RGB components as the alpha component.
-        ColorMatrix satMatrix = new ColorMatrix();
-        satMatrix.setSaturation(0);
-        float[] vals = satMatrix.getArray();
-        vals[15] = vals[16] = vals[17] = .3333f;
-        vals[18] = vals[19] = 0;
-        mCopyPaint.setColorFilter(new ColorMatrixColorFilter(vals));
-    }
-
-    private void drawDrawable(Drawable drawable) {
-        if (drawable != null) {
-            drawable.setBounds(0, 0, mBitmapSize, mBitmapSize);
-            drawable.draw(mFlatCanvas);
-        }
-    }
-
-    /**
-     * Creates a monochrome version of the provided drawable
-     */
-    @WorkerThread
-    public Drawable wrap(AdaptiveIconDrawable icon) {
-        mFlatCanvas.drawColor(Color.BLACK);
-        drawDrawable(icon.getBackground());
-        drawDrawable(icon.getForeground());
-        generateMono();
-        return new ClippedMonoDrawable(this);
-    }
-
-    @WorkerThread
-    private void generateMono() {
-        mAlphaCanvas.drawBitmap(mFlatBitmap, 0, 0, mCopyPaint);
-
-        // Scale the end points:
-        ByteBuffer buffer = ByteBuffer.wrap(mPixels);
-        buffer.rewind();
-        mAlphaBitmap.copyPixelsToBuffer(buffer);
-
-        int min = 0xFF;
-        int max = 0;
-        for (byte b : mPixels) {
-            min = Math.min(min, b & 0xFF);
-            max = Math.max(max, b & 0xFF);
-        }
-
-        if (min < max) {
-            // rescale pixels to increase contrast
-            float range = max - min;
-
-            // In order to check if the colors should be flipped, we just take the average color
-            // of top and bottom edge which should correspond to be background color. If the edge
-            // colors have more opacity, we flip the colors;
-            int sum = 0;
-            for (int i = 0; i < mEdgePixelLength; i++) {
-                sum += (mPixels[i] & 0xFF);
-                sum += (mPixels[mPixels.length - 1 - i] & 0xFF);
-            }
-            float edgeAverage = sum / (mEdgePixelLength * 2f);
-            float edgeMapped = (edgeAverage - min) / range;
-            boolean flipColor = edgeMapped > .5f;
-
-            for (int i = 0; i < mPixels.length; i++) {
-                int p = mPixels[i] & 0xFF;
-                int p2 = Math.round((p - min) * 0xFF / range);
-                mPixels[i] = flipColor ? (byte) (255 - p2) : (byte) (p2);
-            }
-            buffer.rewind();
-            mAlphaBitmap.copyPixelsFromBuffer(buffer);
-        }
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        canvas.drawBitmap(mAlphaBitmap, mSrcRect, getBounds(), mDrawPaint);
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-
-    @Override
-    public void setAlpha(int i) {
-        mDrawPaint.setAlpha(i);
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter colorFilter) {
-        mDrawPaint.setColorFilter(colorFilter);
-    }
-}
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 49f75eb..f9c6e96 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -45,16 +45,18 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.shortcuts.ShortcutRequest;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.DaggerSingletonObject;
 import com.android.launcher3.util.PersistedItemArray;
 import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 
 import java.util.HashSet;
@@ -62,10 +64,13 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import javax.inject.Inject;
+
 /**
  * Class to maintain a queue of pending items to be added to the workspace.
  */
-public class ItemInstallQueue implements SafeCloseable {
+@LauncherAppSingleton
+public class ItemInstallQueue {
 
     private static final String LOG = "ItemInstallQueue";
 
@@ -81,9 +86,8 @@
     public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450;
     public static final int NEW_SHORTCUT_STAGGER_DELAY = 85;
 
-    public static MainThreadInitializedObject<ItemInstallQueue> INSTANCE =
-            new MainThreadInitializedObject<>(ItemInstallQueue::new);
-
+    public static DaggerSingletonObject<ItemInstallQueue> INSTANCE =
+            new DaggerSingletonObject<>(LauncherBaseAppComponent::getItemInstallQueue);
     private final PersistedItemArray<PendingInstallShortcutInfo> mStorage =
             new PersistedItemArray<>(APPS_PENDING_INSTALL);
     private final Context mContext;
@@ -95,13 +99,11 @@
     // Only accessed on worker thread
     private List<PendingInstallShortcutInfo> mItems;
 
-    private ItemInstallQueue(Context context) {
+    @Inject
+    public ItemInstallQueue(@ApplicationContext Context context) {
         mContext = context;
     }
 
-    @Override
-    public void close() {}
-
     @WorkerThread
     private void ensureQueueLoaded() {
         Preconditions.assertWorkerThread();
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index 0ca5afd..2ffbbf4 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -77,7 +77,6 @@
             ANIM_WORKSPACE_PAGE_TRANSLATE_X,
             ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN,
             ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE,
-            ANIM_ALL_APPS_BOTTOM_SHEET_FADE,
             ANIM_ALL_APPS_KEYBOARD_FADE
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -101,8 +100,7 @@
     public static final int ANIM_WORKSPACE_PAGE_TRANSLATE_X = 15;
     public static final int ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN = 17;
     public static final int ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE = 18;
-    public static final int ANIM_ALL_APPS_BOTTOM_SHEET_FADE = 19;
-    public static final int ANIM_ALL_APPS_KEYBOARD_FADE = 20;
+    public static final int ANIM_ALL_APPS_KEYBOARD_FADE = 19;
 
     private static final int ANIM_TYPES_COUNT = 21;
 
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 9dcdf22..107bcc1 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -198,7 +198,7 @@
      * Applies Animation config values for transition from all apps to home.
      */
     public static void applyAllAppsToNormalConfig(Launcher launcher, StateAnimationConfig config) {
-        if (launcher.getDeviceProfile().isTablet) {
+        if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
             config.setInterpolator(ANIM_SCRIM_FADE,
                     Interpolators.reverse(ALL_APPS_SCRIM_RESPONDER));
             config.setInterpolator(ANIM_ALL_APPS_FADE, FINAL_FRAME);
@@ -240,7 +240,7 @@
      */
     public static void applyNormalToAllAppsAnimConfig(
             Launcher launcher, StateAnimationConfig config) {
-        if (launcher.getDeviceProfile().isTablet) {
+        if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
             config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
             config.setInterpolator(ANIM_SCRIM_FADE, ALL_APPS_SCRIM_RESPONDER);
             if (!config.isUserControlled()) {
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index a45e3bb..33ffd1d 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -158,16 +158,16 @@
 
 
         waitForLauncherCondition("work profile initial state check failed", launcher ->
-                        manager.getWorkModeSwitch() != null
+                        manager.getWorkUtilityView() != null
                                 && manager.getCurrentState() == WorkProfileManager.STATE_ENABLED
-                                && manager.getWorkModeSwitch().isEnabled(),
+                                && manager.getWorkUtilityView().isEnabled(),
                 LauncherInstrumentation.WAIT_TIME_MS);
 
         //start work profile toggle OFF test
         executeOnLauncher(l -> {
             // Ensure updates are not deferred so notification happens when apps pause.
             l.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
-            l.getAppsView().getWorkManager().getWorkModeSwitch().performClick();
+            l.getAppsView().getWorkManager().getWorkUtilityView().performClick();
         });
 
         waitForLauncherCondition("Work profile toggle OFF failed", launcher -> {
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index e1bd686..512db39 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -29,6 +29,7 @@
 
 import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
 import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
+import com.android.launcher3.tapl.OverviewTask.TaskViewType;
 import com.android.launcher3.testing.shared.TestProtocol;
 
 import java.util.List;
@@ -121,12 +122,31 @@
                         if (mLauncher.isTablet()) {
                             List<UiObject2> tasks = mLauncher.getDevice().findObjects(
                                     TASK_SELECTOR);
+
                             final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
-                            mLauncher.assertTrue(
-                                    "Task(s) found to the right of the swiped task",
-                                    tasks.stream().allMatch(t ->
-                                            t.getVisibleBounds().right < centerX
-                                                    || t.getVisibleBounds().centerX() == centerX));
+                            UiObject2 centerTask = tasks.stream()
+                                    .filter(t -> t.getVisibleCenter().x == centerX)
+                                    .findFirst()
+                                    .orElse(null);
+
+                            if (centerTask != null) {
+                                mLauncher.assertTrue(
+                                        "Task(s) found to the right of the swiped task",
+                                        tasks.stream()
+                                                .filter(t -> t != centerTask
+                                                        && OverviewTask.getType(t)
+                                                        != TaskViewType.DESKTOP)
+                                                .allMatch(t -> t.getVisibleBounds().right
+                                                        < centerTask.getVisibleBounds().left));
+                                mLauncher.assertTrue(
+                                        "DesktopTask(s) found to the left of the swiped task",
+                                        tasks.stream()
+                                                .filter(t -> t != centerTask
+                                                        && OverviewTask.getType(t)
+                                                        == TaskViewType.DESKTOP)
+                                                .allMatch(t -> t.getVisibleBounds().left
+                                                        > centerTask.getVisibleBounds().right));
+                            }
                         }
 
                     }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 5fd4dac..8512d73 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -57,7 +57,7 @@
         mLauncher.assertNotNull("task must not be null", task);
         mTask = task;
         mOverview = overview;
-        mType = getType();
+        mType = getType(task);
         verifyActiveContainer();
     }
 
@@ -304,8 +304,12 @@
         return containsContentDescription(expected, DEFAULT);
     }
 
-    private TaskViewType getType() {
-        String resourceName = mTask.getResourceName();
+    /**
+     * Returns the TaskView type of the task. It will return whether the task is a single TaskView,
+     * a GroupedTaskView or a DesktopTaskView.
+     */
+    static TaskViewType getType(UiObject2 task) {
+        String resourceName = task.getResourceName();
         if (resourceName.endsWith("task_view_grouped")) {
             return TaskViewType.GROUPED;
         } else if (resourceName.endsWith("task_view_desktop")) {
@@ -345,7 +349,7 @@
         }
     }
 
-    private enum TaskViewType {
+    enum TaskViewType {
         SINGLE,
         GROUPED,
         DESKTOP