Merge "Fix two bugs with thumbnail screenshotting for split apps" into udc-qpr-dev
diff --git a/quickstep/protos_overrides/launcher_atom_extension.proto b/quickstep/protos_overrides/launcher_atom_extension.proto
index f5a277b..b3df353 100644
--- a/quickstep/protos_overrides/launcher_atom_extension.proto
+++ b/quickstep/protos_overrides/launcher_atom_extension.proto
@@ -61,6 +61,9 @@
 
       // User entered by tapping on QSB bar on homescreen.
       QSB = 2;
+
+      // User entered by swiping up from overview (using Rocket Gesture).
+      OVERVIEW = 3;
     }
   }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
index c9d331b..2517ff6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -41,10 +41,8 @@
     public static final int FLAG_AUTOHIDE_SUSPEND_TOUCHING = 1 << 2;
     // Taskbar EDU overlay is open above the Taskbar. */
     public static final int FLAG_AUTOHIDE_SUSPEND_EDU_OPEN = 1 << 3;
-    // Taskbar is in immersive mode in overview.
+    // Taskbar in immersive mode in overview
     public static final int FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER = 1 << 4;
-    // Transient Taskbar is temporarily unstashed (pending a timeout).
-    public static final int FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR = 1 << 5;
 
     @IntDef(flag = true, value = {
             FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
@@ -52,7 +50,6 @@
             FLAG_AUTOHIDE_SUSPEND_TOUCHING,
             FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
             FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
-            FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AutohideSuspendFlag {}
@@ -88,21 +85,18 @@
 
         boolean isSuspended = isSuspended();
         mSystemUiProxy.notifyTaskbarAutohideSuspend(isSuspended);
-        mActivity.onTransientAutohideSuspendFlagChanged(isTransientTaskbarStashingSuspended());
+        mActivity.onTransientAutohideSuspendFlagChanged(isSuspended);
     }
 
     /**
-     * Returns true iff taskbar autohide is currently suspended for immersive mode.
+     * Returns true iff taskbar autohide is currently suspended.
      */
-    private boolean isSuspended() {
+    public boolean isSuspended() {
         return mAutohideSuspendFlags != 0;
     }
 
-    /**
-     * Returns whether Transient Taskbar should avoid auto-stashing.
-     */
-    public boolean isTransientTaskbarStashingSuspended() {
-        return (mAutohideSuspendFlags & ~FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR) != 0;
+    public boolean isSuspendedForTransientTaskbarInOverview() {
+        return (mAutohideSuspendFlags & FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER) != 0;
     }
 
     @Override
@@ -121,8 +115,6 @@
         appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_EDU_OPEN, "FLAG_AUTOHIDE_SUSPEND_EDU_OPEN");
         appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
                 "FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER");
-        appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
-                "FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR");
         return str.toString();
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 90d42ec..3f2396b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -520,8 +520,10 @@
             return;
         }
 
-        if (stash && mControllers.taskbarAutohideSuspendController
-                .isTransientTaskbarStashingSuspended()) {
+        if (stash && mControllers.taskbarAutohideSuspendController.isSuspended()
+                && !mControllers.taskbarAutohideSuspendController
+                .isSuspendedForTransientTaskbarInOverview()) {
+            // Avoid stashing if autohide is currently suspended.
             return;
         }
 
@@ -1079,9 +1081,6 @@
             mActivity.getStatsLogManager().logger().log(hasAnyFlag(FLAG_STASHED_IN_APP_AUTO)
                     ? LAUNCHER_TRANSIENT_TASKBAR_HIDE
                     : LAUNCHER_TRANSIENT_TASKBAR_SHOW);
-            mControllers.taskbarAutohideSuspendController.updateFlag(
-                    TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
-                    !hasAnyFlag(FLAG_STASHED_IN_APP_AUTO));
         }
     }
 
@@ -1174,7 +1173,7 @@
     }
 
     private void onTaskbarTimeout(Alarm alarm) {
-        if (mControllers.taskbarAutohideSuspendController.isTransientTaskbarStashingSuspended()) {
+        if (mControllers.taskbarAutohideSuspendController.isSuspended()) {
             return;
         }
         updateAndAnimateTransientTaskbarForTimeout();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
index 39543b0..f7bef03 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -243,6 +243,7 @@
         } else {
             widgetView = new LauncherAppWidgetHostView(context);
         }
+        widgetView.setIsWidgetCachingDisabled(true);
         widgetView.setInteractionHandler(mInteractionHandler);
         widgetView.setAppWidget(appWidgetId, appWidget);
         mViews.put(appWidgetId, widgetView);
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index f25619d..2123253 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -810,6 +810,7 @@
         mAnimateCurrentTaskDismissal = false;
         mDismissingFromSplitPair = false;
         mSecondPendingIntent = null;
+        mFirstFloatingTaskView = null;
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index ea027bf..4d88a04 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -695,8 +695,6 @@
      */
     private int mSplitHiddenTaskViewIndex = -1;
     @Nullable
-    private FloatingTaskView mFirstFloatingTaskView;
-    @Nullable
     private FloatingTaskView mSecondFloatingTaskView;
 
     /**
@@ -3190,7 +3188,7 @@
                 AnimUtils.getDeviceOverviewToSplitTimings(mActivity.getDeviceProfile().isTablet);
 
         RectF startingTaskRect = new RectF();
-        safeRemoveDragLayerView(mFirstFloatingTaskView);
+        safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
         SplitAnimInitProps splitAnimInitProps =
                 mSplitSelectStateController.getSplitAnimationController().getFirstAnimInitViews(
                         () -> mSplitHiddenTaskView, () -> mSplitSelectSource);
@@ -3203,17 +3201,18 @@
                     timings.getIconFadeEndOffset()));
         }
 
-        mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
+        FloatingTaskView firstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
                 splitAnimInitProps.getOriginalView(),
                 splitAnimInitProps.getOriginalBitmap(),
                 splitAnimInitProps.getIconDrawable(), startingTaskRect);
-        mFirstFloatingTaskView.setAlpha(1);
-        mFirstFloatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
+        firstFloatingTaskView.setAlpha(1);
+        firstFloatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
                 splitAnimInitProps.getFadeWithThumbnail(), splitAnimInitProps.isStagedTask());
+        mSplitSelectStateController.setFirstFloatingTaskView(firstFloatingTaskView);
 
         // Allow user to click staged app to launch into fullscreen
         if (ENABLE_LAUNCH_FROM_STAGED_APP.get()) {
-            mFirstFloatingTaskView.setOnClickListener(this::animateToFullscreen);
+            firstFloatingTaskView.setOnClickListener(this::animateToFullscreen);
         }
 
         // SplitInstructionsView: animate in
@@ -4703,8 +4702,10 @@
                 mSplitSelectStateController.getActiveSplitStagePosition(), firstTaskEndingBounds,
                 secondTaskEndingBounds);
 
-        mFirstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
-        mFirstFloatingTaskView.addConfirmAnimation(pendingAnimation,
+        FloatingTaskView firstFloatingTaskView =
+                mSplitSelectStateController.getFirstFloatingTaskView();
+        firstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
+        firstFloatingTaskView.addConfirmAnimation(pendingAnimation,
                 new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
                 false /* fadeWithThumbnail */, true /* isStagedTask */);
 
@@ -4745,10 +4746,9 @@
     @SuppressLint("WrongCall")
     protected void resetFromSplitSelectionState() {
         if (mSplitSelectSource != null || mSplitHiddenTaskViewIndex != -1) {
-            safeRemoveDragLayerView(mFirstFloatingTaskView);
+            safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
             safeRemoveDragLayerView(mSecondFloatingTaskView);
             safeRemoveDragLayerView(mSplitInstructionsView);
-            mFirstFloatingTaskView = null;
             mSecondFloatingTaskView = null;
             mSplitInstructionsView = null;
             mSplitSelectSource = null;
@@ -4831,8 +4831,10 @@
                 mSplitPlaceholderInset, mActivity.getDeviceProfile(),
                 mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
         mTempRectF.set(mTempRect);
-        mFirstFloatingTaskView.updateOrientationHandler(mOrientationHandler);
-        mFirstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
+        FloatingTaskView firstFloatingTaskView =
+                mSplitSelectStateController.getFirstFloatingTaskView();
+        firstFloatingTaskView.updateOrientationHandler(mOrientationHandler);
+        firstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
 
         PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
         Pair<FloatProperty, FloatProperty> taskViewsFloat =
@@ -5954,7 +5956,7 @@
 
     @Nullable
     public FloatingTaskView getFirstFloatingTaskView() {
-        return mFirstFloatingTaskView;
+        return mSplitSelectStateController.getFirstFloatingTaskView();
     }
 
     @Nullable
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 083b4f8..3edda6b 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -117,12 +117,13 @@
             Utilities.enableRunningInTestHarnessForTests();
         }
 
-        final ViewCaptureRule viewCaptureRule = new ViewCaptureRule();
+        final ViewCaptureRule viewCaptureRule = new ViewCaptureRule(
+                RecentsActivity.ACTIVITY_TRACKER::getCreatedActivity);
         mOrderSensitiveRules = RuleChain
                 .outerRule(new SamplerRule())
                 .around(new NavigationModeSwitchRule(mLauncher))
-                .around(viewCaptureRule)
                 .around(new FailureWatcher(mDevice, mLauncher, viewCaptureRule.getViewCapture()))
+                .around(viewCaptureRule)
                 .around(new ViewCaptureAnalysisRule(viewCaptureRule.getViewCapture()));
 
         mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
diff --git a/res/color-night-v31/material_color_surface.xml b/res/color-night-v31/material_color_surface.xml
new file mode 100644
index 0000000..a645f24
--- /dev/null
+++ b/res/color-night-v31/material_color_surface.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="6" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_bright.xml b/res/color-night-v31/material_color_surface_bright.xml
new file mode 100644
index 0000000..f34ed6c
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_bright.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="24" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_container.xml b/res/color-night-v31/material_color_surface_container.xml
new file mode 100644
index 0000000..002b88e
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_container.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_container_high.xml b/res/color-night-v31/material_color_surface_container_high.xml
new file mode 100644
index 0000000..002b88e
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_container_high.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_container_highest.xml b/res/color-night-v31/material_color_surface_container_highest.xml
new file mode 100644
index 0000000..002b88e
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_container_highest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_container_low.xml b/res/color-night-v31/material_color_surface_container_low.xml
new file mode 100644
index 0000000..002b88e
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_container_low.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_container_lowest.xml b/res/color-night-v31/material_color_surface_container_lowest.xml
new file mode 100644
index 0000000..002b88e
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_container_lowest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_dim.xml b/res/color-night-v31/material_color_surface_dim.xml
new file mode 100644
index 0000000..a645f24
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_dim.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="6" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_inverse.xml b/res/color-night-v31/material_color_surface_inverse.xml
new file mode 100644
index 0000000..ac63072
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_inverse.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_variant.xml b/res/color-night-v31/material_color_surface_variant.xml
new file mode 100644
index 0000000..a645f24
--- /dev/null
+++ b/res/color-night-v31/material_color_surface_variant.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="6" />
+</selector>
\ No newline at end of file
diff --git a/res/color-night-v31/surface.xml b/res/color-night-v31/surface.xml
deleted file mode 100644
index fbc9e43..0000000
--- a/res/color-night-v31/surface.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2021, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<selector
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_800" />
-</selector>
diff --git a/res/color-v31/material_color_surface.xml b/res/color-v31/material_color_surface.xml
new file mode 100644
index 0000000..b049851
--- /dev/null
+++ b/res/color-v31/material_color_surface.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_bright.xml b/res/color-v31/material_color_surface_bright.xml
new file mode 100644
index 0000000..b049851
--- /dev/null
+++ b/res/color-v31/material_color_surface_bright.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container.xml b/res/color-v31/material_color_surface_container.xml
new file mode 100644
index 0000000..b031c08
--- /dev/null
+++ b/res/color-v31/material_color_surface_container.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_high.xml b/res/color-v31/material_color_surface_container_high.xml
new file mode 100644
index 0000000..b031c08
--- /dev/null
+++ b/res/color-v31/material_color_surface_container_high.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_highest.xml b/res/color-v31/material_color_surface_container_highest.xml
new file mode 100644
index 0000000..b031c08
--- /dev/null
+++ b/res/color-v31/material_color_surface_container_highest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_low.xml b/res/color-v31/material_color_surface_container_low.xml
new file mode 100644
index 0000000..b031c08
--- /dev/null
+++ b/res/color-v31/material_color_surface_container_low.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_lowest.xml b/res/color-v31/material_color_surface_container_lowest.xml
new file mode 100644
index 0000000..674fc73
--- /dev/null
+++ b/res/color-v31/material_color_surface_container_lowest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_dim.xml b/res/color-v31/material_color_surface_dim.xml
new file mode 100644
index 0000000..e2d226f
--- /dev/null
+++ b/res/color-v31/material_color_surface_dim.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="87" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_inverse.xml b/res/color-v31/material_color_surface_inverse.xml
new file mode 100644
index 0000000..e189862
--- /dev/null
+++ b/res/color-v31/material_color_surface_inverse.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="6" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_variant.xml b/res/color-v31/material_color_surface_variant.xml
new file mode 100644
index 0000000..e2d226f
--- /dev/null
+++ b/res/color-v31/material_color_surface_variant.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="87" />
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/surface.xml b/res/color-v31/surface.xml
index 30f3032..da4571a 100644
--- a/res/color-v31/surface.xml
+++ b/res/color-v31/surface.xml
@@ -19,5 +19,6 @@
 -->
 <selector
     xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="98"/>
+    <item android:color="?attr/materialColorSurfaceContainerHighest"/>
 </selector>
+
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 55dd1de..9868e20 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -19,6 +19,7 @@
     android:layout_height="wrap_content"
     android:paddingHorizontal="@dimen/widget_cell_horizontal_padding"
     android:paddingVertical="@dimen/widget_cell_vertical_padding"
+    android:layout_marginHorizontal="@dimen/widget_cell_horizontal_padding"
     android:layout_weight="1"
     android:orientation="vertical"
     android:focusable="true"
diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml
index 3453668..e462ae0 100644
--- a/res/values-night-v31/colors.xml
+++ b/res/values-night-v31/colors.xml
@@ -51,4 +51,39 @@
         @android:color/system_accent1_200</color>
     <color name="work_fab_icon_color">
         @android:color/system_accent1_900</color>
+
+    <color name="material_color_on_secondary_fixed_variant">@android:color/system_accent2_700</color>
+    <color name="material_color_on_tertiary_fixed_variant">@android:color/system_accent3_700</color>
+    <color name="material_color_on_primary_fixed_variant">@android:color/system_accent1_700</color>
+    <color name="material_color_on_secondary_container">@android:color/system_accent2_100</color>
+    <color name="material_color_on_tertiary_container">@android:color/system_accent3_100</color>
+    <color name="material_color_on_primary_container">@android:color/system_accent1_100</color>
+    <color name="material_color_secondary_fixed_dim">@android:color/system_accent2_200</color>
+    <color name="material_color_on_error_container">#FFDAD5</color>
+    <color name="material_color_on_secondary_fixed">@android:color/system_accent2_900</color>
+    <color name="material_color_on_surface_inverse">@android:color/system_neutral1_900</color>
+    <color name="material_color_tertiary_fixed_dim">@android:color/system_accent3_200</color>
+    <color name="material_color_on_tertiary_fixed">@android:color/system_accent3_900</color>
+    <color name="material_color_primary_fixed_dim">@android:color/system_accent1_200</color>
+    <color name="material_color_secondary_container">@android:color/system_accent2_700</color>
+    <color name="material_color_error_container">#930001</color>
+    <color name="material_color_on_primary_fixed">@android:color/system_accent1_900</color>
+    <color name="material_color_primary_inverse">@android:color/system_accent1_600</color>
+    <color name="material_color_secondary_fixed">@android:color/system_accent2_100</color>
+    <color name="material_color_tertiary_container">@android:color/system_accent3_700</color>
+    <color name="material_color_tertiary_fixed">@android:color/system_accent3_100</color>
+    <color name="material_color_primary_container">@android:color/system_accent1_700</color>
+    <color name="material_color_on_background">@android:color/system_neutral1_800</color>
+    <color name="material_color_primary_fixed">@android:color/system_accent1_100</color>
+    <color name="material_color_on_secondary">@android:color/system_accent2_800</color>
+    <color name="material_color_on_tertiary">@android:color/system_accent3_800</color>
+    <color name="material_color_on_error">#690001</color>
+    <color name="material_color_on_surface_variant">@android:color/system_neutral2_200</color>
+    <color name="material_color_outline">@android:color/system_neutral2_400</color>
+    <color name="material_color_outline_variant">@android:color/system_neutral2_700</color>
+    <color name="material_color_on_primary">@android:color/system_accent1_800</color>
+    <color name="material_color_on_surface">@android:color/system_neutral1_100</color>
+    <color name="material_color_primary">@android:color/system_accent1_200</color>
+    <color name="material_color_secondary">@android:color/system_accent2_200</color>
+    <color name="material_color_tertiary">@android:color/system_accent3_200</color>
 </resources>
\ No newline at end of file
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
new file mode 100644
index 0000000..95b3a63
--- /dev/null
+++ b/res/values-night/colors.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <color name="material_color_on_secondary_fixed_variant">#3F4759</color>
+    <color name="material_color_on_tertiary_fixed_variant">#583E5B</color>
+    <color name="material_color_surface_container_lowest">#0D0E11</color>
+    <color name="material_color_on_primary_fixed_variant">#2B4678</color>
+    <color name="material_color_on_secondary_container">#DBE2F9</color>
+    <color name="material_color_on_tertiary_container">#FBD7FC</color>
+    <color name="material_color_surface_container_low">#1B1B1F</color>
+    <color name="material_color_on_primary_container">#D8E2FF</color>
+    <color name="material_color_secondary_fixed_dim">#BFC6DC</color>
+    <color name="material_color_on_error_container">#FFDAD5</color>
+    <color name="material_color_on_secondary_fixed">#141B2C</color>
+    <color name="material_color_on_surface_inverse">#1B1B1F</color>
+    <color name="material_color_tertiary_fixed_dim">#DEBCDF</color>
+    <color name="material_color_on_tertiary_fixed">#29132D</color>
+    <color name="material_color_primary_fixed_dim">#ADC6FF</color>
+    <color name="material_color_secondary_container">#3F4759</color>
+    <color name="material_color_error_container">#930001</color>
+    <color name="material_color_on_primary_fixed">#001A41</color>
+    <color name="material_color_primary_inverse">#445E91</color>
+    <color name="material_color_secondary_fixed">#DBE2F9</color>
+    <color name="material_color_surface_inverse">#FAF9FD</color>
+    <color name="material_color_surface_variant">#44474F</color>
+    <color name="material_color_tertiary_container">#583E5B</color>
+    <color name="material_color_tertiary_fixed">#FBD7FC</color>
+    <color name="material_color_primary_container">#2B4678</color>
+    <color name="material_color_on_background">#E3E2E6</color>
+    <color name="material_color_primary_fixed">#D8E2FF</color>
+    <color name="material_color_on_secondary">#293041</color>
+    <color name="material_color_on_tertiary">#402843</color>
+    <color name="material_color_surface_dim">#121316</color>
+    <color name="material_color_surface_bright">#38393C</color>
+    <color name="material_color_on_error">#690001</color>
+    <color name="material_color_surface">#121316</color>
+    <color name="material_color_surface_container_high">#292A2D</color>
+    <color name="material_color_surface_container_highest">#343538</color>
+    <color name="material_color_on_surface_variant">#C4C6D0</color>
+    <color name="material_color_outline">#72747D</color>
+    <color name="material_color_outline_variant">#444746</color>
+    <color name="material_color_on_primary">#102F60</color>
+    <color name="material_color_on_surface">#E3E2E6</color>
+    <color name="material_color_surface_container">#1F1F23</color>
+    <color name="material_color_primary">#ADC6FF</color>
+    <color name="material_color_secondary">#BFC6DC</color>
+    <color name="material_color_tertiary">#DEBCDF</color>
+</resources>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 4ffff57..841e07b 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -102,4 +102,40 @@
         @android:color/system_accent1_200</color>
     <color name="work_fab_icon_color">
         @android:color/system_accent1_900</color>
+
+
+    <color name="material_color_on_secondary_fixed_variant">@android:color/system_accent2_700</color>
+    <color name="material_color_on_tertiary_fixed_variant">@android:color/system_accent3_700</color>
+    <color name="material_color_on_primary_fixed_variant">@android:color/system_accent1_700</color>
+    <color name="material_color_on_secondary_container">@android:color/system_accent2_900</color>
+    <color name="material_color_on_tertiary_container">@android:color/system_accent3_900</color>
+    <color name="material_color_on_primary_container">@android:color/system_accent1_900</color>
+    <color name="material_color_secondary_fixed_dim">@android:color/system_accent2_200</color>
+    <color name="material_color_on_error_container">#410000</color>
+    <color name="material_color_on_secondary_fixed">@android:color/system_accent2_900</color>
+    <color name="material_color_on_surface_inverse">@android:color/system_neutral1_100</color>
+    <color name="material_color_tertiary_fixed_dim">@android:color/system_accent3_200</color>
+    <color name="material_color_on_tertiary_fixed">@android:color/system_accent3_900</color>
+    <color name="material_color_primary_fixed_dim">@android:color/system_accent1_200</color>
+    <color name="material_color_secondary_container">@android:color/system_accent2_100</color>
+    <color name="material_color_error_container">#FFDAD5</color>
+    <color name="material_color_on_primary_fixed">@android:color/system_accent1_900</color>
+    <color name="material_color_primary_inverse">@android:color/system_accent1_200</color>
+    <color name="material_color_secondary_fixed">@android:color/system_accent2_100</color>
+    <color name="material_color_tertiary_container">@android:color/system_accent3_100</color>
+    <color name="material_color_tertiary_fixed">@android:color/system_accent3_100</color>
+    <color name="material_color_primary_container">@android:color/system_accent1_100</color>
+    <color name="material_color_on_background">@android:color/system_neutral1_50</color>
+    <color name="material_color_primary_fixed">@android:color/system_accent1_100</color>
+    <color name="material_color_on_secondary">@android:color/system_accent2_0</color>
+    <color name="material_color_on_tertiary">@android:color/system_accent3_0</color>
+    <color name="material_color_on_error">#FFFFFF</color>
+    <color name="material_color_on_surface_variant">@android:color/system_neutral2_700</color>
+    <color name="material_color_outline">@android:color/system_neutral2_500</color>
+    <color name="material_color_outline_variant">@android:color/system_neutral2_200</color>
+    <color name="material_color_on_primary">@android:color/system_accent1_0</color>
+    <color name="material_color_on_surface">@android:color/system_neutral1_900</color>
+    <color name="material_color_primary">@android:color/system_accent1_600</color>
+    <color name="material_color_secondary">@android:color/system_accent2_600</color>
+    <color name="material_color_tertiary">@android:color/system_accent3_600</color>
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 1be1a1a..1aab8de 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -257,6 +257,7 @@
         <attr name="ofAvailableSpace" format="float" />
         <attr name="ofRemainderSpace" format="float" />
         <attr name="matchWorkspace" format="boolean" />
+        <attr name="maxSize" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="FolderSpec">
@@ -264,6 +265,11 @@
         <attr name="maxAvailableSize" />
     </declare-styleable>
 
+    <declare-styleable name="AllAppsSpec">
+        <attr name="specType" />
+        <attr name="maxAvailableSize" />
+    </declare-styleable>
+
     <declare-styleable name="ProfileDisplayOption">
         <attr name="name" />
         <attr name="minWidthDps" format="float" />
@@ -512,6 +518,51 @@
         <attr name="appIconSize" format="dimension" />
     </declare-styleable>
 
+    <attr name="materialColorOnSecondaryFixedVariant" format="color" />
+    <attr name="materialColorOnTertiaryFixedVariant" format="color" />
+    <attr name="materialColorSurfaceContainerLowest" format="color" />
+    <attr name="materialColorOnPrimaryFixedVariant" format="color" />
+    <attr name="materialColorOnSecondaryContainer" format="color" />
+    <attr name="materialColorOnTertiaryContainer" format="color" />
+    <attr name="materialColorSurfaceContainerLow" format="color" />
+    <attr name="materialColorOnPrimaryContainer" format="color" />
+    <attr name="materialColorSecondaryFixedDim" format="color" />
+    <attr name="materialColorOnErrorContainer" format="color" />
+    <attr name="materialColorOnSecondaryFixed" format="color" />
+    <attr name="materialColorOnSurfaceInverse" format="color" />
+    <attr name="materialColorTertiaryFixedDim" format="color" />
+    <attr name="materialColorOnTertiaryFixed" format="color" />
+    <attr name="materialColorPrimaryFixedDim" format="color" />
+    <attr name="materialColorSecondaryContainer" format="color" />
+    <attr name="materialColorErrorContainer" format="color" />
+    <attr name="materialColorOnPrimaryFixed" format="color" />
+    <attr name="materialColorPrimaryInverse" format="color" />
+    <attr name="materialColorSecondaryFixed" format="color" />
+    <attr name="materialColorTertiaryContainer" format="color" />
+    <attr name="materialColorTertiaryFixed" format="color" />
+    <attr name="materialColorPrimaryContainer" format="color" />
+    <attr name="materialColorOnBackground" format="color" />
+    <attr name="materialColorPrimaryFixed" format="color" />
+    <attr name="materialColorOnSecondary" format="color" />
+    <attr name="materialColorOnTertiary" format="color" />
+    <attr name="materialColorOnError" format="color" />
+    <attr name="materialColorOnSurfaceVariant" format="color" />
+    <attr name="materialColorOutline" format="color" />
+    <attr name="materialColorOutlineVariant" format="color" />
+    <attr name="materialColorOnPrimary" format="color" />
+    <attr name="materialColorOnSurface" format="color" />
+    <attr name="materialColorPrimary" format="color" />
+    <attr name="materialColorSecondary" format="color" />
+    <attr name="materialColorTertiary" format="color" />
+    <attr name="materialColorSurfaceInverse" format="color" />
+    <attr name="materialColorSurfaceVariant" format="color" />
+    <attr name="materialColorSurfaceDim" format="color" />
+    <attr name="materialColorSurfaceBright" format="color" />
+    <attr name="materialColorSurface" format="color" />
+    <attr name="materialColorSurfaceContainerHigh" format="color" />
+    <attr name="materialColorSurfaceContainerHighest" format="color" />
+    <attr name="materialColorSurfaceContainer" format="color" />
+
     <declare-styleable name="WidgetSections">
         <!-- Component name of an app widget provider. -->
         <attr name="provider" format="string" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index ad7a10b..6c3b54c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -128,4 +128,49 @@
     <color name="widget_picker_selected_tab_text_color_dark">#2D312F</color>
     <color name="widget_picker_unselected_tab_text_color_dark">#C4C7C5</color>
     <color name="widget_picker_collapse_handle_color_dark">#444746</color>
+
+    <color name="material_color_on_secondary_fixed_variant">#3F4759</color>
+    <color name="material_color_on_tertiary_fixed_variant">#583E5B</color>
+    <color name="material_color_surface_container_lowest">#FFFFFF</color>
+    <color name="material_color_on_primary_fixed_variant">#2B4678</color>
+    <color name="material_color_on_secondary_container">#141B2C</color>
+    <color name="material_color_on_tertiary_container">#29132D</color>
+    <color name="material_color_surface_container_low">#F5F3F7</color>
+    <color name="material_color_on_primary_container">#001A41</color>
+    <color name="material_color_secondary_fixed_dim">#BFC6DC</color>
+    <color name="material_color_on_error_container">#410000</color>
+    <color name="material_color_on_secondary_fixed">#141B2C</color>
+    <color name="material_color_on_surface_inverse">#E3E2E6</color>
+    <color name="material_color_tertiary_fixed_dim">#DEBCDF</color>
+    <color name="material_color_on_tertiary_fixed">#29132D</color>
+    <color name="material_color_primary_fixed_dim">#ADC6FF</color>
+    <color name="material_color_secondary_container">#DBE2F9</color>
+    <color name="material_color_error_container">#FFDAD5</color>
+    <color name="material_color_on_primary_fixed">#001A41</color>
+    <color name="material_color_primary_inverse">#ADC6FF</color>
+    <color name="material_color_secondary_fixed">#DBE2F9</color>
+    <color name="material_color_surface_inverse">#121316</color>
+    <color name="material_color_surface_variant">#E1E2EC</color>
+    <color name="material_color_tertiary_container">#FBD7FC</color>
+    <color name="material_color_tertiary_fixed">#FBD7FC</color>
+    <color name="material_color_primary_container">#D8E2FF</color>
+    <color name="material_color_on_background">#1B1B1F</color>
+    <color name="material_color_primary_fixed">#D8E2FF</color>
+    <color name="material_color_on_secondary">#FFFFFF</color>
+    <color name="material_color_on_tertiary">#FFFFFF</color>
+    <color name="material_color_surface_dim">#DBD9DD</color>
+    <color name="material_color_surface_bright">#FAF9FD</color>
+    <color name="material_color_on_error">#FFFFFF</color>
+    <color name="material_color_surface">#FAF9FD</color>
+    <color name="material_color_surface_container_high">#E9E7EC</color>
+    <color name="material_color_surface_container_highest">#E3E2E6</color>
+    <color name="material_color_on_surface_variant">#44474F</color>
+    <color name="material_color_outline">#72747D</color>
+    <color name="material_color_outline_variant">#C4C7C5</color>
+    <color name="material_color_on_primary">#FFFFFF</color>
+    <color name="material_color_on_surface">#1B1B1F</color>
+    <color name="material_color_surface_container">#EFEDF1</color>
+    <color name="material_color_primary">#445E91</color>
+    <color name="material_color_secondary">#575E71</color>
+    <color name="material_color_tertiary">#715573</color>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ecff9ec..14454bd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -31,7 +31,7 @@
 
     <style name="LauncherTheme" parent="@style/BaseLauncherTheme">
         <item name="android:textColorSecondary">#DE000000</item>
-        <item name="allAppsScrimColor">?android:attr/colorBackgroundFloating</item>
+        <item name="allAppsScrimColor">?attr/materialColorSurfaceDim</item>
         <item name="allappsHeaderProtectionColor">@color/popup_color_tertiary_light</item>
         <item name="allAppsNavBarScrimColor">#66FFFFFF</item>
         <item name="popupColorPrimary">@color/popup_color_primary_light</item>
@@ -74,6 +74,51 @@
         <item name="android:statusBarColor">#00000000</item>
         <item name="android:navigationBarColor">#00000000</item>
         <item name="android:switchStyle">@style/SwitchStyle</item>
+
+        <item name="materialColorOnSecondaryFixedVariant">@color/material_color_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/material_color_on_tertiary_fixed_variant</item>
+        <item name="materialColorSurfaceContainerLowest">@color/material_color_surface_container_lowest</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/material_color_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryContainer">@color/material_color_on_secondary_container</item>
+        <item name="materialColorOnTertiaryContainer">@color/material_color_on_tertiary_container</item>
+        <item name="materialColorSurfaceContainerLow">@color/material_color_surface_container_low</item>
+        <item name="materialColorOnPrimaryContainer">@color/material_color_on_primary_container</item>
+        <item name="materialColorSecondaryFixedDim">@color/material_color_secondary_fixed_dim</item>
+        <item name="materialColorOnErrorContainer">@color/material_color_on_error_container</item>
+        <item name="materialColorOnSecondaryFixed">@color/material_color_on_secondary_fixed</item>
+        <item name="materialColorOnSurfaceInverse">@color/material_color_on_surface_inverse</item>
+        <item name="materialColorTertiaryFixedDim">@color/material_color_tertiary_fixed_dim</item>
+        <item name="materialColorOnTertiaryFixed">@color/material_color_on_tertiary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/material_color_primary_fixed_dim</item>
+        <item name="materialColorSecondaryContainer">@color/material_color_secondary_container</item>
+        <item name="materialColorErrorContainer">@color/material_color_error_container</item>
+        <item name="materialColorOnPrimaryFixed">@color/material_color_on_primary_fixed</item>
+        <item name="materialColorPrimaryInverse">@color/material_color_primary_inverse</item>
+        <item name="materialColorSecondaryFixed">@color/material_color_secondary_fixed</item>
+        <item name="materialColorSurfaceInverse">@color/material_color_surface_inverse</item>
+        <item name="materialColorSurfaceVariant">@color/material_color_surface_variant</item>
+        <item name="materialColorTertiaryContainer">@color/material_color_tertiary_container</item>
+        <item name="materialColorTertiaryFixed">@color/material_color_tertiary_fixed</item>
+        <item name="materialColorPrimaryContainer">@color/material_color_primary_container</item>
+        <item name="materialColorOnBackground">@color/material_color_on_background</item>
+        <item name="materialColorPrimaryFixed">@color/material_color_primary_fixed</item>
+        <item name="materialColorOnSecondary">@color/material_color_on_secondary</item>
+        <item name="materialColorOnTertiary">@color/material_color_on_tertiary</item>
+        <item name="materialColorSurfaceDim">@color/material_color_surface_dim</item>
+        <item name="materialColorSurfaceBright">@color/material_color_surface_bright</item>
+        <item name="materialColorOnError">@color/material_color_on_error</item>
+        <item name="materialColorSurface">@color/material_color_surface</item>
+        <item name="materialColorSurfaceContainerHigh">@color/material_color_surface_container_high</item>
+        <item name="materialColorSurfaceContainerHighest">@color/material_color_surface_container_highest</item>
+        <item name="materialColorOnSurfaceVariant">@color/material_color_on_surface_variant</item>
+        <item name="materialColorOutline">@color/material_color_outline</item>
+        <item name="materialColorOutlineVariant">@color/material_color_outline_variant</item>
+        <item name="materialColorOnPrimary">@color/material_color_on_primary</item>
+        <item name="materialColorOnSurface">@color/material_color_on_surface</item>
+        <item name="materialColorSurfaceContainer">@color/material_color_surface_container</item>
+        <item name="materialColorPrimary">@color/material_color_primary</item>
+        <item name="materialColorSecondary">@color/material_color_secondary</item>
+        <item name="materialColorTertiary">@color/material_color_tertiary</item>
     </style>
 
     <style name="SwitchStyle"
@@ -103,7 +148,7 @@
         <item name="android:textColorHint">#A0FFFFFF</item>
         <item name="android:colorControlHighlight">#19FFFFFF</item>
         <item name="android:colorPrimary">#FF212121</item>
-        <item name="allAppsScrimColor">?android:attr/colorBackgroundFloating</item>
+        <item name="allAppsScrimColor">?attr/materialColorSurfaceDim</item>
         <item name="allAppsNavBarScrimColor">#80000000</item>
         <item name="popupColorPrimary">@color/popup_color_primary_dark</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 7131452..9a1ccd0 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -360,37 +360,6 @@
             lp.y = sTmpRect.top;
         }
 
-        // Handle invalid resize across CellLayouts in the two panel UI.
-        if (mCellLayout.getParent() instanceof Workspace) {
-            Workspace<?> workspace = (Workspace<?>) mCellLayout.getParent();
-            CellLayout pairedCellLayout = workspace.getScreenPair(mCellLayout);
-            if (pairedCellLayout != null) {
-                Rect focusedCellLayoutBound = sTmpRect;
-                mDragLayerRelativeCoordinateHelper.viewToRect(mCellLayout, focusedCellLayoutBound);
-                Rect resizeFrameBound = sTmpRect2;
-                findViewById(R.id.widget_resize_frame).getGlobalVisibleRect(resizeFrameBound);
-                float progress = 1f;
-                if (workspace.indexOfChild(pairedCellLayout) < workspace.indexOfChild(mCellLayout)
-                        && mDeltaX < 0
-                        && resizeFrameBound.left < focusedCellLayoutBound.left) {
-                    // Resize from right to left.
-                    progress = (mDragAcrossTwoPanelOpacityMargin + mDeltaX)
-                            / mDragAcrossTwoPanelOpacityMargin;
-                } else if (workspace.indexOfChild(pairedCellLayout)
-                                > workspace.indexOfChild(mCellLayout)
-                        && mDeltaX > 0
-                        && resizeFrameBound.right > focusedCellLayoutBound.right) {
-                    // Resize from left to right.
-                    progress = (mDragAcrossTwoPanelOpacityMargin - mDeltaX)
-                            / mDragAcrossTwoPanelOpacityMargin;
-                }
-                float alpha = Math.max(MIN_OPACITY_FOR_CELL_LAYOUT_DURING_INVALID_RESIZE, progress);
-                float springLoadedProgress = Math.min(1f, 1f - progress);
-                updateInvalidResizeEffect(mCellLayout, pairedCellLayout, alpha,
-                        springLoadedProgress);
-            }
-        }
-
         requestLayout();
     }
 
@@ -547,13 +516,6 @@
         }
 
         final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
-        final CellLayout pairedCellLayout;
-        if (mCellLayout.getParent() instanceof Workspace) {
-            Workspace<?> workspace = (Workspace<?>) mCellLayout.getParent();
-            pairedCellLayout = workspace.getScreenPair(mCellLayout);
-        } else {
-            pairedCellLayout = null;
-        }
         if (!animate) {
             lp.width = newWidth;
             lp.height = newHeight;
@@ -562,10 +524,6 @@
             for (int i = 0; i < HANDLE_COUNT; i++) {
                 mDragHandles[i].setAlpha(1f);
             }
-            if (pairedCellLayout != null) {
-                updateInvalidResizeEffect(mCellLayout, pairedCellLayout, /* alpha= */ 1f,
-                        /* springLoadedProgress= */ 0f);
-            }
             requestLayout();
         } else {
             ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp,
@@ -581,10 +539,6 @@
                 set.play(mFirstFrameAnimatorHelper.addTo(
                         ObjectAnimator.ofFloat(mDragHandles[i], ALPHA, 1f)));
             }
-            if (pairedCellLayout != null) {
-                updateInvalidResizeEffect(mCellLayout, pairedCellLayout, /* alpha= */ 1f,
-                        /* springLoadedProgress= */ 0f, /* animatorSet= */ set);
-            }
             set.setDuration(SNAP_DURATION);
             set.start();
         }
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 376f54d..7eb085a 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.LauncherPrefs.GRID_NAME;
 import static com.android.launcher3.Utilities.dpiFromPx;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
 import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
 import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
@@ -302,7 +301,7 @@
         int type = displayInfo.supportedBounds.stream()
                 .mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
                 .reduce(0, (a, b) -> a | b);
-        if ((type == (flagPhone | flagTablet)) && ENABLE_TWO_PANEL_HOME.get()) {
+        if ((type == (flagPhone | flagTablet))) {
             // device has profiles supporting both phone and table modes
             return TYPE_MULTI_DISPLAY;
         } else if (type == flagTablet) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index caf5755..bf375d7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -44,7 +44,6 @@
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
-import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
 import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
 import static com.android.launcher3.config.FeatureFlags.SHOW_DOT_PAGINATION;
 import static com.android.launcher3.logging.StatsLogManager.EventEnum;
@@ -760,7 +759,7 @@
         }
 
         onDeviceProfileInitiated();
-        if (FOLDABLE_SINGLE_PAGE.get() && mDeviceProfile.isTwoPanels) {
+        if (mDeviceProfile.isTwoPanels) {
             mCellPosMapper = new TwoPanelCellPosMapper(mDeviceProfile.inv.numColumns);
         } else {
             mCellPosMapper = CellPosMapper.DEFAULT;
@@ -3045,6 +3044,7 @@
     @Override
     public void bindStringCache(StringCache cache) {
         mStringCache = cache;
+        mAppsView.updateWorkUI();
     }
 
     @Override
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index adaf20f..b141e18 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -28,7 +28,6 @@
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
 import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
-import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
@@ -127,7 +126,6 @@
 import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
 
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -503,20 +501,15 @@
                 .log(LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED);
     }
 
-    private boolean isTwoPanelEnabled() {
-        return !FOLDABLE_SINGLE_PAGE.get() && mLauncher.mDeviceProfile.isTwoPanels;
-    }
-
-    @Override
-    public int getPanelCount() {
-        return isTwoPanelEnabled() ? 2 : super.getPanelCount();
-    }
-
     public void deferRemoveExtraEmptyScreen() {
         mDeferRemoveExtraEmptyScreen = true;
     }
 
     @Override
+    public int getPanelCount() {
+        return super.getPanelCount();
+    }
+    @Override
     public void onDragEnd() {
         if (ENFORCE_DRAG_EVENT_ORDER) {
             enforceDragParity("onDragEnd", 0, 0);
@@ -668,7 +661,7 @@
         // created CellLayout.
         DeviceProfile dp = mLauncher.getDeviceProfile();
         CellLayout newScreen;
-        if (FOLDABLE_SINGLE_PAGE.get() && dp.isTwoPanels) {
+        if (dp.isTwoPanels) {
             newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
                     R.layout.workspace_screen_foldable, this, false /* attachToRoot */);
         } else {
@@ -693,15 +686,6 @@
 
         if (mDragSourceInternal != null) {
             int dragSourceChildCount = mDragSourceInternal.getChildCount();
-
-            // If the icon was dragged from Hotseat, there is no page pair
-            if (isTwoPanelEnabled() && !(mDragSourceInternal.getParent() instanceof Hotseat)) {
-                int pagePairScreenId = getScreenPair(getCellPosMapper().mapModelToPresenter(
-                        dragObject.dragInfo).screenId);
-                CellLayout pagePair = mWorkspaceScreens.get(pagePairScreenId);
-                dragSourceChildCount += pagePair.getShortcutsAndWidgets().getChildCount();
-            }
-
             // When the drag view content is a LauncherAppWidgetHostView, we should increment the
             // drag source child count by 1 because the widget in drag has been detached from its
             // original parent, ShortcutAndWidgetContainer, and reattached to the DragView.
@@ -712,11 +696,6 @@
             if (dragSourceChildCount == 1) {
                 lastChildOnScreen = true;
             }
-            CellLayout cl = (CellLayout) mDragSourceInternal.getParent();
-            if (!FOLDABLE_SINGLE_PAGE.get() && getLeftmostVisiblePageForIndex(indexOfChild(cl))
-                    == getLeftmostVisiblePageForIndex(getPageCount() - 1)) {
-                childOnFinalScreen = true;
-            }
         }
 
         // If this is the last item on the final screen
@@ -751,9 +730,6 @@
      */
     private void forEachExtraEmptyPageId(Consumer<Integer> callback) {
         callback.accept(EXTRA_EMPTY_SCREEN_ID);
-        if (isTwoPanelEnabled()) {
-            callback.accept(EXTRA_EMPTY_SCREEN_SECOND_ID);
-        }
     }
 
     /**
@@ -867,9 +843,7 @@
 
     public boolean hasExtraEmptyScreens() {
         return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)
-                && getChildCount() > getPanelCount()
-                && (!isTwoPanelEnabled()
-                || mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_SECOND_ID));
+                && getChildCount() > getPanelCount();
     }
 
     /**
@@ -975,14 +949,7 @@
      */
     @Nullable
     public CellLayout getScreenPair(CellLayout cellLayout) {
-        if (!isTwoPanelEnabled()) {
-            return null;
-        }
-        int screenId = getIdForScreen(cellLayout);
-        if (screenId == -1) {
-            return null;
-        }
-        return getScreenWithId(getScreenPair(screenId));
+        return null;
     }
 
     public void stripEmptyScreens() {
@@ -1010,22 +977,6 @@
             }
         }
 
-        // When two panel home is enabled we only remove an empty page if both visible pages are
-        // empty.
-        if (isTwoPanelEnabled()) {
-            // We go through all the pages that were marked as removable and check their page pair
-            Iterator<Integer> removeScreensIterator = removeScreens.iterator();
-            while (removeScreensIterator.hasNext()) {
-                int pageToRemove = removeScreensIterator.next();
-                int pagePair = getScreenPair(pageToRemove);
-                if (!removeScreens.contains(pagePair)) {
-                    // The page pair isn't empty so we want to remove the current page from the
-                    // removable pages' collection
-                    removeScreensIterator.remove();
-                }
-            }
-        }
-
         // We enforce at least one page (two pages on two panel home) to add new items to.
         // In the case that we remove the last such screen(s), we convert the last screen(s)
         // to the empty screen(s)
@@ -1046,12 +997,7 @@
                 removeView(cl);
             } else {
                 // The last page(s) should be converted into extra empty page(s)
-                int extraScreenId = isTwoPanelEnabled() && id % 2 == 1
-                        // This is the right panel in a two panel scenario
-                        ? EXTRA_EMPTY_SCREEN_SECOND_ID
-                        // This is either the last screen in a one panel scenario, or the left panel
-                        // in a two panel scenario when there are only two empty pages left
-                        : EXTRA_EMPTY_SCREEN_ID;
+                int extraScreenId = EXTRA_EMPTY_SCREEN_ID;
                 mWorkspaceScreens.put(extraScreenId, cl);
                 mScreenOrder.add(extraScreenId);
             }
@@ -2572,8 +2518,7 @@
         // Go through the pages and check if the dragged item is inside one of them. This block
         // is responsible for determining whether we need to snap to a different screen.
         int nextPage = getNextPage();
-        IntSet pageIndexesToVerify = IntSet.wrap(nextPage - 1,
-                nextPage + (isTwoPanelEnabled() ? 2 : 1));
+        IntSet pageIndexesToVerify = IntSet.wrap(nextPage - 1, nextPage + 1);
 
         for (int pageIndex : pageIndexesToVerify) {
             // When deciding whether to perform a page switch, we need to consider the most
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 183b268..4590125 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -16,6 +16,8 @@
 package com.android.launcher3.allapps;
 
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
@@ -77,6 +79,7 @@
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
@@ -1167,6 +1170,30 @@
         return view.getGlobalVisibleRect(new Rect());
     }
 
+    /** Called in Launcher#bindStringCache() to update the UI when cache is updated. */
+    public void updateWorkUI() {
+        setDeviceManagementResources();
+        if (mWorkManager.getWorkModeSwitch() != null) {
+            mWorkManager.getWorkModeSwitch().updateStringFromCache();
+        }
+        inflateWorkCardsIfNeeded();
+    }
+
+    private void inflateWorkCardsIfNeeded() {
+        AllAppsRecyclerView workRV = mAH.get(AdapterHolder.WORK).mRecyclerView;
+        if (workRV != null) {
+            for (int i = 0; i < workRV.getChildCount(); i++) {
+                View currentView  = workRV.getChildAt(i);
+                int currentItemViewType = workRV.getChildViewHolder(currentView).getItemViewType();
+                if (currentItemViewType == VIEW_TYPE_WORK_EDU_CARD) {
+                    ((WorkEduCard) currentView).updateStringFromCache();
+                } else if (currentItemViewType == VIEW_TYPE_WORK_DISABLED_CARD) {
+                    ((WorkPausedCard) currentView).updateStringFromCache();
+                }
+            }
+        }
+    }
+
     @VisibleForTesting
     public boolean isPersonalTabVisible() {
         return isDescendantViewVisible(R.id.tab_personal);
diff --git a/src/com/android/launcher3/allapps/WorkEduCard.java b/src/com/android/launcher3/allapps/WorkEduCard.java
index b4cdc96..1059097 100644
--- a/src/com/android/launcher3/allapps/WorkEduCard.java
+++ b/src/com/android/launcher3/allapps/WorkEduCard.java
@@ -76,11 +76,7 @@
         super.onFinishInflate();
         findViewById(R.id.action_btn).setOnClickListener(this);
 
-        StringCache cache = mActivityContext.getStringCache();
-        if (cache != null) {
-            TextView title = findViewById(R.id.work_apps_paused_title);
-            title.setText(cache.workProfileEdu);
-        }
+        updateStringFromCache();
     }
 
     @Override
@@ -121,4 +117,12 @@
     public void setPosition(int position) {
         mPosition = position;
     }
+
+    public void updateStringFromCache() {
+        StringCache cache = mActivityContext.getStringCache();
+        if (cache != null) {
+            TextView title = findViewById(R.id.work_apps_paused_title);
+            title.setText(cache.workProfileEdu);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index e60752e..28a3312 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -91,10 +91,7 @@
         }
 
         setInsets(mActivityContext.getDeviceProfile().getInsets());
-        StringCache cache = mActivityContext.getStringCache();
-        if (cache != null) {
-            mTextView.setText(cache.workProfilePauseButton);
-        }
+        updateStringFromCache();
 
         getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
     }
@@ -212,4 +209,11 @@
     public int getScrollThreshold() {
         return mScrollThreshold;
     }
+
+    public void updateStringFromCache(){
+        StringCache cache = mActivityContext.getStringCache();
+        if (cache != null) {
+            mTextView.setText(cache.workProfilePauseButton);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/allapps/WorkPausedCard.java b/src/com/android/launcher3/allapps/WorkPausedCard.java
index 26a7803..1882667 100644
--- a/src/com/android/launcher3/allapps/WorkPausedCard.java
+++ b/src/com/android/launcher3/allapps/WorkPausedCard.java
@@ -57,6 +57,10 @@
         mBtn = findViewById(R.id.enable_work_apps);
         mBtn.setOnClickListener(this);
 
+        updateStringFromCache();
+    }
+
+    public void updateStringFromCache() {
         StringCache cache = mActivityContext.getStringCache();
         if (cache != null) {
             setWorkProfilePausedResources(cache);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index d4fe7ae..02bbd24 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -182,18 +182,6 @@
             "ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION", DISABLED,
             "Enables predictive back animation from all apps and widgets to home");
 
-    // TODO(Block 11): Clean up flags
-    public static final BooleanFlag ENABLE_TWO_PANEL_HOME = getDebugFlag(270392643,
-            "ENABLE_TWO_PANEL_HOME", ENABLED,
-            "Uses two panel on home screen. Only applicable on large screen devices.");
-
-    public static final BooleanFlag FOLDABLE_WORKSPACE_REORDER = getDebugFlag(270395070,
-            "FOLDABLE_WORKSPACE_REORDER", DISABLED,
-            "In foldables, when reordering the icons and widgets, is now going to use both sides");
-
-    public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
-            "FOLDABLE_SINGLE_PAGE", ENABLED, "Use a single page for the workspace");
-
     // TODO(Block 12): Clean up flags
     public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680,
             "ENABLE_MULTI_INSTANCE", DISABLED,
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 1f165d1..556ac26 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -314,7 +314,8 @@
                                 currentScreenIds, pendingTasks, workspaceItemCount, isBindSync);
                     }, mUiExecutor);
 
-            mCallbacks.bindStringCache(mBgDataModel.stringCache.clone());
+            StringCache cacheClone = mBgDataModel.stringCache.clone();
+            executeCallbacksTask(c -> c.bindStringCache(cacheClone), pendingExecutor);
         }
 
         private void bindWorkspaceItems(
@@ -442,9 +443,8 @@
                         .resumeModelPush(FLAG_LOADER_RUNNING);
             });
 
-            for (Callbacks cb : mCallbacksList) {
-                cb.bindStringCache(mBgDataModel.stringCache.clone());
-            }
+            StringCache cacheClone = mBgDataModel.stringCache.clone();
+            executeCallbacksTask(c -> c.bindStringCache(cacheClone), mUiExecutor);
         }
 
         private void bindWorkspaceItems(final ArrayList<ItemInfo> workspaceItems) {
diff --git a/src/com/android/launcher3/responsive/AllAppsSpecs.kt b/src/com/android/launcher3/responsive/AllAppsSpecs.kt
new file mode 100644
index 0000000..85e383e
--- /dev/null
+++ b/src/com/android/launcher3/responsive/AllAppsSpecs.kt
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.res.XmlResourceParser
+import android.util.AttributeSet
+import android.util.Log
+import android.util.Xml
+import com.android.launcher3.R
+import com.android.launcher3.util.ResourceHelper
+import com.android.launcher3.workspace.CalculatedWorkspaceSpec
+import java.io.IOException
+import kotlin.math.roundToInt
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParserException
+
+private const val LOG_TAG = "AllAppsSpecs"
+
+class AllAppsSpecs(resourceHelper: ResourceHelper) {
+    object XmlTags {
+        const val ALL_APPS_SPECS = "allAppsSpecs"
+
+        const val ALL_APPS_SPEC = "allAppsSpec"
+        const val START_PADDING = "startPadding"
+        const val END_PADDING = "endPadding"
+        const val GUTTER = "gutter"
+        const val CELL_SIZE = "cellSize"
+    }
+
+    val allAppsHeightSpecList = mutableListOf<AllAppsSpec>()
+    val allAppsWidthSpecList = mutableListOf<AllAppsSpec>()
+
+    // TODO(b/286538013) Remove this init after a more generic or reusable parser is created
+    init {
+        var parser: XmlResourceParser? = null
+        try {
+            parser = resourceHelper.getXml()
+            val depth = parser.depth
+            var type: Int
+            while (
+                (parser.next().also { type = it } != XmlPullParser.END_TAG ||
+                    parser.depth > depth) && type != XmlPullParser.END_DOCUMENT
+            ) {
+                if (type == XmlPullParser.START_TAG && XmlTags.ALL_APPS_SPECS == parser.name) {
+                    val displayDepth = parser.depth
+                    while (
+                        (parser.next().also { type = it } != XmlPullParser.END_TAG ||
+                            parser.depth > displayDepth) && type != XmlPullParser.END_DOCUMENT
+                    ) {
+                        if (
+                            type == XmlPullParser.START_TAG && XmlTags.ALL_APPS_SPEC == parser.name
+                        ) {
+                            val attrs =
+                                resourceHelper.obtainStyledAttributes(
+                                    Xml.asAttributeSet(parser),
+                                    R.styleable.AllAppsSpec
+                                )
+                            val maxAvailableSize =
+                                attrs.getDimensionPixelSize(
+                                    R.styleable.AllAppsSpec_maxAvailableSize,
+                                    0
+                                )
+                            val specType =
+                                AllAppsSpec.SpecType.values()[
+                                        attrs.getInt(
+                                            R.styleable.AllAppsSpec_specType,
+                                            AllAppsSpec.SpecType.HEIGHT.ordinal
+                                        )]
+                            attrs.recycle()
+
+                            var startPadding: SizeSpec? = null
+                            var endPadding: SizeSpec? = null
+                            var gutter: SizeSpec? = null
+                            var cellSize: SizeSpec? = null
+
+                            val limitDepth = parser.depth
+                            while (
+                                (parser.next().also { type = it } != XmlPullParser.END_TAG ||
+                                    parser.depth > limitDepth) && type != XmlPullParser.END_DOCUMENT
+                            ) {
+                                val attr: AttributeSet = Xml.asAttributeSet(parser)
+                                if (type == XmlPullParser.START_TAG) {
+                                    when (parser.name) {
+                                        XmlTags.START_PADDING -> {
+                                            startPadding = SizeSpec.create(resourceHelper, attr)
+                                        }
+                                        XmlTags.END_PADDING -> {
+                                            endPadding = SizeSpec.create(resourceHelper, attr)
+                                        }
+                                        XmlTags.GUTTER -> {
+                                            gutter = SizeSpec.create(resourceHelper, attr)
+                                        }
+                                        XmlTags.CELL_SIZE -> {
+                                            cellSize = SizeSpec.create(resourceHelper, attr)
+                                        }
+                                    }
+                                }
+                            }
+
+                            if (
+                                startPadding == null ||
+                                    endPadding == null ||
+                                    gutter == null ||
+                                    cellSize == null
+                            ) {
+                                throw IllegalStateException(
+                                    "All attributes in AllAppsSpec must be defined"
+                                )
+                            }
+
+                            val allAppsSpec =
+                                AllAppsSpec(
+                                    maxAvailableSize,
+                                    specType,
+                                    startPadding,
+                                    endPadding,
+                                    gutter,
+                                    cellSize
+                                )
+                            if (allAppsSpec.isValid()) {
+                                if (allAppsSpec.specType == AllAppsSpec.SpecType.HEIGHT)
+                                    allAppsHeightSpecList.add(allAppsSpec)
+                                else allAppsWidthSpecList.add(allAppsSpec)
+                            } else {
+                                throw IllegalStateException("Invalid AllAppsSpec found.")
+                            }
+                        }
+                    }
+
+                    if (allAppsWidthSpecList.isEmpty() || allAppsHeightSpecList.isEmpty()) {
+                        throw IllegalStateException(
+                            "AllAppsSpecs is incomplete - " +
+                                "height list size = ${allAppsHeightSpecList.size}; " +
+                                "width list size = ${allAppsWidthSpecList.size}."
+                        )
+                    }
+                }
+            }
+        } catch (e: Exception) {
+            when (e) {
+                is IOException,
+                is XmlPullParserException -> {
+                    throw RuntimeException("Failure parsing all apps specs file.", e)
+                }
+                else -> throw e
+            }
+        } finally {
+            parser?.close()
+        }
+    }
+
+    /**
+     * Returns the CalculatedAllAppsSpec for width, based on the available width, the AllAppsSpecs
+     * and the CalculatedWorkspaceSpec.
+     */
+    fun getCalculatedWidthSpec(
+        columns: Int,
+        availableWidth: Int,
+        calculatedWorkspaceSpec: CalculatedWorkspaceSpec
+    ): CalculatedAllAppsSpec {
+        val widthSpec = allAppsWidthSpecList.first { availableWidth <= it.maxAvailableSize }
+
+        return CalculatedAllAppsSpec(availableWidth, columns, widthSpec, calculatedWorkspaceSpec)
+    }
+
+    /**
+     * Returns the CalculatedAllAppsSpec for height, based on the available height, the AllAppsSpecs
+     * and the CalculatedWorkspaceSpec.
+     */
+    fun getCalculatedHeightSpec(
+        rows: Int,
+        availableHeight: Int,
+        calculatedWorkspaceSpec: CalculatedWorkspaceSpec
+    ): CalculatedAllAppsSpec {
+        val heightSpec = allAppsHeightSpecList.first { availableHeight <= it.maxAvailableSize }
+
+        return CalculatedAllAppsSpec(availableHeight, rows, heightSpec, calculatedWorkspaceSpec)
+    }
+}
+
+class CalculatedAllAppsSpec(
+    val availableSpace: Int,
+    val cells: Int,
+    private val allAppsSpec: AllAppsSpec,
+    calculatedWorkspaceSpec: CalculatedWorkspaceSpec
+) {
+    var startPaddingPx: Int = 0
+        private set
+    var endPaddingPx: Int = 0
+        private set
+    var gutterPx: Int = 0
+        private set
+    var cellSizePx: Int = 0
+        private set
+    init {
+        // Copy values from workspace
+        if (allAppsSpec.startPadding.matchWorkspace)
+            startPaddingPx = calculatedWorkspaceSpec.startPaddingPx
+        if (allAppsSpec.endPadding.matchWorkspace)
+            endPaddingPx = calculatedWorkspaceSpec.endPaddingPx
+        if (allAppsSpec.gutter.matchWorkspace) gutterPx = calculatedWorkspaceSpec.gutterPx
+        if (allAppsSpec.cellSize.matchWorkspace) cellSizePx = calculatedWorkspaceSpec.cellSizePx
+
+        // Calculate all fixed size first
+        if (allAppsSpec.startPadding.fixedSize > 0)
+            startPaddingPx = allAppsSpec.startPadding.fixedSize.roundToInt()
+        if (allAppsSpec.endPadding.fixedSize > 0)
+            endPaddingPx = allAppsSpec.endPadding.fixedSize.roundToInt()
+        if (allAppsSpec.gutter.fixedSize > 0) gutterPx = allAppsSpec.gutter.fixedSize.roundToInt()
+        if (allAppsSpec.cellSize.fixedSize > 0)
+            cellSizePx = allAppsSpec.cellSize.fixedSize.roundToInt()
+
+        // Calculate all available space next
+        if (allAppsSpec.startPadding.ofAvailableSpace > 0)
+            startPaddingPx =
+                (allAppsSpec.startPadding.ofAvailableSpace * availableSpace).roundToInt()
+        if (allAppsSpec.endPadding.ofAvailableSpace > 0)
+            endPaddingPx = (allAppsSpec.endPadding.ofAvailableSpace * availableSpace).roundToInt()
+        if (allAppsSpec.gutter.ofAvailableSpace > 0)
+            gutterPx = (allAppsSpec.gutter.ofAvailableSpace * availableSpace).roundToInt()
+        if (allAppsSpec.cellSize.ofAvailableSpace > 0)
+            cellSizePx = (allAppsSpec.cellSize.ofAvailableSpace * availableSpace).roundToInt()
+
+        // Calculate remainder space last
+        val gutters = cells - 1
+        val usedSpace = startPaddingPx + endPaddingPx + (gutterPx * gutters) + (cellSizePx * cells)
+        val remainderSpace = availableSpace - usedSpace
+        if (allAppsSpec.startPadding.ofRemainderSpace > 0)
+            startPaddingPx =
+                (allAppsSpec.startPadding.ofRemainderSpace * remainderSpace).roundToInt()
+        if (allAppsSpec.endPadding.ofRemainderSpace > 0)
+            endPaddingPx = (allAppsSpec.endPadding.ofRemainderSpace * remainderSpace).roundToInt()
+        if (allAppsSpec.gutter.ofRemainderSpace > 0)
+            gutterPx = (allAppsSpec.gutter.ofRemainderSpace * remainderSpace).roundToInt()
+        if (allAppsSpec.cellSize.ofRemainderSpace > 0)
+            cellSizePx = (allAppsSpec.cellSize.ofRemainderSpace * remainderSpace).roundToInt()
+    }
+
+    override fun toString(): String {
+        return "CalculatedAllAppsSpec(availableSpace=$availableSpace, " +
+            "cells=$cells, startPaddingPx=$startPaddingPx, endPaddingPx=$endPaddingPx, " +
+            "gutterPx=$gutterPx, cellSizePx=$cellSizePx, " +
+            "AllAppsSpec.maxAvailableSize=${allAppsSpec.maxAvailableSize})"
+    }
+}
+
+data class AllAppsSpec(
+    val maxAvailableSize: Int,
+    val specType: SpecType,
+    val startPadding: SizeSpec,
+    val endPadding: SizeSpec,
+    val gutter: SizeSpec,
+    val cellSize: SizeSpec
+) {
+
+    enum class SpecType {
+        HEIGHT,
+        WIDTH
+    }
+
+    fun isValid(): Boolean {
+        if (maxAvailableSize <= 0) {
+            Log.e(LOG_TAG, "AllAppsSpec#isValid - maxAvailableSize <= 0")
+            return false
+        }
+
+        // All specs need to be individually valid
+        if (!allSpecsAreValid()) {
+            Log.e(LOG_TAG, "AllAppsSpec#isValid - !allSpecsAreValid()")
+            return false
+        }
+
+        return true
+    }
+
+    private fun allSpecsAreValid(): Boolean =
+        startPadding.isValid() && endPadding.isValid() && gutter.isValid() && cellSize.isValid()
+}
diff --git a/src/com/android/launcher3/responsive/SizeSpec.kt b/src/com/android/launcher3/responsive/SizeSpec.kt
index 407a212..3d618f9 100644
--- a/src/com/android/launcher3/responsive/SizeSpec.kt
+++ b/src/com/android/launcher3/responsive/SizeSpec.kt
@@ -15,22 +15,27 @@
  * @param ofAvailableSpace a percentage of the available space
  * @param ofRemainderSpace a percentage of the remaining space (available space minus used space)
  * @param matchWorkspace indicates whether the workspace value will be used or not.
+ * @param maxSize restricts the maximum value allowed for the [SizeSpec].
  */
 data class SizeSpec(
     val fixedSize: Float = 0f,
     val ofAvailableSpace: Float = 0f,
     val ofRemainderSpace: Float = 0f,
-    val matchWorkspace: Boolean = false
+    val matchWorkspace: Boolean = false,
+    val maxSize: Int = Int.MAX_VALUE
 ) {
 
     /** Retrieves the correct value for [SizeSpec]. */
     fun getCalculatedValue(availableSpace: Int, workspaceValue: Int): Int {
-        return when {
-            fixedSize > 0 -> fixedSize.roundToInt()
-            ofAvailableSpace > 0 -> (ofAvailableSpace * availableSpace).roundToInt()
-            matchWorkspace -> workspaceValue
-            else -> 0
-        }
+        val calculatedValue =
+            when {
+                fixedSize > 0 -> fixedSize.roundToInt()
+                matchWorkspace -> workspaceValue
+                ofAvailableSpace > 0 -> (ofAvailableSpace * availableSpace).roundToInt()
+                else -> 0
+            }
+
+        return calculatedValue.coerceAtMost(maxSize)
     }
 
     /**
@@ -38,11 +43,14 @@
      * is 0, returns a default value.
      */
     fun getRemainderSpaceValue(remainderSpace: Int, defaultValue: Int): Int {
-        return if (ofRemainderSpace > 0) {
-            (ofRemainderSpace * remainderSpace).roundToInt()
-        } else {
-            defaultValue
-        }
+        val remainderSpaceValue =
+            if (ofRemainderSpace > 0) {
+                (ofRemainderSpace * remainderSpace).roundToInt()
+            } else {
+                defaultValue
+            }
+
+        return remainderSpaceValue.coerceAtMost(maxSize)
     }
 
     fun isValid(): Boolean {
@@ -69,12 +77,17 @@
             return false
         }
 
-        // Invalid fixed size
-        if (fixedSize < 0f) {
+        // Invalid fixed or max size
+        if (fixedSize < 0f || maxSize < 0f) {
             Log.e(TAG, "SizeSpec#isValid - values should be bigger or equal to zero.")
             return false
         }
 
+        if (fixedSize > 0f && fixedSize > maxSize) {
+            Log.e(TAG, "SizeSpec#isValid - fixed size should be smaller than the max size.")
+            return false
+        }
+
         return true
     }
 
@@ -96,10 +109,12 @@
             val ofAvailableSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofAvailableSpace)
             val ofRemainderSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofRemainderSpace)
             val matchWorkspace = styledAttrs.getBoolean(R.styleable.SizeSpec_matchWorkspace, false)
+            val maxSize =
+                styledAttrs.getDimensionPixelSize(R.styleable.SizeSpec_maxSize, Int.MAX_VALUE)
 
             styledAttrs.recycle()
 
-            return SizeSpec(fixedSize, ofAvailableSpace, ofRemainderSpace, matchWorkspace)
+            return SizeSpec(fixedSize, ofAvailableSpace, ofRemainderSpace, matchWorkspace, maxSize)
         }
     }
 }
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 0bb018d..b054f51 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -17,7 +17,6 @@
 
 import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
-import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.annotation.TargetApi;
@@ -157,8 +156,7 @@
                 return response;
 
             case TestProtocol.REQUEST_IS_TWO_PANELS:
-                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
-                        FOLDABLE_SINGLE_PAGE.get() ? false : mDeviceProfile.isTwoPanels);
+                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, false);
                 return response;
 
             case TestProtocol.REQUEST_GET_HAD_NONTEST_EVENTS:
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index bc3889f..98d854e 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -95,6 +95,8 @@
 
     private boolean mTrackingWidgetUpdate = false;
 
+    private boolean mIsWidgetCachingDisabled = false;
+
     public LauncherAppWidgetHostView(Context context) {
         super(context);
         mLauncher = Launcher.getLauncher(context);
@@ -138,6 +140,10 @@
         }
     }
 
+    public void setIsWidgetCachingDisabled(boolean isWidgetCachingDisabled) {
+        mIsWidgetCachingDisabled = isWidgetCachingDisabled;
+    }
+
     @Override
     @TargetApi(Build.VERSION_CODES.Q)
     public void updateAppWidget(RemoteViews remoteViews) {
@@ -147,7 +153,8 @@
                     TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId());
             mTrackingWidgetUpdate = false;
         }
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
+        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()
+                && !mIsWidgetCachingDisabled) {
             mLastRemoteViews = remoteViews;
             if (isDeferringUpdates()) {
                 return;
diff --git a/tests/res/values/attrs.xml b/tests/res/values/attrs.xml
index 54f0381..0d586c2 100644
--- a/tests/res/values/attrs.xml
+++ b/tests/res/values/attrs.xml
@@ -31,6 +31,7 @@
         <attr name="ofAvailableSpace" format="float" />
         <attr name="ofRemainderSpace" format="float" />
         <attr name="matchWorkspace" format="boolean" />
+        <attr name="maxSize" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="FolderSpec">
@@ -38,4 +39,8 @@
         <attr name="maxAvailableSize" />
     </declare-styleable>
 
+    <declare-styleable name="AllAppsSpec">
+        <attr name="specType" />
+        <attr name="maxAvailableSize" />
+    </declare-styleable>
 </resources>
diff --git a/tests/res/xml/invalid_all_apps_file_case_1.xml b/tests/res/xml/invalid_all_apps_file_case_1.xml
new file mode 100644
index 0000000..6fd35b1
--- /dev/null
+++ b/tests/res/xml/invalid_all_apps_file_case_1.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <allAppsSpec
+        launcher:specType="height"
+        launcher:maxAvailableSize="9999dp">
+        <!--  missing startPadding  -->
+        <endPadding launcher:fixedSize="0dp" />
+        <gutter launcher:matchWorkspace="true" />
+        <cellSize launcher:matchWorkspace="true" />
+    </allAppsSpec>
+
+    <allAppsSpec
+        launcher:specType="width"
+        launcher:maxAvailableSize="9999dp">
+        <startPadding launcher:matchWorkspace="true" />
+        <endPadding launcher:matchWorkspace="true" />
+        <gutter launcher:matchWorkspace="true" />
+        <cellSize launcher:matchWorkspace="true" />
+    </allAppsSpec>
+
+</allAppsSpecs>
+
diff --git a/tests/res/xml/invalid_all_apps_file_case_2.xml b/tests/res/xml/invalid_all_apps_file_case_2.xml
new file mode 100644
index 0000000..de9c1ac
--- /dev/null
+++ b/tests/res/xml/invalid_all_apps_file_case_2.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <allAppsSpec
+        launcher:specType="height"
+        launcher:maxAvailableSize="9999dp">
+        <startPadding launcher:fixedSize="0dp" />
+        <endPadding launcher:fixedSize="0dp" />
+        <!--  more than 1 value in one tag -->
+        <gutter
+            launcher:matchWorkspace="true"
+            launcher:fixedSize="16dp" />
+        <cellSize launcher:matchWorkspace="true" />
+    </allAppsSpec>
+
+    <allAppsSpec
+        launcher:specType="width"
+        launcher:maxAvailableSize="9999dp">
+        <startPadding launcher:matchWorkspace="true" />
+        <endPadding launcher:matchWorkspace="true" />
+        <gutter launcher:matchWorkspace="true" />
+        <cellSize launcher:matchWorkspace="true" />
+    </allAppsSpec>
+
+</allAppsSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/invalid_all_apps_file_case_3.xml b/tests/res/xml/invalid_all_apps_file_case_3.xml
new file mode 100644
index 0000000..7af0af4
--- /dev/null
+++ b/tests/res/xml/invalid_all_apps_file_case_3.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <allAppsSpec
+        launcher:specType="height"
+        launcher:maxAvailableSize="9999dp">
+        <startPadding launcher:fixedSize="0dp" />
+        <endPadding launcher:fixedSize="0dp" />
+        <gutter launcher:matchWorkspace="true" />
+        <!--  value bigger than 1 -->
+        <cellSize launcher:ofRemainderSpace="1.001" />
+    </allAppsSpec>
+
+    <allAppsSpec
+        launcher:specType="width"
+        launcher:maxAvailableSize="9999dp">
+        <startPadding launcher:matchWorkspace="true" />
+        <endPadding launcher:matchWorkspace="true" />
+        <gutter launcher:matchWorkspace="true" />
+        <cellSize launcher:matchWorkspace="true" />
+    </allAppsSpec>
+
+</allAppsSpecs>
+
diff --git a/tests/res/xml/valid_all_apps_file.xml b/tests/res/xml/valid_all_apps_file.xml
new file mode 100644
index 0000000..0be55d1
--- /dev/null
+++ b/tests/res/xml/valid_all_apps_file.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <allAppsSpec
+        launcher:specType="height"
+        launcher:maxAvailableSize="9999dp">
+        <startPadding launcher:fixedSize="0dp" />
+        <endPadding launcher:fixedSize="0dp" />
+        <gutter launcher:matchWorkspace="true" />
+        <cellSize launcher:matchWorkspace="true" />
+    </allAppsSpec>
+
+    <allAppsSpec
+        launcher:specType="width"
+        launcher:maxAvailableSize="9999dp">
+        <startPadding launcher:matchWorkspace="true" />
+        <endPadding launcher:matchWorkspace="true" />
+        <gutter launcher:matchWorkspace="true" />
+        <cellSize launcher:matchWorkspace="true" />
+    </allAppsSpec>
+
+</allAppsSpecs>
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 6dec67e..f0cedd3 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -27,6 +27,10 @@
 import com.android.launcher3.util.WindowBounds
 import com.android.launcher3.util.window.CachedDisplayInfo
 import com.android.launcher3.util.window.WindowManagerProxy
+import java.io.BufferedReader
+import java.io.File
+import java.io.PrintWriter
+import java.io.StringWriter
 import kotlin.math.max
 import kotlin.math.min
 import org.junit.After
@@ -287,4 +291,19 @@
         whenever(displayController.info).thenReturn(info)
         whenever(displayController.isTransientTaskbar).thenReturn(isGestureMode)
     }
+
+    /** Create a new dump of DeviceProfile, saves to a file in the device and returns it */
+    protected fun dump(context: Context, dp: DeviceProfile, fileName: String): String {
+        val stringWriter = StringWriter()
+        PrintWriter(stringWriter).use { dp.dump(context, "", it) }
+        return stringWriter.toString().also { content -> writeToDevice(context, fileName, content) }
+    }
+
+    /** Read a file from assets/ and return it as a string */
+    protected fun readDumpFromAssets(context: Context, fileName: String): String =
+        context.assets.open("dumpTests/$fileName").bufferedReader().use(BufferedReader::readText)
+
+    private fun writeToDevice(context: Context, fileName: String, content: String) {
+        File(context.getDir("dumpTests", Context.MODE_PRIVATE), fileName).writeText(content)
+    }
 }
diff --git a/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt b/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
new file mode 100644
index 0000000..77ea5ba
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.tests.R as TestR
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AllAppsSpecsTest : AbstractDeviceProfileTest() {
+    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+
+    @Before
+    fun setup() {
+        initializeVarsForPhone(deviceSpecs["phone"]!!)
+    }
+
+    @Test
+    fun parseValidFile() {
+        val allAppsSpecs =
+            AllAppsSpecs(TestResourceHelper(context!!, TestR.xml.valid_all_apps_file))
+        assertThat(allAppsSpecs.allAppsHeightSpecList.size).isEqualTo(1)
+        assertThat(allAppsSpecs.allAppsHeightSpecList[0].toString())
+            .isEqualTo(
+                "AllAppsSpec(" +
+                    "maxAvailableSize=26247, " +
+                    "specType=HEIGHT, " +
+                    "startPadding=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0, " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
+                    "endPadding=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0, " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
+                    "gutter=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0, " +
+                    "matchWorkspace=true, " +
+                    "maxSize=2147483647), " +
+                    "cellSize=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0, " +
+                    "matchWorkspace=true, " +
+                    "maxSize=2147483647)" +
+                    ")"
+            )
+
+        assertThat(allAppsSpecs.allAppsWidthSpecList.size).isEqualTo(1)
+        assertThat(allAppsSpecs.allAppsWidthSpecList[0].toString())
+            .isEqualTo(
+                "AllAppsSpec(" +
+                    "maxAvailableSize=26247, " +
+                    "specType=WIDTH, " +
+                    "startPadding=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0, " +
+                    "matchWorkspace=true, " +
+                    "maxSize=2147483647), " +
+                    "endPadding=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0, " +
+                    "matchWorkspace=true, " +
+                    "maxSize=2147483647), " +
+                    "gutter=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0, " +
+                    "matchWorkspace=true, " +
+                    "maxSize=2147483647), " +
+                    "cellSize=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0, " +
+                    "matchWorkspace=true, " +
+                    "maxSize=2147483647)" +
+                    ")"
+            )
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_missingTag_throwsError() {
+        AllAppsSpecs(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_1))
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
+        AllAppsSpecs(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_2))
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_valueBiggerThan1_throwsError() {
+        AllAppsSpecs(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_3))
+    }
+}
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
new file mode 100644
index 0000000..9f981fa
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.tests.R as TestR
+import com.android.launcher3.util.TestResourceHelper
+import com.android.launcher3.workspace.WorkspaceSpecs
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CalculatedAllAppsSpecTest : AbstractDeviceProfileTest() {
+    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+
+    /**
+     * This test tests:
+     * - (height spec) copy values from workspace
+     * - (width spec) copy values from workspace
+     */
+    @Test
+    fun normalPhone_copiesFromWorkspace() {
+        val deviceSpec = deviceSpecs["phone"]!!
+        initializeVarsForPhone(deviceSpec)
+
+        val availableWidth = deviceSpec.naturalSize.first
+        // Hotseat size is roughly 495px on a real device,
+        // it doesn't need to be precise on unit tests
+        val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 495
+
+        val workspaceSpecs =
+            WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
+        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
+        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+
+        val allAppsSpecs =
+            AllAppsSpecs(TestResourceHelper(context!!, TestR.xml.valid_all_apps_file))
+
+        with(allAppsSpecs.getCalculatedWidthSpec(4, availableWidth, widthSpec)) {
+            assertThat(availableSpace).isEqualTo(availableWidth)
+            assertThat(cells).isEqualTo(4)
+            assertThat(startPaddingPx).isEqualTo(widthSpec.startPaddingPx)
+            assertThat(endPaddingPx).isEqualTo(widthSpec.endPaddingPx)
+            assertThat(gutterPx).isEqualTo(widthSpec.gutterPx)
+            assertThat(cellSizePx).isEqualTo(widthSpec.cellSizePx)
+        }
+
+        with(allAppsSpecs.getCalculatedHeightSpec(5, availableHeight, heightSpec)) {
+            assertThat(availableSpace).isEqualTo(availableHeight)
+            assertThat(cells).isEqualTo(5)
+            assertThat(startPaddingPx).isEqualTo(0)
+            assertThat(endPaddingPx).isEqualTo(0)
+            assertThat(gutterPx).isEqualTo(heightSpec.gutterPx)
+            assertThat(cellSizePx).isEqualTo(heightSpec.cellSizePx)
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/responsive/SizeSpecTest.kt b/tests/src/com/android/launcher3/responsive/SizeSpecTest.kt
index 5db86ff..088cae1 100644
--- a/tests/src/com/android/launcher3/responsive/SizeSpecTest.kt
+++ b/tests/src/com/android/launcher3/responsive/SizeSpecTest.kt
@@ -45,7 +45,12 @@
                 SizeSpec(0f, 1f, 0f, false),
                 SizeSpec(0f, 0f, 1f, false),
                 SizeSpec(0f, 0f, 0f, false),
-                SizeSpec(0f, 0f, 0f, true)
+                SizeSpec(0f, 0f, 0f, true),
+                SizeSpec(100f, 0f, 0f, false, 100),
+                SizeSpec(0f, 1f, 0f, false, 100),
+                SizeSpec(0f, 0f, 1f, false, 100),
+                SizeSpec(0f, 0f, 0f, false, 100),
+                SizeSpec(0f, 0f, 0f, true, 100)
             )
 
         for (instance in combinations) {
@@ -62,7 +67,12 @@
                 SizeSpec(100f) to 100,
                 SizeSpec(ofAvailableSpace = .5f) to (availableSpace * .5f).roundToInt(),
                 SizeSpec(ofRemainderSpace = .5f) to 0,
-                SizeSpec(matchWorkspace = true) to matchWorkspaceValue
+                SizeSpec(matchWorkspace = true) to matchWorkspaceValue,
+                // Restricts max size up to 10 (calculated value > 10)
+                SizeSpec(100f, maxSize = 10) to 10,
+                SizeSpec(ofAvailableSpace = .5f, maxSize = 10) to 10,
+                SizeSpec(ofRemainderSpace = .5f, maxSize = 10) to 0,
+                SizeSpec(matchWorkspace = true, maxSize = 10) to 10
             )
 
         for ((sizeSpec, expectedValue) in combinations) {
@@ -74,13 +84,18 @@
     @Test
     fun validate_getRemainderSpaceValue() {
         val remainderSpace = 100
-        val defaultValue = 10
+        val defaultValue = 50
         val combinations =
             listOf(
                 SizeSpec(100f) to defaultValue,
                 SizeSpec(ofAvailableSpace = .5f) to defaultValue,
                 SizeSpec(ofRemainderSpace = .5f) to (remainderSpace * .5f).roundToInt(),
-                SizeSpec(matchWorkspace = true) to defaultValue
+                SizeSpec(matchWorkspace = true) to defaultValue,
+                // Restricts max size up to 10 (defaultValue > 10)
+                SizeSpec(100f, maxSize = 10) to 10,
+                SizeSpec(ofAvailableSpace = .5f, maxSize = 10) to 10,
+                SizeSpec(ofRemainderSpace = .5f, maxSize = 10) to 10,
+                SizeSpec(matchWorkspace = true, maxSize = 10) to 10,
             )
 
         for ((sizeSpec, expectedValue) in combinations) {
@@ -111,11 +126,13 @@
     fun invalid_values() {
         val combinations =
             listOf(
+                SizeSpec(-1f, 0f, 0f, false),
                 SizeSpec(0f, 1.1f, 0f, false),
                 SizeSpec(0f, -0.1f, 0f, false),
                 SizeSpec(0f, 0f, 1.1f, false),
                 SizeSpec(0f, 0f, -0.1f, false),
-                SizeSpec(-1f, 0f, 0f, false)
+                SizeSpec(0f, 0f, 0f, false, -10),
+                SizeSpec(50f, 0f, 0f, false, 10)
             )
 
         for (instance in combinations) {
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 60f1418..68e586c 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -204,11 +204,11 @@
     }
 
     protected TestRule getRulesInsideActivityMonitor() {
-        final ViewCaptureRule viewCaptureRule = new ViewCaptureRule();
+        final ViewCaptureRule viewCaptureRule = new ViewCaptureRule(mActivityMonitor::getActivity);
         final RuleChain inner = RuleChain
                 .outerRule(new PortraitLandscapeRunner(this))
-                .around(viewCaptureRule)
                 .around(new FailureWatcher(mDevice, mLauncher, viewCaptureRule.getViewCapture()))
+                .around(viewCaptureRule)
                 .around(new ViewCaptureAnalysisRule(viewCaptureRule.getViewCapture()));
 
         return TestHelpers.isInLauncherProcess()
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index a12d10b..e427560 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -23,7 +23,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
@@ -58,6 +57,7 @@
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 import com.android.launcher3.util.rule.TISBindRule;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
@@ -507,16 +507,11 @@
 
     private void verifyAppUninstalledFromAllApps(Workspace workspace, String appName) {
         final HomeAllApps allApps = workspace.switchToAllApps();
-        allApps.freeze();
-        try {
-            assertNull(appName + " app was found on all apps after being uninstalled",
-                    allApps.tryGetAppIcon(appName));
-        } finally {
-            allApps.unfreeze();
-        }
+        Wait.atMost(appName + " app was found on all apps after being uninstalled",
+                () -> allApps.tryGetAppIcon(appName) == null,
+                DEFAULT_UI_TIMEOUT, mLauncher);
     }
 
-    @Ignore("b/256615483")
     @Test
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
@@ -540,7 +535,6 @@
             Workspace workspace = mLauncher.getWorkspace();
             final HomeAllApps allApps = workspace.switchToAllApps();
             workspace = allApps.getAppIcon(DUMMY_APP_NAME).uninstall();
-            waitForLauncherUIUpdate();
             verifyAppUninstalledFromAllApps(workspace, DUMMY_APP_NAME);
         } finally {
             TestUtil.uninstallDummyApp();
diff --git a/tests/src/com/android/launcher3/util/TestResourceHelper.kt b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
index 691a069..cf80ece 100644
--- a/tests/src/com/android/launcher3/util/TestResourceHelper.kt
+++ b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
@@ -31,6 +31,7 @@
                 styleId.contentEquals(R.styleable.SizeSpec) -> TestR.styleable.SizeSpec
                 styleId.contentEquals(R.styleable.WorkspaceSpec) -> TestR.styleable.WorkspaceSpec
                 styleId.contentEquals(R.styleable.FolderSpec) -> TestR.styleable.FolderSpec
+                styleId.contentEquals(R.styleable.AllAppsSpec) -> TestR.styleable.AllAppsSpec
                 else -> styleId.clone()
             }
 
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
index 0c65539..ca3147d 100644
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -23,6 +23,7 @@
 import com.android.app.viewcapture.SimpleViewCapture
 import com.android.app.viewcapture.ViewCapture.MAIN_EXECUTOR
 import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
+import java.util.function.Supplier
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
@@ -33,7 +34,7 @@
  *
  * This rule will not work in OOP tests that don't have access to the activity under test.
  */
-class ViewCaptureRule : TestRule {
+class ViewCaptureRule(var alreadyOpenActivitySupplier: Supplier<Activity?>) : TestRule {
     val viewCapture = SimpleViewCapture("test-view-capture")
 
     override fun apply(base: Statement, description: Description): Statement {
@@ -41,16 +42,16 @@
             override fun evaluate() {
                 val windowListenerCloseables = mutableListOf<SafeCloseable>()
 
+                val alreadyOpenActivity = alreadyOpenActivitySupplier.get()
+                if (alreadyOpenActivity != null) {
+                    startCapture(windowListenerCloseables, alreadyOpenActivity)
+                }
+
                 val lifecycleCallbacks =
                     object : ActivityLifecycleCallbacksAdapter {
                         override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
                             super.onActivityCreated(activity, bundle)
-                            windowListenerCloseables.add(
-                                viewCapture.startCapture(
-                                    activity.window.decorView,
-                                    "${description.testClass?.simpleName}.${description.methodName}"
-                                )
-                            )
+                            startCapture(windowListenerCloseables, activity)
                         }
 
                         override fun onActivityDestroyed(activity: Activity) {
@@ -75,6 +76,18 @@
                     MAIN_EXECUTOR.execute { windowListenerCloseables.onEach(SafeCloseable::close) }
                 }
             }
+
+            private fun startCapture(
+                windowListenerCloseables: MutableCollection<SafeCloseable>,
+                activity: Activity
+            ) {
+                windowListenerCloseables.add(
+                    viewCapture.startCapture(
+                        activity.window.decorView,
+                        "${description.testClass?.simpleName}.${description.methodName}"
+                    )
+                )
+            }
         }
     }
 }
diff --git a/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt b/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
index 51808e3..8b99a3a 100644
--- a/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
+++ b/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
@@ -51,19 +51,23 @@
                     "startPadding=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "endPadding=SizeSpec(fixedSize=84.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "gutter=SizeSpec(fixedSize=42.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "cellSize=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.15808, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false)" +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647)" +
                     ")"
             )
         assertThat(workspaceSpecs.workspaceHeightSpecList[1].toString())
@@ -74,19 +78,23 @@
                     "startPadding=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "endPadding=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=1.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "gutter=SizeSpec(fixedSize=42.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "cellSize=SizeSpec(fixedSize=273.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false)" +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647)" +
                     ")"
             )
         assertThat(workspaceSpecs.workspaceHeightSpecList[2].toString())
@@ -97,19 +105,23 @@
                     "startPadding=SizeSpec(fixedSize=21.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "endPadding=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=1.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "gutter=SizeSpec(fixedSize=42.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "cellSize=SizeSpec(fixedSize=273.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false)" +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647)" +
                     ")"
             )
         assertThat(workspaceSpecs.workspaceWidthSpecList.size).isEqualTo(1)
@@ -121,19 +133,23 @@
                     "startPadding=SizeSpec(fixedSize=58.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "endPadding=SizeSpec(fixedSize=58.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "gutter=SizeSpec(fixedSize=42.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
-                    "matchWorkspace=false), " +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647), " +
                     "cellSize=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.25, " +
-                    "matchWorkspace=false)" +
+                    "matchWorkspace=false, " +
+                    "maxSize=2147483647)" +
                     ")"
             )
     }