[automerger skipped] Revert "Replace field injection with constructor  injection." am: fb64691c44 am: 8ac66064eb -s ours

am skip reason: Merged-In I718113e103da303ddfb102b73c95f9a9b25da132 with SHA-1 65d5aa7e11 is already in history. Merged-In was found from reverted change.

Reverted change: https://android-review.googlesource.com/c/platform/packages/apps/ThemePicker/+/3343446

Original change: https://android-review.googlesource.com/c/platform/packages/apps/ThemePicker/+/3344343

Change-Id: Icd2874267adb8c754434bac37deaa6f0111c5679
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6e5844d..f89ff6e 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -82,6 +82,16 @@
 
         <activity
             tools:node="replace"
+            android:name="com.android.wallpaper.picker.customization.ui.CustomizationPickerActivity2"
+            android:label="@string/app_name"
+            android:relinquishTaskIdentity="true"
+            android:resizeableActivity="false"
+            android:theme="@style/WallpaperTheme"
+            android:configChanges="assetsPaths"
+            android:exported="false"/>
+
+        <activity
+            tools:node="replace"
             android:name="com.android.wallpaper.picker.PassThroughCustomizationPickerActivity"
             android:label="@string/app_name"
             android:resizeableActivity="false"
diff --git a/res/drawable/clock_font_apply.xml b/res/drawable/clock_font_apply.xml
new file mode 100644
index 0000000..11c6f06
--- /dev/null
+++ b/res/drawable/clock_font_apply.xml
@@ -0,0 +1,24 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="72dp"
+    android:height="56dp"
+    android:viewportWidth="72"
+    android:viewportHeight="56">
+  <group>
+    <clip-path
+        android:pathData="M0,0h72v56h-72z"/>
+    <group>
+      <clip-path
+          android:pathData="M0,28C0,12.536 12.536,0 28,0H44C59.464,0 72,12.536 72,28C72,43.464 59.464,56 44,56H28C12.536,56 0,43.464 0,28Z"/>
+      <path
+          android:pathData="M0,28C0,12.536 12.536,0 28,0H44C59.464,0 72,12.536 72,28C72,43.464 59.464,56 44,56H28C12.536,56 0,43.464 0,28Z"
+          android:fillColor="@color/system_on_primary"/>
+      <group>
+        <clip-path
+            android:pathData="M24,16h24v24h-24z"/>
+        <path
+            android:pathData="M33.55,34L27.85,28.3L29.275,26.875L33.55,31.15L42.725,21.975L44.15,23.4L33.55,34Z"
+            android:fillColor="@color/system_primary"/>
+      </group>
+    </group>
+  </group>
+</vector>
diff --git a/res/drawable/clock_font_revert.xml b/res/drawable/clock_font_revert.xml
new file mode 100644
index 0000000..10a46ad
--- /dev/null
+++ b/res/drawable/clock_font_revert.xml
@@ -0,0 +1,24 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="72dp"
+    android:height="56dp"
+    android:viewportWidth="72"
+    android:viewportHeight="56">
+  <group>
+    <clip-path
+        android:pathData="M0,0h72v56h-72z"/>
+    <group>
+      <clip-path
+          android:pathData="M0,28C0,12.536 12.536,0 28,0H44C59.464,0 72,12.536 72,28C72,43.464 59.464,56 44,56H28C12.536,56 0,43.464 0,28Z"/>
+      <path
+          android:pathData="M0,28C0,12.536 12.536,0 28,0H44C59.464,0 72,12.536 72,28C72,43.464 59.464,56 44,56H28C12.536,56 0,43.464 0,28Z"
+          android:fillColor="@color/system_secondary_container"/>
+      <group>
+        <clip-path
+            android:pathData="M24,16h24v24h-24z"/>
+        <path
+            android:pathData="M30.4,35L29,33.6L34.6,28L29,22.4L30.4,21L36,26.6L41.6,21L43,22.4L37.4,28L43,33.6L41.6,35L36,29.4L30.4,35Z"
+            android:fillColor="@color/system_on_secondary_container"/>
+      </group>
+    </group>
+  </group>
+</vector>
diff --git a/res/drawable/clock_font_switch_divider.xml b/res/drawable/clock_font_switch_divider.xml
new file mode 100644
index 0000000..abaee24
--- /dev/null
+++ b/res/drawable/clock_font_switch_divider.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="6dp"
+    android:height="48dp"
+    android:viewportWidth="6"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M2,11C2,10.448 2.448,10 3,10C3.552,10 4,10.448 4,11V37C4,37.552 3.552,38 3,38C2.448,38 2,37.552 2,37V11Z"
+      android:fillColor="@color/system_outline"/>
+</vector>
diff --git a/res/drawable/color_overflow.xml b/res/drawable/color_overflow.xml
index 1ad29fc..62050fb 100644
--- a/res/drawable/color_overflow.xml
+++ b/res/drawable/color_overflow.xml
@@ -23,7 +23,7 @@
         <shape
             android:shape="ring"
             android:innerRadius="@dimen/component_color_overflow_small_radius_default"
-            android:thickness="-1dp"
+            android:thickness="-2dp"
             android:useLevel="false">
             <solid android:color="@color/system_outline"/>
         </shape>
diff --git a/res/drawable/customization_option_entry_icon_background.xml b/res/drawable/customization_option_entry_icon_background.xml
index b92fa0e..3166ea7 100644
--- a/res/drawable/customization_option_entry_icon_background.xml
+++ b/res/drawable/customization_option_entry_icon_background.xml
@@ -16,6 +16,6 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="@color/picker_section_icon_background" />
+    <solid android:color="@color/system_surface_container" />
     <corners android:radius="18dp" />
 </shape>
\ No newline at end of file
diff --git a/res/drawable/edit_icon.xml b/res/drawable/edit_icon.xml
new file mode 100644
index 0000000..9690d17
--- /dev/null
+++ b/res/drawable/edit_icon.xml
@@ -0,0 +1,20 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <group>
+    <clip-path
+        android:pathData="M8,24C8,15.163 15.163,8 24,8C32.837,8 40,15.163 40,24C40,32.837 32.837,40 24,40C15.163,40 8,32.837 8,24Z"/>
+    <path
+        android:pathData="M8,24C8,15.163 15.163,8 24,8C32.837,8 40,15.163 40,24C40,32.837 32.837,40 24,40C15.163,40 8,32.837 8,24Z"
+        android:fillColor="@color/system_on_primary_fixed_variant"/>
+    <group>
+      <clip-path
+          android:pathData="M14,14h20v20h-20z"/>
+      <path
+          android:pathData="M17,31V27.813L27.375,17.438C27.528,17.285 27.694,17.174 27.875,17.104C28.056,17.035 28.243,17 28.438,17C28.632,17 28.819,17.035 29,17.104C29.181,17.174 29.347,17.285 29.5,17.438L30.563,18.5C30.715,18.653 30.826,18.819 30.896,19C30.965,19.181 31,19.368 31,19.563C31,19.757 30.965,19.944 30.896,20.125C30.826,20.306 30.715,20.472 30.563,20.625L20.188,31H17ZM28.438,20.625L29.5,19.563L28.438,18.5L27.375,19.563L28.438,20.625Z"
+          android:fillColor="#ffffff"/>
+    </group>
+  </group>
+</vector>
diff --git a/res/drawable/horizontal_divider_16dp.xml b/res/drawable/horizontal_divider_16dp.xml
new file mode 100644
index 0000000..a1a17df
--- /dev/null
+++ b/res/drawable/horizontal_divider_16dp.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <size
+        android:width="16dp"
+        android:height="0dp" />
+</shape>
diff --git a/res/drawable/horizontal_divider_4dp.xml b/res/drawable/horizontal_divider_4dp.xml
new file mode 100644
index 0000000..db343c1
--- /dev/null
+++ b/res/drawable/horizontal_divider_4dp.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <size
+        android:width="4dp"
+        android:height="0dp" />
+</shape>
diff --git a/res/drawable/ic_apps_filled_24px.xml b/res/drawable/ic_apps_filled_24px.xml
new file mode 100644
index 0000000..af6fcef
--- /dev/null
+++ b/res/drawable/ic_apps_filled_24px.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white" android:pathData="M240,800Q207,800 183.5,776.5Q160,753 160,720Q160,687 183.5,663.5Q207,640 240,640Q273,640 296.5,663.5Q320,687 320,720Q320,753 296.5,776.5Q273,800 240,800ZM480,800Q447,800 423.5,776.5Q400,753 400,720Q400,687 423.5,663.5Q447,640 480,640Q513,640 536.5,663.5Q560,687 560,720Q560,753 536.5,776.5Q513,800 480,800ZM720,800Q687,800 663.5,776.5Q640,753 640,720Q640,687 663.5,663.5Q687,640 720,640Q753,640 776.5,663.5Q800,687 800,720Q800,753 776.5,776.5Q753,800 720,800ZM240,560Q207,560 183.5,536.5Q160,513 160,480Q160,447 183.5,423.5Q207,400 240,400Q273,400 296.5,423.5Q320,447 320,480Q320,513 296.5,536.5Q273,560 240,560ZM480,560Q447,560 423.5,536.5Q400,513 400,480Q400,447 423.5,423.5Q447,400 480,400Q513,400 536.5,423.5Q560,447 560,480Q560,513 536.5,536.5Q513,560 480,560ZM720,560Q687,560 663.5,536.5Q640,513 640,480Q640,447 663.5,423.5Q687,400 720,400Q753,400 776.5,423.5Q800,447 800,480Q800,513 776.5,536.5Q753,560 720,560ZM240,320Q207,320 183.5,296.5Q160,273 160,240Q160,207 183.5,183.5Q207,160 240,160Q273,160 296.5,183.5Q320,207 320,240Q320,273 296.5,296.5Q273,320 240,320ZM480,320Q447,320 423.5,296.5Q400,273 400,240Q400,207 423.5,183.5Q447,160 480,160Q513,160 536.5,183.5Q560,207 560,240Q560,273 536.5,296.5Q513,320 480,320ZM720,320Q687,320 663.5,296.5Q640,273 640,240Q640,207 663.5,183.5Q687,160 720,160Q753,160 776.5,183.5Q800,207 800,240Q800,273 776.5,296.5Q753,320 720,320Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_category_filled_24px.xml b/res/drawable/ic_category_filled_24px.xml
new file mode 100644
index 0000000..ae87e03
--- /dev/null
+++ b/res/drawable/ic_category_filled_24px.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white" android:pathData="M260,440L480,80L700,440L260,440ZM700,880Q625,880 572.5,827.5Q520,775 520,700Q520,625 572.5,572.5Q625,520 700,520Q775,520 827.5,572.5Q880,625 880,700Q880,775 827.5,827.5Q775,880 700,880ZM120,860L120,540L440,540L440,860L120,860Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_colors.xml b/res/drawable/ic_colors.xml
new file mode 100644
index 0000000..31bf4d9
--- /dev/null
+++ b/res/drawable/ic_colors.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M346,820L100,574Q90,564 85,552Q80,540 80,527Q80,514 85,502Q90,490 100,480L330,251L224,145L286,80L686,480Q696,490 700.5,502Q705,514 705,527Q705,540 700.5,552Q696,564 686,574L440,820Q430,830 418,835Q406,840 393,840Q380,840 368,835Q356,830 346,820ZM393,314L179,528Q179,528 179,528Q179,528 179,528L607,528Q607,528 607,528Q607,528 607,528L393,314ZM792,840Q756,840 731,814.5Q706,789 706,752Q706,725 719.5,701Q733,677 750,654L792,600L836,654Q852,677 866,701Q880,725 880,752Q880,789 854,814.5Q828,840 792,840Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_open_in_full_24px.xml b/res/drawable/ic_open_in_full_24px.xml
new file mode 100644
index 0000000..4864792
--- /dev/null
+++ b/res/drawable/ic_open_in_full_24px.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white" android:pathData="M120,840L120,520L200,520L200,704L704,200L520,200L520,120L840,120L840,440L760,440L760,256L256,760L440,760L440,840L120,840Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_palette_filled_24px.xml b/res/drawable/ic_palette_filled_24px.xml
new file mode 100644
index 0000000..941335f
--- /dev/null
+++ b/res/drawable/ic_palette_filled_24px.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white" android:pathData="M480,880Q398,880 325,848.5Q252,817 197.5,762.5Q143,708 111.5,635Q80,562 80,480Q80,397 112.5,324Q145,251 200.5,197Q256,143 330,111.5Q404,80 488,80Q568,80 639,107.5Q710,135 763.5,183.5Q817,232 848.5,298.5Q880,365 880,442Q880,557 810,618.5Q740,680 640,680L566,680Q557,680 553.5,685Q550,690 550,696Q550,708 565,730.5Q580,753 580,782Q580,832 552.5,856Q525,880 480,880ZM260,520Q286,520 303,503Q320,486 320,460Q320,434 303,417Q286,400 260,400Q234,400 217,417Q200,434 200,460Q200,486 217,503Q234,520 260,520ZM380,360Q406,360 423,343Q440,326 440,300Q440,274 423,257Q406,240 380,240Q354,240 337,257Q320,274 320,300Q320,326 337,343Q354,360 380,360ZM580,360Q606,360 623,343Q640,326 640,300Q640,274 623,257Q606,240 580,240Q554,240 537,257Q520,274 520,300Q520,326 537,343Q554,360 580,360ZM700,520Q726,520 743,503Q760,486 760,460Q760,434 743,417Q726,400 700,400Q674,400 657,417Q640,434 640,460Q640,486 657,503Q674,520 700,520Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_style_filled_24px.xml b/res/drawable/ic_style_filled_24px.xml
new file mode 100644
index 0000000..0b9ec32
--- /dev/null
+++ b/res/drawable/ic_style_filled_24px.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white" android:pathData="M159,792L125,778Q94,765 83.5,733Q73,701 87,670L159,514L159,792ZM319,880Q286,880 262.5,856.5Q239,833 239,800L239,560L345,854Q348,861 351,867.5Q354,874 359,880L319,880ZM525,876Q493,888 463,873Q433,858 421,826L243,338Q231,306 245,275.5Q259,245 291,234L593,124Q625,112 655,127Q685,142 697,174L875,662Q887,694 873,724.5Q859,755 827,766L525,876ZM439,400Q456,400 467.5,388.5Q479,377 479,360Q479,343 467.5,331.5Q456,320 439,320Q422,320 410.5,331.5Q399,343 399,360Q399,377 410.5,388.5Q422,400 439,400Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout/clock_font_axis_name.xml b/res/layout/clock_font_axis_name.xml
new file mode 100644
index 0000000..dd29c6b
--- /dev/null
+++ b/res/layout/clock_font_axis_name.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/clock_axis_name"
+    android:layout_width="@dimen/clock_font_axis_name_width"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical" />
\ No newline at end of file
diff --git a/res/layout/clock_font_axis_slider_row.xml b/res/layout/clock_font_axis_slider_row.xml
new file mode 100644
index 0000000..cb663b4
--- /dev/null
+++ b/res/layout/clock_font_axis_slider_row.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingVertical="@dimen/clock_axis_control_row_vertical_padding"
+    android:orientation="horizontal">
+    <include layout="@layout/clock_font_axis_name" />
+
+    <SeekBar
+        android:id="@+id/clock_axis_slider"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:paddingStart="@dimen/clock_axis_control_padding_start"
+        android:minHeight="@dimen/touch_target_min_height"
+        android:thumb="@null"
+        android:background="@null"
+        android:splitTrack="false"
+        android:progressDrawable="@drawable/saturation_progress_drawable" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/clock_font_axis_switch.xml b/res/layout/clock_font_axis_switch.xml
new file mode 100644
index 0000000..385d105
--- /dev/null
+++ b/res/layout/clock_font_axis_switch.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<Switch xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/clock_axis_switch"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/clock_axis_control_padding_start"
+    style="@style/Switch.SettingsLib" />
\ No newline at end of file
diff --git a/res/layout/clock_font_axis_switch_row.xml b/res/layout/clock_font_axis_switch_row.xml
new file mode 100644
index 0000000..139e5e0
--- /dev/null
+++ b/res/layout/clock_font_axis_switch_row.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingVertical="@dimen/clock_axis_control_row_vertical_padding"
+    android:orientation="horizontal">
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/clock_switch_one"
+        android:orientation="horizontal">
+
+        <include layout="@layout/clock_font_axis_name" />
+        <include layout="@layout/clock_font_axis_switch" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/clock_switch_two"
+        android:orientation="horizontal"
+        android:visibility="gone">
+
+        <ImageView
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:src="@drawable/clock_font_switch_divider"
+            android:layout_marginHorizontal="@dimen/clock_font_control_switch_padding_horizontal"
+            android:layout_gravity="center_vertical"/>
+
+        <include layout="@layout/clock_font_axis_name" />
+        <include layout="@layout/clock_font_axis_switch" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/clock_host_view.xml b/res/layout/clock_host_view.xml
new file mode 100644
index 0000000..d6f5275
--- /dev/null
+++ b/res/layout/clock_host_view.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<com.android.customization.picker.clock.ui.view.ClockConstraintLayoutHostView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/clock_host_view"
+    android:importantForAccessibility="noHideDescendants"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:clipChildren="false"/>
\ No newline at end of file
diff --git a/res/layout/clock_style_option.xml b/res/layout/clock_style_option.xml
new file mode 100644
index 0000000..27fe597
--- /dev/null
+++ b/res/layout/clock_style_option.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Content description is set programmatically on the parent FrameLayout -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/floating_sheet_clock_style_option_size"
+    android:layout_height="@dimen/floating_sheet_clock_style_option_size"
+    android:clipChildren="false">
+
+    <ImageView
+        android:id="@id/selection_border"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/option_item_border"
+        android:alpha="0"
+        android:importantForAccessibility="no" />
+
+    <ImageView
+        android:id="@id/background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/option_item_background"
+        android:importantForAccessibility="no" />
+
+    <FrameLayout
+        android:id="@+id/foreground"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <ImageView
+            android:id="@+id/clock_icon"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="@dimen/floating_sheet_clock_style_thumbnail_margin"
+            android:src="@drawable/ic_clock_24px" />
+
+        <ImageView
+            android:id="@+id/edit_icon"
+            android:layout_width="@dimen/floating_sheet_clock_edit_icon_size"
+            android:layout_height="@dimen/floating_sheet_clock_edit_icon_size"
+            android:layout_marginTop="-16dp"
+            android:layout_marginLeft="50dp"
+            android:src="@drawable/edit_icon"/>
+
+    </FrameLayout>
+</FrameLayout>
+
diff --git a/res/layout/clock_style_option2.xml b/res/layout/clock_style_option2.xml
new file mode 100644
index 0000000..8bb60d1
--- /dev/null
+++ b/res/layout/clock_style_option2.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Content description is set programmatically on the parent FrameLayout -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="80dp"
+    android:layout_height="80dp"
+    android:clipToPadding="false"
+    android:clipChildren="false">
+
+    <com.android.wallpaper.picker.option.ui.view.OptionItemBackground
+        android:id="@id/background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:importantForAccessibility="no" />
+
+    <ImageView
+        android:id="@+id/foreground"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="@dimen/floating_sheet_clock_style_thumbnail_margin"
+        android:src="@drawable/ic_clock_24px" />
+
+    <ImageView
+        android:id="@+id/edit_icon"
+        android:layout_width="@dimen/floating_sheet_clock_edit_icon_size"
+        android:layout_height="@dimen/floating_sheet_clock_edit_icon_size"
+        android:layout_marginTop="-16dp"
+        android:layout_marginStart="50dp"
+        android:src="@drawable/edit_icon"
+        android:importantForAccessibility="no" />
+</FrameLayout>
+
diff --git a/res/layout/color_option2.xml b/res/layout/color_option2.xml
new file mode 100644
index 0000000..2605da9
--- /dev/null
+++ b/res/layout/color_option2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Content description is set programmatically on the parent FrameLayout -->
+<com.android.customization.picker.color.ui.view.ColorOptionIconView2
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@id/background"
+    android:layout_width="@dimen/floating_sheet_color_option_size"
+    android:layout_height="@dimen/floating_sheet_color_option_size"/>
+
diff --git a/res/layout/color_section_view.xml b/res/layout/color_section_view.xml
index cfa9be3..e50a351 100644
--- a/res/layout/color_section_view.xml
+++ b/res/layout/color_section_view.xml
@@ -37,7 +37,6 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        android:paddingVertical="20dp"
         android:paddingHorizontal="24dp"
         android:weightSum="@integer/color_section_num_columns">
         <include
@@ -53,8 +52,8 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
-        android:layout_marginTop="10dp"
-        android:minHeight="48dp"
+        android:minHeight="24dp"
+        android:paddingVertical="16dp"
         android:gravity="center"
         android:drawablePadding="12dp"
         android:drawableStart="@drawable/ic_nav_color"
diff --git a/res/layout/customization_option_entry_app_shape.xml b/res/layout/customization_option_entry_app_shape.xml
deleted file mode 100644
index 66d9b07..0000000
--- a/res/layout/customization_option_entry_app_shape.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright (C) 2024 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<androidx.constraintlayout.widget.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:paddingHorizontal="@dimen/customization_option_entry_horizontal_padding"
-    android:paddingVertical="@dimen/customization_option_entry_vertical_padding"
-    android:clickable="true">
-
-    <TextView
-        style="@style/SectionTitleTextStyle"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:text="@string/preview_name_shape"
-        android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@+id/option_entry_app_shape_icon"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintVertical_chainStyle="packed" />
-
-    <FrameLayout
-        android:id="@+id/option_entry_app_shape_icon"
-        android:layout_width="@dimen/customization_option_entry_icon_size"
-        android:layout_height="@dimen/customization_option_entry_icon_size"
-        android:orientation="horizontal"
-        android:background="@drawable/customization_option_entry_icon_background"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent" />
-</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/res/layout/customization_option_entry_app_grid.xml b/res/layout/customization_option_entry_app_shape_grid.xml
similarity index 73%
rename from res/layout/customization_option_entry_app_grid.xml
rename to res/layout/customization_option_entry_app_shape_grid.xml
index bc8b8fd..8d18e7c 100644
--- a/res/layout/customization_option_entry_app_grid.xml
+++ b/res/layout/customization_option_entry_app_shape_grid.xml
@@ -24,37 +24,43 @@
     android:clickable="true">
 
     <TextView
-        android:id="@+id/option_entry_app_grid_title"
-        style="@style/SectionTitleTextStyle"
+        android:id="@+id/option_entry_app_shape_grid_title"
+        style="@style/CustomizationOptionEntryTitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:text="@string/grid_title"
+        android:text="@string/shape_and_grid_title"
         android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon"
-        app:layout_constraintBottom_toTopOf="@+id/option_entry_app_grid_description"
+        app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon_container"
+        app:layout_constraintBottom_toTopOf="@+id/option_entry_app_shape_grid_description"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintVertical_chainStyle="packed" />
 
     <TextView
-        android:id="@+id/option_entry_app_grid_description"
-        style="@style/SectionSubtitleTextStyle"
+        android:id="@+id/option_entry_app_shape_grid_description"
+        style="@style/CustomizationOptionEntrySubtitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end"
-        android:text="4x4"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon"
+        app:layout_constraintEnd_toStartOf="@+id/option_entry_app_grid_icon_container"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@+id/option_entry_app_grid_title" />
+        app:layout_constraintTop_toBottomOf="@+id/option_entry_app_shape_grid_title" />
 
     <FrameLayout
-        android:id="@+id/option_entry_app_grid_icon"
+        android:id="@+id/option_entry_app_grid_icon_container"
         android:layout_width="@dimen/customization_option_entry_icon_size"
         android:layout_height="@dimen/customization_option_entry_icon_size"
-        android:orientation="horizontal"
+        android:padding="@dimen/customization_option_entry_icon_padding"
         android:background="@drawable/customization_option_entry_icon_background"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent" />
+        app:layout_constraintBottom_toBottomOf="parent">
+
+        <ImageView
+            android:id="@+id/option_entry_app_shape_grid_icon"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:contentDescription="@string/grid_preview_card_content_description" />
+    </FrameLayout>
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/res/layout/customization_option_entry_clock.xml b/res/layout/customization_option_entry_clock.xml
index 4c56916..c302965 100644
--- a/res/layout/customization_option_entry_clock.xml
+++ b/res/layout/customization_option_entry_clock.xml
@@ -24,7 +24,7 @@
     android:clickable="true">
 
     <TextView
-        style="@style/SectionTitleTextStyle"
+        style="@style/CustomizationOptionEntryTitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:text="@string/clock_title"
diff --git a/res/layout/customization_option_entry_colors.xml b/res/layout/customization_option_entry_colors.xml
index cd32e74..3046173 100644
--- a/res/layout/customization_option_entry_colors.xml
+++ b/res/layout/customization_option_entry_colors.xml
@@ -24,7 +24,7 @@
     android:clickable="true">
 
     <TextView
-        style="@style/SectionTitleTextStyle"
+        style="@style/CustomizationOptionEntryTitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:text="@string/color_picker_title"
diff --git a/res/layout/customization_option_entry_keyguard_quick_affordance.xml b/res/layout/customization_option_entry_keyguard_quick_affordance.xml
index aa8152d..d4d30dd 100644
--- a/res/layout/customization_option_entry_keyguard_quick_affordance.xml
+++ b/res/layout/customization_option_entry_keyguard_quick_affordance.xml
@@ -26,7 +26,7 @@
 
     <TextView
         android:id="@+id/option_entry_keyguard_quick_affordance_title"
-        style="@style/SectionTitleTextStyle"
+        style="@style/CustomizationOptionEntryTitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:text="@string/keyguard_quick_affordance_title"
@@ -39,7 +39,7 @@
 
     <TextView
         android:id="@+id/option_entry_keyguard_quick_affordance_description"
-        style="@style/SectionSubtitleTextStyle"
+        style="@style/CustomizationOptionEntrySubtitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end"
@@ -56,8 +56,8 @@
         android:layout_height="@dimen/customization_option_entry_icon_size"
         android:orientation="horizontal"
         android:background="@drawable/customization_option_entry_icon_background"
-        android:divider="@drawable/horizontal_divider_14dp"
-        android:layout_gravity="center"
+        android:gravity="center"
+        android:divider="@drawable/horizontal_divider_4dp"
         android:showDividers="middle"
         android:importantForAccessibility="noHideDescendants"
         app:layout_constraintEnd_toEndOf="parent"
@@ -66,15 +66,15 @@
 
         <ImageView
             android:id="@+id/option_entry_keyguard_quick_affordance_icon_1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_width="@dimen/customization_option_entry_shortcut_icon_size"
+            android:layout_height="@dimen/customization_option_entry_shortcut_icon_size"
             android:visibility="gone"
             android:tint="@color/system_on_surface" />
 
         <ImageView
             android:id="@+id/option_entry_keyguard_quick_affordance_icon_2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_width="@dimen/customization_option_entry_shortcut_icon_size"
+            android:layout_height="@dimen/customization_option_entry_shortcut_icon_size"
             android:visibility="gone"
             android:tint="@color/system_on_surface" />
     </LinearLayout>
diff --git a/res/layout/customization_option_entry_more_lock_settings.xml b/res/layout/customization_option_entry_more_lock_settings.xml
index 6ddbe7e..518af78 100644
--- a/res/layout/customization_option_entry_more_lock_settings.xml
+++ b/res/layout/customization_option_entry_more_lock_settings.xml
@@ -20,12 +20,12 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingHorizontal="@dimen/customization_option_entry_horizontal_padding"
-    android:paddingVertical="@dimen/customization_option_entry_vertical_padding"
+    android:paddingVertical="@dimen/customization_option_entry_vertical_padding_large"
     android:clickable="true">
 
     <TextView
         android:id="@+id/option_entry_more_lock_settings_title"
-        style="@style/SectionTitleTextStyle"
+        style="@style/CustomizationOptionEntryTitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:text="@string/more_settings_section_title"
@@ -37,7 +37,7 @@
 
     <TextView
         android:id="@+id/option_entry_more_lock_settings_description"
-        style="@style/SectionSubtitleTextStyle"
+        style="@style/CustomizationOptionEntrySubtitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:text="@string/more_settings_section_description"
diff --git a/res/layout/customization_option_entry_show_notifications.xml b/res/layout/customization_option_entry_show_notifications.xml
index 2a482e8..b067131 100644
--- a/res/layout/customization_option_entry_show_notifications.xml
+++ b/res/layout/customization_option_entry_show_notifications.xml
@@ -21,11 +21,11 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingHorizontal="@dimen/customization_option_entry_horizontal_padding"
-    android:paddingVertical="@dimen/customization_option_entry_vertical_padding"
+    android:paddingVertical="@dimen/customization_option_entry_vertical_padding_large"
     android:clickable="true">
 
     <TextView
-        style="@style/SectionTitleTextStyle"
+        style="@style/CustomizationOptionEntryTitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:text="@string/show_notifications_on_lock_screen"
diff --git a/res/layout/customization_option_entry_themed_icons.xml b/res/layout/customization_option_entry_themed_icons.xml
index 683fb0a..06461dc 100644
--- a/res/layout/customization_option_entry_themed_icons.xml
+++ b/res/layout/customization_option_entry_themed_icons.xml
@@ -21,12 +21,12 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingHorizontal="@dimen/customization_option_entry_horizontal_padding"
-    android:paddingVertical="@dimen/customization_option_entry_vertical_padding"
+    android:paddingVertical="@dimen/customization_option_entry_vertical_padding_large"
     android:clickable="true">
 
     <TextView
         android:id="@+id/option_entry_themed_icons_title"
-        style="@style/SectionTitleTextStyle"
+        style="@style/CustomizationOptionEntryTitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:text="@string/themed_icon_title"
@@ -39,7 +39,7 @@
 
     <TextView
         android:id="@+id/option_entry_themed_icons_description"
-        style="@style/SectionSubtitleTextStyle"
+        style="@style/CustomizationOptionEntrySubtitleTextStyle"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/customization_option_entry_text_margin_end"
diff --git a/res/layout/floating_sheet_clock.xml b/res/layout/floating_sheet_clock.xml
new file mode 100644
index 0000000..cdaf3de
--- /dev/null
+++ b/res/layout/floating_sheet_clock.xml
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:paddingHorizontal="@dimen/floating_sheet_horizontal_padding"
+    android:orientation="vertical">
+
+    <FrameLayout
+        android:id="@+id/clock_floating_sheet_content_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingVertical="@dimen/floating_sheet_content_vertical_padding"
+        android:background="@drawable/floating_sheet_content_background"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/clock_floating_sheet_style_content"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false"
+            android:clipChildren="false">
+
+            <FrameLayout
+                android:id="@+id/clock_style_list_container"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toTopOf="@+id/clock_style_clock_size_title"
+                android:layout_marginBottom="8dp"
+                android:clipToPadding="false"
+                android:clipChildren="false">
+
+                <!--
+                This is an invisible placeholder put in place so that the parent keeps its height
+                stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows
+                the layout logic to keep the size of the preview container stable as well, which
+                bodes well for setting up the SurfaceView for remote rendering without changing its
+                size after the content is loaded into the RecyclerView.
+
+                It's critical for any TextViews inside the included layout to have text.
+                -->
+                <include
+                    layout="@layout/clock_style_option"
+                    android:layout_width="@dimen/floating_sheet_clock_style_option_size"
+                    android:layout_height="@dimen/floating_sheet_clock_style_option_size"
+                    android:visibility="invisible" />
+
+                <!--
+                TODO (b/377528523): We intentionally disable over scroll mode since it will clip the
+                  edit icon when in over scroll.
+                -->
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/clock_style_list"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:overScrollMode="never"
+                    android:clipChildren="false"
+                    android:clipToPadding="false"/>
+            </FrameLayout>
+
+            <TextView
+                android:id="@+id/clock_style_clock_size_title"
+                style="@style/CustomizationOptionEntryTitleTextStyle"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:text="@string/clock_size_large"
+                android:layout_marginStart="@dimen/floating_sheet_content_horizontal_padding"
+                android:layout_marginEnd="@dimen/floating_sheet_clock_style_clock_size_text_margin_end"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toStartOf="@+id/clock_style_clock_size_switch"
+                app:layout_constraintTop_toBottomOf="@+id/clock_style_list_container"
+                app:layout_constraintBottom_toTopOf="@+id/clock_style_clock_size_description" />
+
+            <TextView
+                android:id="@+id/clock_style_clock_size_description"
+                style="@style/CustomizationOptionEntrySubtitleTextStyle"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/floating_sheet_content_horizontal_padding"
+                android:layout_marginEnd="@dimen/floating_sheet_clock_style_clock_size_text_margin_end"
+                android:text="@string/clock_size_dynamic_description"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toStartOf="@+id/clock_style_clock_size_switch"
+                app:layout_constraintTop_toBottomOf="@+id/clock_style_clock_size_title"
+                app:layout_constraintBottom_toBottomOf="parent" />
+
+            <Switch
+                android:id="@+id/clock_style_clock_size_switch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="@dimen/floating_sheet_content_horizontal_padding"
+                app:layout_constraintTop_toTopOf="@+id/clock_style_clock_size_title"
+                app:layout_constraintBottom_toBottomOf="@+id/clock_style_clock_size_description"
+                app:layout_constraintEnd_toEndOf="parent"
+                style="@style/Switch.SettingsLib"
+                tools:ignore="UseSwitchCompatOrMaterialXml" />
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <LinearLayout
+            android:id="@+id/clock_floating_sheet_color_content"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:clipToPadding="false"
+            android:clipChildren="false">
+
+            <FrameLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:clipToPadding="false"
+                android:clipChildren="false"
+                android:layout_marginBottom="12dp">
+
+                <!--
+                This is an invisible placeholder put in place so that the parent keeps its height
+                stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows
+                the layout logic to keep the size of the preview container stable as well, which
+                bodes well for setting up the SurfaceView for remote rendering without changing its
+                size after the content is loaded into the RecyclerView.
+
+                It's critical for any TextViews inside the included layout to have text.
+                -->
+                <include
+                    layout="@layout/color_option"
+                    android:layout_width="@dimen/option_item_size"
+                    android:layout_height="@dimen/option_item_size"
+                    android:visibility="invisible" />
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/clock_color_list"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:clipChildren="false"
+                    android:clipToPadding="false" />
+            </FrameLayout>
+
+            <SeekBar
+                android:id="@+id/clock_color_slider"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:paddingHorizontal="@dimen/floating_sheet_content_horizontal_padding"
+                android:minHeight="@dimen/touch_target_min_height"
+                android:thumb="@null"
+                android:contentDescription="@string/accessibility_clock_slider_description"
+                android:background="@null"
+                android:progressDrawable="@drawable/saturation_progress_drawable"
+                android:splitTrack="false" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/clock_floating_sheet_font_content"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingHorizontal="@dimen/floating_sheet_content_horizontal_padding"
+            android:orientation="vertical"
+            android:clipToPadding="false"
+            android:clipChildren="false">
+
+            <!-- Populated dynamically w/ clock axis information -->
+        </LinearLayout>
+    </FrameLayout>
+
+    <com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
+        android:id="@+id/floating_toolbar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginVertical="@dimen/floating_sheet_tab_toolbar_vertical_margin" />
+
+    <LinearLayout
+        android:id="@+id/clock_font_toolbar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/floating_sheet_tab_clock_font_toolbar_top_margin"
+        android:layout_marginBottom="@dimen/floating_sheet_tab_clock_font_toolbar_bottom_margin">
+
+        <ImageView
+            android:id="@+id/clock_font_revert"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/clock_font_revert"
+            android:contentDescription="@string/clock_font_editor_revert" />
+
+        <ImageView
+            android:id="@+id/clock_font_apply"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="@dimen/clock_font_apply_padding_start"
+            android:src="@drawable/clock_font_apply"
+            android:contentDescription="@string/clock_font_editor_apply" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/floating_sheet_colors.xml b/res/layout/floating_sheet_colors.xml
new file mode 100644
index 0000000..f8cfc98
--- /dev/null
+++ b/res/layout/floating_sheet_colors.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingHorizontal="@dimen/floating_sheet_horizontal_padding"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/floating_sheet_content_background"
+        android:paddingVertical="@dimen/floating_sheet_content_vertical_padding"
+        android:orientation="vertical"
+        android:clipChildren="false">
+
+        <TextView
+            android:id="@+id/color_type_tab_subhead"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            android:layout_marginHorizontal="20dp"
+            android:gravity="center"
+            android:text="@string/wallpaper_color_subheader"
+            android:textColor="@color/system_on_surface"
+            android:textSize="12sp" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/colors_horizontal_list"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="12dp"
+            android:clipChildren="false"
+            android:clipToPadding="false" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clickable="true"
+            android:gravity="center_vertical"
+            android:layout_marginHorizontal="@dimen/floating_sheet_content_horizontal_padding"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/dark_mode_toggle_title"
+                style="@style/SectionTitleTextStyle"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/mode_title" />
+
+            <Switch
+                android:id="@+id/dark_mode_toggle"
+                style="@style/Switch.SettingsLib"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@null"
+                android:focusable="false"
+                android:minHeight="0dp" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
+        android:id="@+id/floating_toolbar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginVertical="@dimen/floating_sheet_tab_toolbar_vertical_margin"  />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/floating_sheet_shape_grid.xml b/res/layout/floating_sheet_shape_grid.xml
new file mode 100644
index 0000000..4e2409b
--- /dev/null
+++ b/res/layout/floating_sheet_shape_grid.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingHorizontal="@dimen/floating_sheet_horizontal_padding"
+    android:orientation="vertical">
+
+    <FrameLayout
+        android:id="@+id/shape_grid_floating_sheet_content_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/floating_sheet_content_background"
+        android:paddingVertical="@dimen/floating_sheet_content_vertical_padding"
+        android:orientation="vertical"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <FrameLayout
+            android:id="@+id/app_shape_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false"
+            android:clipChildren="false">
+
+            <!--
+            This is just an invisible placeholder put in place so that the parent keeps its height
+            stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the
+            layout logic to keep the size of the preview container stable as well, which bodes well
+            for setting up the SurfaceView for remote rendering without changing its size after the
+            content is loaded into the RecyclerView.
+
+            It's critical for any TextViews inside the included layout to have text.
+            -->
+            <include
+                layout="@layout/shape_option"
+                android:layout_width="64dp"
+                android:layout_height="64dp"
+                android:visibility="invisible" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/shape_options"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:clipToPadding="false"
+                android:clipChildren="false" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:id="@+id/app_grid_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false"
+            android:clipChildren="false">
+
+            <!--
+            This is just an invisible placeholder put in place so that the parent keeps its height
+            stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the
+            layout logic to keep the size of the preview container stable as well, which bodes well
+            for setting up the SurfaceView for remote rendering without changing its size after the
+            content is loaded into the RecyclerView.
+
+            It's critical for any TextViews inside the included layout to have text.
+            -->
+            <include
+                layout="@layout/grid_option"
+                android:id="@+id/invisible_grid_option"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="invisible"/>
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/grid_options"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:clipToPadding="false"
+                android:clipChildren="false"
+                android:layout_gravity="center_horizontal" />
+        </FrameLayout>
+    </FrameLayout>
+
+    <com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
+        android:id="@+id/floating_toolbar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginVertical="@dimen/floating_sheet_tab_toolbar_vertical_margin" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/floating_sheet_shortcut.xml b/res/layout/floating_sheet_shortcut.xml
new file mode 100644
index 0000000..fb24ef4
--- /dev/null
+++ b/res/layout/floating_sheet_shortcut.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingHorizontal="@dimen/floating_sheet_horizontal_padding"
+    android:orientation="vertical">
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingVertical="@dimen/floating_sheet_content_vertical_padding"
+        android:background="@drawable/floating_sheet_content_background"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/quick_affordance_horizontal_list"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:clipChildren="false"
+            android:clipToPadding="false"/>
+    </FrameLayout>
+
+    <com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
+        android:id="@+id/floating_toolbar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginVertical="@dimen/floating_sheet_tab_toolbar_vertical_margin" />
+</LinearLayout>
diff --git a/res/layout/fragment_clock_picker.xml b/res/layout/fragment_clock_picker.xml
index 8ca4863..ee4a24d 100644
--- a/res/layout/fragment_clock_picker.xml
+++ b/res/layout/fragment_clock_picker.xml
@@ -62,10 +62,10 @@
             <Space
                 android:id="@+id/placeholder"
                 android:layout_width="match_parent"
-                android:layout_height="@dimen/min_taptarget_height"
+                android:layout_height="@dimen/accessibility_min_height"
                 app:layout_constraintBottom_toTopOf="@id/apply_button"
                 app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintHeight_min="@dimen/min_taptarget_height"
+                app:layout_constraintHeight_min="@dimen/accessibility_min_height"
                 app:layout_constraintHorizontal_bias="0.0"
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toBottomOf="@id/options_container"
diff --git a/res/layout/fragment_clock_settings.xml b/res/layout/fragment_clock_settings.xml
index 75dae7e..d6ccaba 100644
--- a/res/layout/fragment_clock_settings.xml
+++ b/res/layout/fragment_clock_settings.xml
@@ -150,7 +150,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_gravity="center_vertical"
-                    android:minHeight="48dp"
+                    android:minHeight="@dimen/accessibility_min_height"
                     android:thumb="@null"
                     android:contentDescription="@string/accessibility_clock_slider_description"
                     android:background="@null"
@@ -169,6 +169,7 @@
                 <RadioButton android:id="@+id/radio_dynamic"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:minHeight="@dimen/accessibility_min_height"
                     android:paddingStart="8dp"
                     android:maxLines="3"
                     android:ellipsize="end"
@@ -178,6 +179,7 @@
                 <RadioButton android:id="@+id/radio_small"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:minHeight="@dimen/accessibility_min_height"
                     android:paddingStart="8dp"
                     android:maxLines="3"
                     android:ellipsize="end"
diff --git a/res/layout/fragment_color_picker.xml b/res/layout/fragment_color_picker.xml
index d33fb1f..7870140 100644
--- a/res/layout/fragment_color_picker.xml
+++ b/res/layout/fragment_color_picker.xml
@@ -44,7 +44,8 @@
             android:id="@+id/lock_preview"
             layout="@layout/wallpaper_preview_card"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="12dp"/>
 
         <include
             android:id="@+id/home_preview"
diff --git a/res/layout/quick_affordance_list_item.xml b/res/layout/quick_affordance_list_item.xml
new file mode 100644
index 0000000..c6b3fd4
--- /dev/null
+++ b/res/layout/quick_affordance_list_item.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="64dp"
+    android:layout_height="wrap_content"
+    android:divider="@drawable/vertical_divider_8dp"
+    android:clipChildren="false"
+    android:showDividers="middle">
+
+    <FrameLayout
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:background="@drawable/option_item_background"
+        android:clipChildren="false">
+
+        <ImageView
+            android:id="@id/selection_border"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/option_item_border"
+            android:alpha="0"
+            android:importantForAccessibility="no" />
+
+        <ImageView
+            android:id="@id/background"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/option_item_background"
+            android:importantForAccessibility="no" />
+
+        <ImageView
+            android:id="@id/foreground"
+            android:layout_width="@dimen/keyguard_quick_affordance_icon_size"
+            android:layout_height="@dimen/keyguard_quick_affordance_icon_size"
+            android:layout_gravity="center"
+            android:tint="@color/system_on_surface" />
+    </FrameLayout>
+
+    <TextView
+        android:id="@id/text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_horizontal"
+        android:textColor="@color/system_on_surface"
+        android:lines="2"
+        android:hyphenationFrequency="normal"
+        android:ellipsize="end" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/quick_affordance_list_item2.xml b/res/layout/quick_affordance_list_item2.xml
new file mode 100644
index 0000000..9dd7557
--- /dev/null
+++ b/res/layout/quick_affordance_list_item2.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/keyguard_quick_affordance_background_size"
+    android:layout_height="wrap_content"
+    android:clipChildren="false">
+
+    <com.android.wallpaper.picker.option.ui.view.OptionItemBackground
+        android:id="@id/background"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/keyguard_quick_affordance_background_size"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/text"
+        android:layout_marginBottom="@dimen/keyguard_quick_affordance_background_margin_bottom"
+        android:importantForAccessibility="no" />
+
+    <ImageView
+        android:id="@id/foreground"
+        android:layout_width="@dimen/keyguard_quick_affordance_icon_size"
+        android:layout_height="@dimen/keyguard_quick_affordance_icon_size"
+        app:layout_constraintStart_toStartOf="@id/background"
+        app:layout_constraintEnd_toEndOf="@id/background"
+        app:layout_constraintTop_toTopOf="@id/background"
+        app:layout_constraintBottom_toBottomOf="@id/background"
+        android:tint="@color/system_on_surface"
+        android:importantForAccessibility="no" />
+
+    <TextView
+        android:id="@id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/background"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:gravity="center_horizontal"
+        android:textColor="@color/system_on_surface"
+        android:lines="2"
+        android:hyphenationFrequency="normal"
+        android:ellipsize="end" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/res/layout/shape_option.xml b/res/layout/shape_option.xml
new file mode 100644
index 0000000..d2eb2f2
--- /dev/null
+++ b/res/layout/shape_option.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:clipChildren="false">
+
+    <ImageView
+        android:id="@id/selection_border"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/option_item_border"
+        android:alpha="0"
+        android:importantForAccessibility="no" />
+
+    <ImageView
+        android:id="@id/background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/option_item_background"
+        android:importantForAccessibility="no" />
+
+    <ImageView
+        android:id="@id/foreground"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:layout_gravity="center" />
+</FrameLayout>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index adaa3b9..40b79d9 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Horlosiekleur en -grootte"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Horlosiekleur en -grootte"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Styl"</string>
     <string name="clock_color" msgid="8081608867289156163">"Kleur"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rooi"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranje"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Groot"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Klein"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"’n Klein horlosie word in die hoek van jou skerm gewys"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Pas horlosiefontveranderinge toe"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Ontdoen horlosiefontveranderinge"</string>
     <string name="grid_title" msgid="1688173478777254123">"Approoster"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Appvorm &amp; uitleg"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Uitleg"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Pas toe"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tik om te wysig"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Hou huidige muurpapier"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index a33a13e..34e22a5 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"የClock ቀለም እና መጠን"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"የClock ቀለም እና መጠን"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>፣ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"ቅጥ"</string>
     <string name="clock_color" msgid="8081608867289156163">"ቀለም"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ቀይ"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ብርቱካናማ"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ትልቅ"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"ትንሽ"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"በእርስዎ ማያ ገፅ ጥግ ላይ ትንሽ ሰዓት ይታያል"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"የሰዓት ቅርጸ-ቁምፊ ለውጦችን ተግብር"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"የሰዓት ቅርጸ-ቁምፊ ለውጦችን ቀልብስ"</string>
     <string name="grid_title" msgid="1688173478777254123">"የመተግበሪያ ፍርግርግ"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"የመተግበሪያ ቅርጽ እና አቀማመጥ"</string>
+    <string name="grid_layout" msgid="370175667652663686">"አቀማመጥ"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"ተግብር"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ለማርትዕ መታ ያድርጉ"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"የአሁኑን ልጣፍ ያቆዩት"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 536dc3b..188564c 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"لون الساعة وحجمها"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"لون الساعة وحجمها"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g> و<xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"النمط"</string>
     <string name="clock_color" msgid="8081608867289156163">"اللون"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"أحمر"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"برتقالي"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"كبير"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"صغير"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"تظهر ساعة صغيرة في زاوية الشاشة"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"تطبيق التغييرات على خط الساعة"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"التراجع عن التغييرات على خط الساعة"</string>
     <string name="grid_title" msgid="1688173478777254123">"شبكة التطبيقات"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"شكل التطبيق وتصميمه"</string>
+    <string name="grid_layout" msgid="370175667652663686">"التصميم"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"تطبيق"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"انقُر للتعديل."</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"الاحتفاظ بالخلفية الحالية"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 2d8b529..0091ff3 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ঘড়ীৰ ৰং আৰু আকাৰ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ঘড়ীৰ ৰং আৰু আকাৰ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"শৈলী"</string>
     <string name="clock_color" msgid="8081608867289156163">"ৰং"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ৰঙা"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"কমলা"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ডাঙৰ"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"সৰু"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"আপোনাৰ স্ক্ৰীনখনৰ চুকত এটা সৰু ঘড়ীয়ে দেখুৱায়"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ঘড়ীৰ ফণ্টত কৰা সালসলনি প্ৰয়োগ কৰক"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ঘড়ীৰ ফণ্টত কৰা সালসলনি আনডু কৰক"</string>
     <string name="grid_title" msgid="1688173478777254123">"এপৰ গ্ৰিড"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"এপৰ আকৃতি আৰু লে’আউট"</string>
+    <string name="grid_layout" msgid="370175667652663686">"লে’আউট"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"প্ৰয়োগ কৰক"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"সম্পাদনা কৰিবলৈ টিপক"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"বৰ্তমানৰ ৱালপেপাৰখন ৰাখক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index b6d1f55..e64868d 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Saat rəngi və ölçü"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Saat rəngi və ölçüsü"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Üslub"</string>
     <string name="clock_color" msgid="8081608867289156163">"Rəng"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Qırmızı"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Narıncı"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Böyük"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Kiçik"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Ekranın mərkəzində kiçik saat görünür"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Saat şrifti dəyişikliklərini tətbiq edin"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Saat şrifti dəyişikliklərini geri qaytarın"</string>
     <string name="grid_title" msgid="1688173478777254123">"Tətbiq toru"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Tətbiq forması və düzən"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Düzən"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Tətbiq edin"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Redaktə etmək üçün klikləyin"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Cari divar kağızını saxlayın"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 6b6293e..b52cbf2 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Boja i veličina sata"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Boja i veličina sata"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Boja"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Crvena"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Narandžasta"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Veliko"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Mali"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Mali sat se prikazuje u uglu ekrana"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Primenite promene fonta sata"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Opozovite promene fonta sata"</string>
     <string name="grid_title" msgid="1688173478777254123">"Mreža apl."</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Oblik i izgled"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Izgled"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Primeni"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Dodirnite da biste izmenili"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Zadrži aktuelnu pozadinu"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 6b2b474..324a0a3 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Колер/памер гадз-ка"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Колер і памер гадзінніка"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Стыль"</string>
     <string name="clock_color" msgid="8081608867289156163">"Колер"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Чырвоны"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Аранжавы"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Вялікі"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Дробны"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Невялікі гадзіннік у вугле экрана"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Прымяніць змяненні шрыфту гадзінніка"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Адрабіць змяненні шрыфту гадзінніка"</string>
     <string name="grid_title" msgid="1688173478777254123">"Сетка праграм"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Форма і кампаноўка праграмы"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Макет"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Ужыць"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Дакраніцеся, каб рэдагаваць"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Захаваць бягучыя шпалеры"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 051cd35..78046eb 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Часовн.: Цвят и размер"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Часовн.: Цвят и размер"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Стил"</string>
     <string name="clock_color" msgid="8081608867289156163">"Цвят"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"червено"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"оранжево"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Голям"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Малък"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"В ъгъла на екрана се показва малък часовник"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Прилагане на промените на шрифта на часовника"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Отмяна на промените на шрифта на часовника"</string>
     <string name="grid_title" msgid="1688173478777254123">"Решетка с прил."</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Оформление и форма"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Оформление"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Прилагане"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Докоснете, за да редактирате"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Запазване на текущия тапет"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index e419aac..bc15b9a 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ঘড়ির রঙ &amp; সাইজ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ঘড়ির রঙ ও সাইজ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"স্টাইল"</string>
     <string name="clock_color" msgid="8081608867289156163">"রঙ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"লাল"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"কমলা"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"বড়"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"ছোট করুন"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"স্ক্রিনের কোনায় একটি ছোট ঘড়ি দেখানো হয়"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ঘড়ির ফন্ট পরিবর্তন প্রয়োগ করুন"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ঘড়ির ফন্ট পরিবর্তনকে আগের অবস্থায় ফিরিয়ে আনুন"</string>
     <string name="grid_title" msgid="1688173478777254123">"অ্যাপ গ্রিড"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"অ্যাপ শেপ ও লেআউট"</string>
+    <string name="grid_layout" msgid="370175667652663686">"লেআউট"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"প্রয়োগ করুন"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"এডিট করতে ট্যাপ করুন"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"এখন যে ওয়ালপেপার আছে সেটি রাখুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index e25a69a..fae80c2 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Boja i veličina sata"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Boja i veličina sata"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Boja"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Crvena"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Narandžasta"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Veliko"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Malo"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Mali sat se prikazuje u uglu vašeg ekrana"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Primjena promjena fonta na satu"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Poništavanje promjena fonta na satu"</string>
     <string name="grid_title" msgid="1688173478777254123">"Mreža aplikacija"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Oblik i raspored apl."</string>
+    <string name="grid_layout" msgid="370175667652663686">"Raspored"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Primijeni"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Dodirnite da uredite"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Zadrži trenutnu pozadinsku sliku"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index b37ddd8..c9f1d4e 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Color i mida rellotge"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Color i mida del rellotge"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Estil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Color"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Vermell"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Taronja"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Gran"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Petit"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Es mostra un rellotge petit a l\'extrem de la pantalla"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Aplica els canvis de font del rellotge"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Desfés els canvis de font del rellotge"</string>
     <string name="grid_title" msgid="1688173478777254123">"Quadrícula d\'apps"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Forma i disseny d\'app"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Disseny"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Aplica"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Toca per editar"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Mantén el fons de pantalla actual"</string>
@@ -73,7 +78,7 @@
     <string name="applied_theme_msg" msgid="3749018706366796244">"L\'estil s\'ha definit correctament"</string>
     <string name="applied_clock_msg" msgid="1303338016701443767">"El rellotge s\'ha definit correctament"</string>
     <string name="applied_grid_msg" msgid="3250499654436933034">"La quadrícula s\'ha definit correctament"</string>
-    <string name="apply_theme_error_msg" msgid="791364062636538317">"S\'ha produït un error en aplicar l\'estil"</string>
+    <string name="apply_theme_error_msg" msgid="791364062636538317">"Hi ha hagut un error en aplicar l\'estil"</string>
     <string name="custom_theme_next" msgid="6235420097213197301">"Següent"</string>
     <string name="custom_theme_previous" msgid="4941132112640503022">"Anterior"</string>
     <string name="custom_theme" msgid="1618351922263478163">"Personalitzat"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index ffe69a4..9dd309f 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Barva a velikost"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Barva a velikost"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Styl"</string>
     <string name="clock_color" msgid="8081608867289156163">"Barva"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Červená"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranžová"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Velká"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Malá"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"V rohu obrazovky se zobrazují malé hodiny"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Použít změny písma hodin"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Vrátit změny písma hodin zpět"</string>
     <string name="grid_title" msgid="1688173478777254123">"Mřížka aplikací"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Tvar a rovrž."</string>
+    <string name="grid_layout" msgid="370175667652663686">"Rozvržení"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Použít"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Klepnutím upravte"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Zachovat stávající tapetu"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index d99847b..ed25013 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Urets farve og str."</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Urets farve og størrelse"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Farve"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rød"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Stor"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Lille"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Et lille ur vises i hjørnet af skærmen"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Anvend ændringerne af urets skrifttype"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Fortryd ændringerne af urets skrifttype"</string>
     <string name="grid_title" msgid="1688173478777254123">"Appgitter"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Appform og layout"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Anvend"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tryk for at redigere"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Behold den aktuelle baggrund"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index be98c62..6a07aaf 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Uhr-Farbe &amp; -Größe"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Uhr-Farbe und -Größe"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Farbe"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rot"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Groß"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Klein"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Eine kleine Uhr wird in der Ecke des Displays angezeigt"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Uhr-Schriftart ändern"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Änderungen an Uhr-Schriftart rückgängig machen"</string>
     <string name="grid_title" msgid="1688173478777254123">"App-Raster"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Formen &amp; Layouts"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Anwenden"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Zum Bearbeiten tippen"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Aktuellen Hintergrund behalten"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index d9ce549..a746f7c 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Χρώμα/μέγεθ. ρολογ."</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Χρώμα και μέγεθος"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Στιλ"</string>
     <string name="clock_color" msgid="8081608867289156163">"Χρώμα"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Κόκκινο"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Πορτοκαλί"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Μεγάλο"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Μικρό"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Ένα μικρό ρολόι εμφανίζεται στη γωνία της οθόνης"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Εφαρμογή αλλαγών στη γραμματοσειρά ρολογιού"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Αναίρεση αλλαγών στη γραμματοσειρά ρολογιού"</string>
     <string name="grid_title" msgid="1688173478777254123">"Πλέγμα εφαρμ."</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Σχήμα, διάταξη"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Διάταξη"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Εφαρμογή"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Πατήστε για επεξεργασία"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Διατήρηση τρέχουσας ταπετσαρίας"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 33de28b..7ac8939 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Clock colour &amp; size"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Clock colour and size"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Style"</string>
     <string name="clock_color" msgid="8081608867289156163">"Colour"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Red"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Large"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Small"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"A small clock shows in the corner of your screen"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Apply clock font changes"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Undo clock font changes"</string>
     <string name="grid_title" msgid="1688173478777254123">"App grid"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"App shape and layout"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Apply"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tap to edit"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Keep current wallpaper"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index b256398..06b00ac 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Clock color &amp; size"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Clock color &amp; size"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Style"</string>
     <string name="clock_color" msgid="8081608867289156163">"Color"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Red"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Large"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Small"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"A small clock shows in the corner of your screen"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Apply clock font changes"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Undo clock font changes"</string>
     <string name="grid_title" msgid="1688173478777254123">"App grid"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"App shape &amp; layout"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Apply"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tap to edit"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Keep current wallpaper"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 33de28b..7ac8939 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Clock colour &amp; size"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Clock colour and size"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Style"</string>
     <string name="clock_color" msgid="8081608867289156163">"Colour"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Red"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Large"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Small"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"A small clock shows in the corner of your screen"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Apply clock font changes"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Undo clock font changes"</string>
     <string name="grid_title" msgid="1688173478777254123">"App grid"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"App shape and layout"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Apply"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tap to edit"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Keep current wallpaper"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 33de28b..7ac8939 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Clock colour &amp; size"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Clock colour and size"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Style"</string>
     <string name="clock_color" msgid="8081608867289156163">"Colour"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Red"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Large"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Small"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"A small clock shows in the corner of your screen"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Apply clock font changes"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Undo clock font changes"</string>
     <string name="grid_title" msgid="1688173478777254123">"App grid"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"App shape and layout"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Apply"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tap to edit"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Keep current wallpaper"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index b6f48d3..07b3146 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎Clock color &amp; size‎‏‎‎‏‎"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎Clock color &amp; size‎‏‎‎‏‎"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="ID_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎<xliff:g id="ID_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="clock_style" msgid="6847711178193804308">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‎‎‎Style‎‏‎‎‏‎"</string>
     <string name="clock_color" msgid="8081608867289156163">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎Color‎‏‎‎‏‎"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎Red‎‏‎‎‏‎"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎Orange‎‏‎‎‏‎"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 318e844..64e3d25 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Color, tamaño de reloj"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Reloj: color, tamaño"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Estilo"</string>
     <string name="clock_color" msgid="8081608867289156163">"Color"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rojo"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Naranja"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Grande"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Pequeño"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Aparece un reloj pequeño en la esquina de tu pantalla"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Aplica cambios a la fuente del reloj"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Deshace cambios a la fuente del reloj"</string>
     <string name="grid_title" msgid="1688173478777254123">"Cuadrícula de apps"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Forma y diseño"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Diseño"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Aplicar"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Presiona para editar"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Conservar fondo de pantalla actual"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index ecb4e04..b619024 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Color/tamaño (reloj)"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Color y tamaño del reloj"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Estilo"</string>
     <string name="clock_color" msgid="8081608867289156163">"Color"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rojo"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Naranja"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Grande"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Pequeño"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Se muestra un pequeño reloj en la esquina de la pantalla"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Aplicar cambios de fuente del reloj"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Deshacer cambios de fuente del reloj"</string>
     <string name="grid_title" msgid="1688173478777254123">"Cuadrícula de apps"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Forma y diseño"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Diseño"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Aplicar"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Toca para editar"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Mantener fondo de pantalla actual"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 28fefd4..e25e35c 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Kella värv/suurus"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Kella värv ja suurus"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stiil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Värv"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Punane"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranž"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Suur"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Väike"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Ekraaninurgas kuvatakse väike kell"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Kella fondi muudatuste rakendamine"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Kella fondi muudatuste tagasivõtmine"</string>
     <string name="grid_title" msgid="1688173478777254123">"Rak. ruudustik"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Rakenduse kuju ja paigutus"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Paigutus"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Rakenda"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Puudutage muutmiseks"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Säilita praegune taustapilt"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 8c2b406..7d879fa 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Erlojuaren kolorea eta tamaina"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Erlojuaren kolorea eta tamaina"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Estiloa"</string>
     <string name="clock_color" msgid="8081608867289156163">"Kolorea"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Gorria"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Laranja"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Handia"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Txikia"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Erloju txiki bat agertzen da pantailaren izkinan"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Aplikatu erlojuaren letrari dagozkion aldaketak"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Desegin erlojuaren letrari dagozkion aldaketak"</string>
     <string name="grid_title" msgid="1688173478777254123">"Aplikazioen sareta"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Aplikazioaren forma eta diseinua"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Diseinua"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Aplikatu"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Sakatu editatzeko"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Utzi bere horretan horma-papera"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index fa81da6..b9f48b9 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"اندازه و رنگ ساعت"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"اندازه و رنگ ساعت"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>، <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"سبک"</string>
     <string name="clock_color" msgid="8081608867289156163">"رنگ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"قرمز"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"نارنجی"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"بزرگ"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"کوچک"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"ساعت کوچکی در گوشه صفحه‌نمایش شما نشان داده می‌شود"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"اعمال تغییرات قلم ساعت"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"واگرد کردن تغییرات قلم ساعت"</string>
     <string name="grid_title" msgid="1688173478777254123">"شبکه برنامه‌ها"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"شکل و چیدمان برنامه"</string>
+    <string name="grid_layout" msgid="370175667652663686">"چیدمان"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"اعمال"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"برای ویرایش تک‌ضرب بزنید"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"حفظ کاغذدیواری فعلی"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index feaadd3..c936538 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Kellon väri ja koko"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Kellon väri ja koko"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Tyyli"</string>
     <string name="clock_color" msgid="8081608867289156163">"Väri"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Punainen"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranssi"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Suuri"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Pieni"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Näytön reunassa näkyy pieni kello"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Ota kellon fontin muutokset käyttöön"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Kumoa kellon fontin muutokset"</string>
     <string name="grid_title" msgid="1688173478777254123">"Ruudukko"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Muoto ja asettelu"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Asettelu"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Käytä"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Muokkaa napauttamalla"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Säilytä nykyinen taustakuva"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 1d2e3e5..48cdef3 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Couleur/taille"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Couleur/taille (horloge)"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Style"</string>
     <string name="clock_color" msgid="8081608867289156163">"Couleur"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rouge"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Grande"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Petite"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Une petite horloge s\'affiche dans le coin de votre écran"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Appliquer les modifications de la police de l\'horloge"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Annuler les modifications de la police de l\'horloge"</string>
     <string name="grid_title" msgid="1688173478777254123">"Grille d\'applis"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Mise en page"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Mise en page"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Appliquer"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Toucher pour modifier"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Garder le fond d\'écran actuel"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 66eaa2e..612101c 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Taille et couleur de l\'Horloge"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Taille et couleur de l\'horloge"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Style"</string>
     <string name="clock_color" msgid="8081608867289156163">"Couleur"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rouge"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Grande"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Petite"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Une petite horloge s\'affiche dans le coin de votre écran"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Appliquer les modifications de police de l\'horloge"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Annuler les modifications de police de l\'horloge"</string>
     <string name="grid_title" msgid="1688173478777254123">"Grille d\'applis"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Forme et mise en page de l\'appli"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Mise en page"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Appliquer"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Appuyer pour modifier"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Conserver le fond d\'écran actuel"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index beeface..91fdb1a 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Tamaño/cor (Reloxo)"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Tamaño/cor do reloxo"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Estilo"</string>
     <string name="clock_color" msgid="8081608867289156163">"Cor"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Vermello"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Laranxa"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Grande"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Pequeno"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Un pequeno reloxo móstrase na esquina da pantalla"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Aplicar os cambios ao tipo de letra do reloxo"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Desfacer os cambios no tipo de letra do reloxo"</string>
     <string name="grid_title" msgid="1688173478777254123">"Grade de apps"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Deseño e forma"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Deseño"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Aplicar"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Toca para editar"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Conservar fondo de pantalla actual"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index e396e91..20430ad 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ઘડિયાળનો રંગ અને કદ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ઘડિયાળનો રંગ અને કદ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"શૈલી"</string>
     <string name="clock_color" msgid="8081608867289156163">"રંગ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"લાલ"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"નારંગી"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"મોટું"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"નાનું"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"તમારી સ્ક્રીનના ખૂણામાં એક નાની ઘડિયાળ દેખાય છે"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Clockના ફૉન્ટમાં કરેલા ફેરફારો લાગુ કરો"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Clockના ફૉન્ટમાં છેલ્લે કરેલા ફેરફારો રદ કરો"</string>
     <string name="grid_title" msgid="1688173478777254123">"ઍપ ગ્રિડ"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ઍપનો આકાર+લેઆઉટ"</string>
+    <string name="grid_layout" msgid="370175667652663686">"લેઆઉટ"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"લાગુ કરો"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ફેરફાર કરવા માટે ટૅપ કરો"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"હાલનું વૉલપેપર રાખો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 059eabb..ffcb108 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"वॉच का रंग और साइज़"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"घड़ी का रंग और साइज़"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"स्टाइल"</string>
     <string name="clock_color" msgid="8081608867289156163">"रंग"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"लाल"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"नारंगी"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"बड़ा"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"छोटा"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"आपके डिवाइस की स्क्रीन के कोने में एक छोटी घड़ी दिखती है"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"घड़ी के फ़ॉन्ट में किए गए बदलावों को लागू करें"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"घड़ी के फ़ॉन्ट में किए गए बदलावों को पहले जैसा करें"</string>
     <string name="grid_title" msgid="1688173478777254123">"ऐप्लिकेशन ग्रिड"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ऐप का शेप और लेआउट"</string>
+    <string name="grid_layout" msgid="370175667652663686">"लेआउट"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"लागू करें"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"बदलाव करने के लिए टैप करें"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"मौजूदा वॉलपेपर बनाए रखें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 69591f7..dea03bc 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Boja i veličina sata"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Boja i veličina sata"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Boja"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Crvena"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Narančasta"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Velik"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Mali sat"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"U kutu zaslona prikazuje se mali sat"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Primijeni izmjene fonta sata"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Poništi izmjene fonta sata"</string>
     <string name="grid_title" msgid="1688173478777254123">"Rešetka aplikacija"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Oblik i izgled aplikacije"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Izgled"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Primijeni"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Dodirnite da biste uredili"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Zadrži trenutačnu pozadinu"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index ed4e10c..65fb8a1 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Óra színe és mérete"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Óra színe és mérete"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stílus"</string>
     <string name="clock_color" msgid="8081608867289156163">"Szín"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Piros"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Narancssárga"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Nagy"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Kicsi"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Megjelenik egy kis óra a képernyő sarkában."</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Az óra betűtípusára vonatkozó módosítások alkalmazása"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Az óra betűtípusára vonatkozó módosítások visszavonása"</string>
     <string name="grid_title" msgid="1688173478777254123">"Alkalmazásrács"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Forma és elrendezés"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Elrendezés"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Alkalmaz"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Koppintson a szerkesztéshez"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Jelenlegi háttérkép megtartása"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 0d75ee7..245afa9 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Գույնը և չափսը"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Գույնը և չափսը"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Ոճ"</string>
     <string name="clock_color" msgid="8081608867289156163">"Գույն"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Կարմիր"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Նարնջագույն"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Մեծ"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Փոքր"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Էկրանի անկյունում ցուցադրվում է փոքրիկ ժամացույց"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Ժամացույցի տառատեսակի փոփոխության կիրառում"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Ժամացույցի տառատեսակի փոփոխության հետարկում"</string>
     <string name="grid_title" msgid="1688173478777254123">"Հավելվածների ցանց"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Ձև և դասավորություն"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Դասավորություն"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Կիրառել"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Հպեք՝ փոփոխելու համար"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Պահպանել ընթացիկ պաստառը"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 04ab409..1ccf8f9 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Warna &amp; ukuran jam"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Warna &amp; ukuran jam"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Gaya"</string>
     <string name="clock_color" msgid="8081608867289156163">"Warna"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Merah"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranye"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Besar"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Kecil"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Jam kecil ditampilkan di sudut layar"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Terapkan perubahan font jam"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Urungkan perubahan font jam"</string>
     <string name="grid_title" msgid="1688173478777254123">"Petak aplikasi"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Bentuk &amp; tata letak aplikasi"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Tata letak"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Terapkan"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Ketuk untuk mengedit"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Pertahankan wallpaper saat ini"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index abad9ec..649244e 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Klukkustærð og litur"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Klukkustærð og litur"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stíll"</string>
     <string name="clock_color" msgid="8081608867289156163">"Litur"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rauður"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Appelsínugulur"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Stór"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Lítil"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Lítil klukka birtist í horni skjásins"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Breyta leturgerð klukku"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Afturkalla breytingar á leturgerð klukku"</string>
     <string name="grid_title" msgid="1688173478777254123">"Forritatafla"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Lögun forrits og uppsetning"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Útlit"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Nota"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Ýttu til að breyta"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Halda núverandi veggfóðri"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 6dffc0b..016075e 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Colore/dim. orologio"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Colore e dimensioni orologio"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stile"</string>
     <string name="clock_color" msgid="8081608867289156163">"Colore"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rosso"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Arancione"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Grandi"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Piccole"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Un piccolo orologio visualizzato nell\'angolo dello schermo"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Applica le modifiche al carattere dell\'orologio"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Annulla le modifiche al carattere dell\'orologio"</string>
     <string name="grid_title" msgid="1688173478777254123">"Griglia di app"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Layout/Forma app"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Applica"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tocca per modificare"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Mantieni lo sfondo corrente"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 8c5ad6e..ac4e52d 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"הצבע והגודל של השעון"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"הצבע והגודל של השעון"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"סגנון"</string>
     <string name="clock_color" msgid="8081608867289156163">"צבע"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"אדום"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"כתום"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"גדול"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"קטן"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"שעון קטן מופיע בפינת המסך"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"החלה של שינויי הגופן בשעון"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ביטול של שינויי הגופן בשעון"</string>
     <string name="grid_title" msgid="1688173478777254123">"תצוגת האפליקציות"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"הצורה והפריסה של האפליקציה"</string>
+    <string name="grid_layout" msgid="370175667652663686">"פריסה"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"אישור"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"יש להקיש כדי לערוך"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"שמירת הטפט הנוכחי"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 4b079b8..9463a32 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"時計の色とサイズ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"時計の色とサイズ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>、<xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"スタイル"</string>
     <string name="clock_color" msgid="8081608867289156163">"色"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"赤"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"オレンジ"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"大"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"小"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"画面の隅に小さい時計を表示します"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"時計のフォント変更を適用"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"時計のフォント変更を元に戻す"</string>
     <string name="grid_title" msgid="1688173478777254123">"アプリグリッド"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"アプリの形状とレイアウト"</string>
+    <string name="grid_layout" msgid="370175667652663686">"レイアウト"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"適用"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"タップして編集"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"現在の壁紙を保持"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index c52a944..d4fee27 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"საათის ფერი და ზომა"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"საათის ფერი &amp; amp; ზომა"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"სტილი"</string>
     <string name="clock_color" msgid="8081608867289156163">"ფერი"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"წითელი"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ნარინჯისფერი"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"დიდი"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"პატარა"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"პატარა საათი მოთავსებულია თქვენი ეკრანის კუთხეში"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"საათის შრიფტის ცვლილებების გამოყენება"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"საათის შრიფტის ცვლილებების გაუქმება"</string>
     <string name="grid_title" msgid="1688173478777254123">"აპების ბადე"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"აპის ფორმა და განლაგება"</string>
+    <string name="grid_layout" msgid="370175667652663686">"განლაგება"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"მისადაგება"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"შეეხეთ რედაქტირებისთვის"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"ამჟამინდელი ფონის შენარჩუნება"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 9389d03..25f424e 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Сағат түсі, көлемі"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Сағаттың түсі, өлшемі"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Стиль"</string>
     <string name="clock_color" msgid="8081608867289156163">"Түс"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Қызыл"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Қызғылт сары"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Үлкен"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Кішi"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Экранның бұрышында шағын сағат көрсетіледі."</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Сағат қаріпі өзгерістерін қолдану"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Сағат қаріпі өзгерістерінен бас тарту"</string>
     <string name="grid_title" msgid="1688173478777254123">"Қолданбалар торы"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Пішін, формат"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Формат"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Қолдану"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Өзгерту үшін түртіңіз"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Қазіргі тұсқағазды қалдыру"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 19762ef..187a2eb 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="1647136562008520313">"ផ្ទាំងរូបភាព និងរចនាប័ទ្ម"</string>
+    <string name="app_name" msgid="1647136562008520313">"ផ្ទាំងរូបភាព និងរចនាបថ"</string>
     <string name="theme_title" msgid="2144932106319405101">"រចនាប័ទ្ម"</string>
     <string name="clock_title" msgid="1974314575211361352">"នាឡិកាផ្ទាល់ខ្លួន"</string>
     <string name="clock_description" msgid="3563839327378948">"ជ្រើសរើសនាឡិកាផ្ទាល់ខ្លួន"</string>
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ពណ៌ និងទំហំនាឡិកា"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ពណ៌ និងទំហំនាឡិកា"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"រចនាបថ"</string>
     <string name="clock_color" msgid="8081608867289156163">"ពណ៌"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ក្រហម"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ទឹកក្រូច"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ធំ"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"តូច"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"នាឡិកា​តូចមួយ​បង្ហាញ​នៅជ្រុងនៃ​អេក្រង់​របស់អ្នក"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"អនុវត្តការផ្លាស់ប្ដូរពុម្ពអក្សរនាឡិកា"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ត្រឡប់ការផ្លាស់ប្ដូរពុម្ពអក្សរនាឡិកាវិញ"</string>
     <string name="grid_title" msgid="1688173478777254123">"ក្រឡា​កម្មវិធី"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"រូបរាង និងប្លង់កម្មវិធី"</string>
+    <string name="grid_layout" msgid="370175667652663686">"ប្លង់"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"ប្រើ"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ចុច ដើម្បី​កែ"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"រក្សាទុក​ផ្ទាំងរូបភាព​បច្ចុប្បន្ន"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 70e229f..d368191 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ಗಡಿಯಾರದ ಬಣ್ಣ, ಗಾತ್ರ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ಗಡಿಯಾರದ ಬಣ್ಣ, ಗಾತ್ರ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"ಶೈಲಿ"</string>
     <string name="clock_color" msgid="8081608867289156163">"ಬಣ್ಣ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ಕೆಂಪು"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ಕಿತ್ತಳೆ"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ದೊಡ್ಡದು"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"ಚಿಕ್ಕದು"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಮೂಲೆಯಲ್ಲಿ ಸಣ್ಣ ಗಡಿಯಾರವೊಂದು ಕಾಣಿಸುತ್ತದೆ"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ಕ್ಲಾಕ್ ಫಾಂಟ್ ಬದಲಾವಣೆಗಳನ್ನು ಅನ್ವಯಿಸಿ"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ಕ್ಲಾಕ್ ಫಾಂಟ್ ಬದಲಾವಣೆಗಳನ್ನು ರದ್ದುಗೊಳಿಸಿ"</string>
     <string name="grid_title" msgid="1688173478777254123">"ಆ್ಯಪ್ ಗ್ರಿಡ್"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ಆ್ಯಪ್ ಆಕಾರ, ಲೇಔಟ್"</string>
+    <string name="grid_layout" msgid="370175667652663686">"ಲೇಔಟ್"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"ಅನ್ವಯಿಸಿ"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ಎಡಿಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"ಪ್ರಸ್ತುತ ವಾಲ್‌ಪೇಪರ್ ಅನ್ನು ಉಳಿಸಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 3582ae6..3e45481 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"시계 색상 및 크기"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"시계 색상 및 크기"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"스타일"</string>
     <string name="clock_color" msgid="8081608867289156163">"색상"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"빨간색"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"주황색"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"크게"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"작게"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"작은 시계가 화면 모서리에 표시됩니다."</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"시계 글꼴 변경사항 적용"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"시계 글꼴 변경사항 실행취소"</string>
     <string name="grid_title" msgid="1688173478777254123">"앱 그리드"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"앱 모양 및 레이아웃"</string>
+    <string name="grid_layout" msgid="370175667652663686">"레이아웃"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"적용"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"탭하여 수정"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"현재 배경화면 유지"</string>
@@ -126,8 +131,8 @@
     <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8117011931337357438">"<xliff:g id="APPNAME">%1$s</xliff:g> 열기"</string>
     <string name="keyguard_affordance_enablement_dialog_message" msgid="6136286758939253570">"<xliff:g id="APPNAME">%1$s</xliff:g> 앱을 바로가기로 추가하려면 다음을 확인하세요."</string>
     <string name="keyguard_affordance_enablement_dialog_dismiss_button" msgid="629754625264422508">"완료"</string>
-    <string name="keyguard_quick_affordance_title" msgid="4242813186995735584">"단축키"</string>
-    <string name="keyguard_quick_affordance_section_title" msgid="2806304242671717309">"단축키"</string>
+    <string name="keyguard_quick_affordance_title" msgid="4242813186995735584">"바로가기"</string>
+    <string name="keyguard_quick_affordance_section_title" msgid="2806304242671717309">"바로가기"</string>
     <string name="color_contrast_section_title" msgid="7194809124718896091">"색상 대비"</string>
     <string name="color_contrast_default_title" msgid="7954235103549276978">"기본값"</string>
     <string name="color_contrast_medium_title" msgid="8071574793250090215">"중간"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index cf57425..1b153e5 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Сааттын түсү, өлчөмү"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Сааттын түсү, өлчөмү"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Стиль"</string>
     <string name="clock_color" msgid="8081608867289156163">"Түс"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"КЫЗЫЛ"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"КЫЗГЫЛТ САРЫ"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Чоң"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Кичине"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Кичинекей саат экрандын бурчунда көрүнүп турат"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Саат арибине өзгөртүү киргизүү"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Саат арибинин өзгөртүүсүн кайтаруу"</string>
     <string name="grid_title" msgid="1688173478777254123">"Колдонмолор торчосу"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Формасы, калыбы"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Калып"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Колдонуу"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Өзгөртүү үчүн таптап коюңуз"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Учурдагы тушкагаз калсын"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index b33cebc..f5064e5 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ສີ ແລະ ຂະໜາດໂມງ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ສີ ແລະ ຂະໜາດໂມງ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"ຮູບແບບ"</string>
     <string name="clock_color" msgid="8081608867289156163">"ສີ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ສີແດງ"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ສີສົ້ມ"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ໃຫຍ່"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"ນ້ອຍ"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"ໂມງນ້ອຍທີ່ສະແດງຢູ່ໃນມຸມຂອງໜ້າຈໍທ່ານ"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ນຳໃຊ້ການປ່ຽນແປງຟອນໂມງ"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ຍົກເລີກການປ່ຽນແປງຟອນໂມງ"</string>
     <string name="grid_title" msgid="1688173478777254123">"ຕາຕະລາງແອັບ"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ຮູບຮ່າງ ແລະ ໂຄງຮ່າງແອັບ"</string>
+    <string name="grid_layout" msgid="370175667652663686">"ໂຄງຮ່າງ"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"ນຳໃຊ້"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ແຕະເພື່ອແກ້ໄຂ"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"ໃຊ້ຮູບພື້ນຫຼັງປັດຈຸບັນ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index d2a21d7..0c5e7cf 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Laikr. spalva, dyd."</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Laikr. spalva ir dydis"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stilius"</string>
     <string name="clock_color" msgid="8081608867289156163">"Spalva"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Raudona"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranžinė"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Didelis"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Mažas"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Ekrano kampe rodomas nedidelis laikrodis"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Taikyti laikrodžio šrifto pakeitimus"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Anuliuoti laikrodžio šrifto pakeitimus"</string>
     <string name="grid_title" msgid="1688173478777254123">"Pr. tinklelis"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Progr. forma ir išd."</string>
+    <string name="grid_layout" msgid="370175667652663686">"Išdėstymas"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Taikyti"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Palieskite ir redaguokite"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Palikti dabartinį ekrano foną"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index bc8f155..207138f 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Pulksteņa krāsa/lielums"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Pulksteņa krāsa/lielums"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stils"</string>
     <string name="clock_color" msgid="8081608867289156163">"Krāsa"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Sarkana"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranža"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Liels"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Mazs"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Jūsu ekrāna stūrī tiek rādīts neliels pulkstenis."</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Lietot pulksteņa fonta izmaiņas"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Atsaukt pulksteņa fonta izmaiņas"</string>
     <string name="grid_title" msgid="1688173478777254123">"Lietotņu režģis"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Lietotnes forma un izkārtojums"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Izkārtojums"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Lietot"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Pieskarieties, lai rediģētu"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Paturēt pašreizējo fona tapeti"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index b3b8ab2..8ec9caf 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Боја и големина"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Боја и големина"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Стил"</string>
     <string name="clock_color" msgid="8081608867289156163">"Боја"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Црвена"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Портокалова"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Голема"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Мала"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Во аголот на екранот се прикажува мал часовник"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Примени ги промените на фонтот на часовникот"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Врати ги промените на фонтот на часовникот"</string>
     <string name="grid_title" msgid="1688173478777254123">"Мрежа"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Распоред и форма"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Распоред"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Примени"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Допрете за да измените"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Задржи тековен тапет"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 685f8f6..466c184 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ക്ലോക്കിന്റെ നിറം, വലുപ്പം"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ക്ലോക്കിന്റെ നിറം, വലുപ്പം"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"സ്റ്റൈൽ"</string>
     <string name="clock_color" msgid="8081608867289156163">"നിറം"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ചുവപ്പ്"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ഓറഞ്ച്"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"വലുത്"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"ചെറുത്"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"സ്ക്രീനിന്റെ മൂലയിൽ ഒരു ചെറിയ ക്ലോക്ക് കാണിക്കുന്നു"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ക്ലോക്ക് ഫോണ്ട് മാറ്റങ്ങൾ ബാധകമാക്കുക"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ക്ലോക്ക് ഫോണ്ട് മാറ്റങ്ങൾ പഴയപടിയാക്കുക"</string>
     <string name="grid_title" msgid="1688173478777254123">"ആപ്പ് ഗ്രിഡ്"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ആപ്പ് രൂപവും ലേഔട്ടും"</string>
+    <string name="grid_layout" msgid="370175667652663686">"ലേഔട്ട്"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"പ്രയോഗിക്കുക"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"എഡിറ്റ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"നിലവിലെ വാൾപേപ്പർ നിലനിർത്തുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 003a69d..e059399 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Цагны өнгө, хэмжээ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Цагны өнгө, хэмжээ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Загвар"</string>
     <string name="clock_color" msgid="8081608867289156163">"Өнгө"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Улаан"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Улбар шар"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Том"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Жижиг"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Таны дэлгэцийн буланд жижиг цаг харуулдаг"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Цагны фонтын өөрчлөлтүүдийг оруулах"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Цагны фонтын өөрчлөлтүүдийг болих"</string>
     <string name="grid_title" msgid="1688173478777254123">"Аппын хүснэгт"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Аппын хэлбэр, бүдүүвч"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Бүдүүвч"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Ашиглах"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Засахын тулд товшино уу"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Одоогийн дэлгэцийн зургийг хадгалах"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 8419783..1081502 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Clock चा रंग व आकार"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"घड्याळाचा रंग व आकार"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"शैली"</string>
     <string name="clock_color" msgid="8081608867289156163">"रंग"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"लाल"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"नारिंगी"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"मोठा"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"छोटे"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"तुमच्या स्क्रीनच्या कोपऱ्यामध्ये एक लहान घड्याळ दिसते"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"घड्याळाच्या फॉंटमध्ये बदल लागू करा"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"घड्याळाच्या फॉंटमध्ये केलेले बदल पहिल्यासारखे करा"</string>
     <string name="grid_title" msgid="1688173478777254123">"ॲप ग्रिड"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"अ‍ॅप आकार व लेआउट"</string>
+    <string name="grid_layout" msgid="370175667652663686">"लेआउट"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"लागू करा"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"संपादित करण्‍यासाठी टॅप करा"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"सध्याचा वॉलपेपर ठेवा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 2757dc8..65fe52f 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Warna &amp; saiz jam"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Warna &amp; saiz jam"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Gaya"</string>
     <string name="clock_color" msgid="8081608867289156163">"Warna"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Merah"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Jingga"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Besar"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Kecil"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Jam kecil dipaparkan di penjuru skrin"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Gunakan perubahan fon jam"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Buat asal perubahan fon jam"</string>
     <string name="grid_title" msgid="1688173478777254123">"Grid apl"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Bentuk &amp; reka letak apl"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Reka letak"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Gunakan"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Ketik untuk edit"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Kekalkan kertas dinding semasa"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index bc71e17..a2352ee 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"နာရီအရောင်၊ အရွယ်"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"နာရီအရောင်နှင့်အရွယ်"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>၊ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"ပုံစံ"</string>
     <string name="clock_color" msgid="8081608867289156163">"အရောင်"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"အနီရောင်"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"လိမ္မော်ရောင်"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ကြီး"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"သေး"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"သင့်ဖန်သားပြင်ထောင့်တွင် ပြသထားသော နာရီအသေးတစ်ခု"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"နာရီဖောင့်အပြောင်းအလဲများ သုံးရန်"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"နာရီဖောင့် အပြောင်းအလဲများ နောက်ပြန်ရန်"</string>
     <string name="grid_title" msgid="1688173478777254123">"အက်ပ်ဇယား"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"အက်ပ်ပုံစံ၊ အပြင်အဆင်"</string>
+    <string name="grid_layout" msgid="370175667652663686">"အပြင်အဆင်"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"အသုံးပြုရန်"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"တည်းဖြတ်ရန် တို့ပါ"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"လက်ရှိနောက်ခံပုံ ဆက်ထားရန်"</string>
@@ -131,7 +136,7 @@
     <string name="color_contrast_section_title" msgid="7194809124718896091">"အရောင်ခြားနားမှု"</string>
     <string name="color_contrast_default_title" msgid="7954235103549276978">"မူရင်း"</string>
     <string name="color_contrast_medium_title" msgid="8071574793250090215">"အသင့်အတင့်"</string>
-    <string name="color_contrast_high_title" msgid="5554685752479470200">"များ"</string>
+    <string name="color_contrast_high_title" msgid="5554685752479470200">"မြင့်"</string>
     <string name="keyguard_quick_affordance_two_selected_template" msgid="1757099194522296363">"<xliff:g id="FIRST">%1$s</xliff:g>၊ <xliff:g id="SECOND">%2$s</xliff:g>"</string>
     <string name="keyguard_quick_affordance_none_selected" msgid="8494127020144112003">"မရှိ"</string>
     <string name="show_notifications_on_lock_screen" msgid="4157744243084646720">"အကြောင်းကြားချက်များကို လော့ခ်မျက်နှာပြင်တွင် ပြပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 20023dd..e7a6f18 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Farge og størrelse"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Farge og størrelse"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Farge"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rød"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oransje"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Stor"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Liten"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"En liten klokke vises i hjørnet av skjermen"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Bruk endringene i klokkeskrifttypen"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Angre endringene i klokkeskrifttypen"</string>
     <string name="grid_title" msgid="1688173478777254123">"Apprutenett"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Appform/-layout"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Oppsett"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Bruk"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Trykk for å endre"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Behold den nåværende bakgrunnen"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 9a941cc..95b0a6c 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"घडीको रङ र आकार"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"घडीको रङ र आकार"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"शैली"</string>
     <string name="clock_color" msgid="8081608867289156163">"रङ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"रातो"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"सुन्तले"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ठुलो"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"सानो"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"तपाईंको स्क्रिनको कुनामा सानो घडी देखा पर्छ"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"घडीको फन्टमा गरिएका परिवर्तनहरू लागू गर्नुहोस्"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"घडीको फन्टमा गरिएका परिवर्तनहरू अन्डू गर्नुहोस्"</string>
     <string name="grid_title" msgid="1688173478777254123">"एप ग्रिड"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"एपको आकार र लेआउट"</string>
+    <string name="grid_layout" msgid="370175667652663686">"लेआउट"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"लागू गर्नुहोस्"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"सम्पादन गर्न ट्याप गर्नुहोस्"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"अहिले कै वालपेपर राख्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 8c22a35..1d96ab2 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Kleur en grootte van klok"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Kleur en formaat van klok"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stijl"</string>
     <string name="clock_color" msgid="8081608867289156163">"Kleur"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rood"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranje"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Groot"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Klein"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Er wordt een kleine klok weergegeven in de hoek van het scherm"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Wijzigingen in lettertype van klok toepassen"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Wijzigingen in lettertype van klok ongedaan maken"</string>
     <string name="grid_title" msgid="1688173478777254123">"App-raster"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Vorm en indeling van app"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Indeling"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Toepassen"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tik om te bewerken"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Huidige achtergrond behouden"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index c9f5ea6..4265f89 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ଘଣ୍ଟାର ରଙ୍ଗ ଓ ସାଇଜ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ଘଣ୍ଟାର ରଙ୍ଗ ଓ ଆକାର"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"ଷ୍ଟାଇଲ"</string>
     <string name="clock_color" msgid="8081608867289156163">"ରଙ୍ଗ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ଲାଲ"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"କମଳା"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ବଡ଼"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"ଛୋଟ"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"ଆପଣଙ୍କ ସ୍କ୍ରିନର କୋଣରେ ଏକ ଛୋଟ ଘଣ୍ଟା ଦେଖାଯାଏ"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ଘଡ଼ିର ଫଣ୍ଟରେ କରାଯାଇଥିବା ପରିବର୍ତ୍ତନକୁ ଲାଗୁ କରନ୍ତୁ"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ଘଡ଼ିର ଫଣ୍ଟରେ କରାଯାଇଥିବା ପରିବର୍ତ୍ତନକୁ ଅନଡୁ କରନ୍ତୁ"</string>
     <string name="grid_title" msgid="1688173478777254123">"ଆପ ଗ୍ରିଡ"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ଆପ ଆକାର ଓ ଲେଆଉଟ"</string>
+    <string name="grid_layout" msgid="370175667652663686">"ଲେଆଉଟ"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"ପ୍ରୟୋଗ କରନ୍ତୁ"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ଏଡିଟ କରିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"ବର୍ତ୍ତମାନର ୱାଲ୍‌ପେପର୍‌କୁ ରଖନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 926dce1..05a7823 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ਘੜੀ ਦਾ ਰੰਗ ਅਤੇ ਆਕਾਰ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ਘੜੀ ਦਾ ਰੰਗ ਅਤੇ ਆਕਾਰ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"ਸਟਾਈਲ"</string>
     <string name="clock_color" msgid="8081608867289156163">"ਰੰਗ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ਲਾਲ"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ਸੰਤਰੀ"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ਵੱਡਾ"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"ਛੋਟਾ"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੇ ਕੋਨੇ \'ਤੇ ਇੱਕ ਛੋਟੀ ਘੜੀ ਦਿਖਾਈ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ਘੜੀ ਦੇ ਫ਼ੌਟਾਂ ਵਿੱਚ ਕੀਤੀਆਂ ਤਬਦੀਲੀਆਂ ਲਾਗੂ ਕਰੋ"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ਘੜੀ ਦੇ ਫ਼ੌਟਾਂ ਵਿੱਚ ਕੀਤੀਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਅਣਕੀਤਾ ਕਰੋ"</string>
     <string name="grid_title" msgid="1688173478777254123">"ਐਪ ਗ੍ਰਿਡ"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ਐਪ ਦੀ ਆਕ੍ਰਿਤੀ ਅਤੇ ਖਾਕਾ"</string>
+    <string name="grid_layout" msgid="370175667652663686">"ਖਾਕਾ"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"ਲਾਗੂ ਕਰੋ"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ਸੰਪਾਦਨ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"ਮੌਜੂਦਾ ਵਾਲਪੇਪਰ ਬਰਕਰਾਰ ਰੱਖੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index d91f026..45ebcac 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Kolor i rozmiar zegara"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Kolor i rozmiar zegara"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Styl"</string>
     <string name="clock_color" msgid="8081608867289156163">"Kolor"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Czerwony"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Pomarańczowy"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Duży"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Mały"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Mały zegar wyświetlany w rogu ekranu"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Zastosuj zmiany czcionki zegara"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Cofnij zmiany czcionki zegara"</string>
     <string name="grid_title" msgid="1688173478777254123">"Siatka aplikacji"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Kształt i układ aplikacji"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Układ"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Zastosuj"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Kliknij, by edytować"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Pozostaw bieżącą tapetę"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index c912c07..c448b7e 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Cor e tamanho do relógio"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Cor e tamanho do relógio"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Estilo"</string>
     <string name="clock_color" msgid="8081608867289156163">"Cor"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Vermelho"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Laranja"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Grande"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Pequeno"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Um pequeno relógio é apresentado no canto do ecrã"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Aplicar alterações ao tipo de letra do relógio"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Anular alterações ao tipo de letra do relógio"</string>
     <string name="grid_title" msgid="1688173478777254123">"Grelha de apps"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Esquema/forma das apps"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Esquema"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Aplicar"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Toque para editar"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Manter a imagem de fundo atual"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index ed833d5..ea3b7b7 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Cor/tam. do relógio"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Cor e tamanho do relógio"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Estilo"</string>
     <string name="clock_color" msgid="8081608867289156163">"Cor"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Vermelho"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Laranja"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Grande"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Pequeno"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Um relógio pequeno aparece no canto da tela"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Aplicar mudanças na fonte do relógio"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Desfazer mudanças na fonte do relógio"</string>
     <string name="grid_title" msgid="1688173478777254123">"Grade de apps"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Formato e layout do app"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Aplicar"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Toque para editar"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Manter o plano de fundo atual"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 44bd489..9ec5802 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Culoare / mărime"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Culoare / dimensiune"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Culoare"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Roșu"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Portocaliu"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Mare"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Mică"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Un ceas mic apare în colțul ecranului"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Aplică modificările fontului ceasului"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Anulează modificările fontului ceasului"</string>
     <string name="grid_title" msgid="1688173478777254123">"Grilă aplicații"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Formă și aspect"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Aspect"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Aplică"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Atinge pentru a modifica"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Păstrează imaginea de fundal actuală"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 85cdb25..525e685 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Цвет и размер часов"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Цвет и размер часов"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>."</string>
+    <string name="clock_style" msgid="6847711178193804308">"Стиль"</string>
     <string name="clock_color" msgid="8081608867289156163">"Цвет"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Красный"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Оранжевый"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Большой"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Маленький"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Небольшие часы в углу экрана"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Применить изменения в шрифтах часов"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Отменить изменения в шрифтах часов"</string>
     <string name="grid_title" msgid="1688173478777254123">"Сетка приложений"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Форма прил., макет"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Макет"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Применить"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Нажмите, чтобы изменить"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Использовать текущие обои"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 35cec6a..a651011 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"ඔරලෝසු වර්ණය සහ තරම"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"ඔරලෝසු වර්ණය සහ තරම"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"විලාසය"</string>
     <string name="clock_color" msgid="8081608867289156163">"වර්ණය"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"රතු"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"තැඹිලි"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"විශාල"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"කුඩා"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"ඔබේ තිරයේ කෙළවරේ කුඩා ඔරලෝසුවක් පෙන්වයි"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ඔරලෝසු අකුරු වෙනස් කිරීම් යොදන්න"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"ඔරලෝසු අකුරු වෙනස් කිරීම් අහෝසි කරන්න"</string>
     <string name="grid_title" msgid="1688173478777254123">"යෙදුම් ජාලකය"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"යෙදුම් හැඩය සහ පිරිසැලසුම"</string>
+    <string name="grid_layout" msgid="370175667652663686">"පිරිසැලසුම"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"යොදන්න"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"සංස්කරණයට තට්ටු කරන්න"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"වත්මන් බිතුපත තබා ගන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 5f26d2f..71552ae 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Farba a veľkosť"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Farba a veľkosť"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Štýl"</string>
     <string name="clock_color" msgid="8081608867289156163">"Farba"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Červená"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranžová"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Veľké"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Malé"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"V rohu obrazovky sa zobrazujú malé hodiny"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Použiť zmeny písma ciferníka"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Vrátiť zmeny písma ciferníka"</string>
     <string name="grid_title" msgid="1688173478777254123">"Mriežka aplikácií"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Tvar a rozloženie"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Rozloženie"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Použiť"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Klepnutím upravte"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Ponechať aktuálnu tapetu"</string>
@@ -107,7 +112,7 @@
     <string name="mode_title" msgid="2394873501427436055">"Tmavý motív"</string>
     <string name="mode_disabled_msg" msgid="9196245518435936512">"Dočasne vypnuté šetričom batérie"</string>
     <string name="mode_changed" msgid="2243581369395418584">"Motív bol zmenený"</string>
-    <string name="themed_icon_title" msgid="7312460430471956558">"Prefarbené ikony"</string>
+    <string name="themed_icon_title" msgid="7312460430471956558">"Ikony s motívom"</string>
     <string name="beta_title" msgid="8703819523760746458">"Beta"</string>
     <string name="gird_picker_entry_content_description" msgid="9087651470212293439">"Zmeniť mriežku aplikácií"</string>
     <string name="wallpaper_color_tab" msgid="1447926591721403840">"Farby tapety"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index c8fb3ce..decab8c 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Barva, velikost ure"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Barva, velikost ure"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Slog"</string>
     <string name="clock_color" msgid="8081608867289156163">"Barva"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Rdeča"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Oranžna"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Velika"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Majhna"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"V kotu zaslona je prikazana majhna ura."</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Uporabi spremembe pisave ure"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Razveljavi spremembe pisave ure"</string>
     <string name="grid_title" msgid="1688173478777254123">"Mreža aplikacij"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Oblika in postavitev aplikacije"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Postavitev"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Uporabi"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Dotaknite se za urejanje"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Obdrži trenutno ozadje"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 19677fa..71fb5fb 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Ora: Ngjyrë/madhësi"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Ora: Ngjyra/madhësia"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stili"</string>
     <string name="clock_color" msgid="8081608867289156163">"Ngjyra"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"E kuqe"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Portokalli"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"E madhe"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"E vogël"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Në këndin e ekranit shfaqet një orë e vogël"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Zbato ndryshimet e fontit të orës"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Zhbëj ndryshimet e fontit të orës"</string>
     <string name="grid_title" msgid="1688173478777254123">"Rrjeta e aplikacioneve"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Forma e struktura e aplikacionit"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Struktura"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Zbato"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Trokit për të modifikuar"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Mbaj imazhin aktual të sfondit"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 4040536..4ee4b2d 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Боја и величина сата"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Боја и величина сата"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Стил"</string>
     <string name="clock_color" msgid="8081608867289156163">"Боја"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Црвена"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Наранџаста"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Велико"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Мали"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Мали сат се приказује у углу екрана"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Примените промене фонта сата"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Опозовите промене фонта сата"</string>
     <string name="grid_title" msgid="1688173478777254123">"Мрежа апл."</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Облик и изглед"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Изглед"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Примени"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Додирните да бисте изменили"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Задржи актуелну позадину"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 8749e96..51c8058 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Klockstorlek/färg"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Klockstorlek/färg"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Färg"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Röd"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Stor"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Liten"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"En liten klockas visas i skärmens hörn"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Tillämpa ändringar av klockans teckensnitt"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Ångra ändringar av klockans teckensnitt"</string>
     <string name="grid_title" msgid="1688173478777254123">"Apprutnät"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Form och layout"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Använd"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tryck för att redigera"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Behåll befintlig bakgrund"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 55f75fc..6fd1b01 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Rangi na ukubwa wa saa"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Rangi na ukubwa wa saa"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Muundo"</string>
     <string name="clock_color" msgid="8081608867289156163">"Rangi"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Nyekundu"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Rangi ya chungwa"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Kubwa"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Ndogo"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Saa ndogo inaonekana kwenye kona ya skrini yako"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Tumia mabadiliko ya fonti ya saa"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Tendua mabadiliko ya fonti ya saa"</string>
     <string name="grid_title" msgid="1688173478777254123">"Gridi ya programu"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Muundo na umbo la programu"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Muundo"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Tumia"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Gusa ili ubadilishe"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Tumia mandhari ya sasa"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 75609c7..d8012b3 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"கடிகார நிறம் &amp; அளவு"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"கடிகார நிறம் &amp; அளவு"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"ஸ்டைல்"</string>
     <string name="clock_color" msgid="8081608867289156163">"நிறம்"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"சிவப்பு"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ஆரஞ்சு"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"பெரியது"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"சிறியது"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"உங்கள் திரையின் மூலையில் ஒரு சிறிய கடிகாரம் காட்டப்படும்"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"கடிகார எழுத்து வடிவ மாற்றங்களைப் பயன்படுத்தும்"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"கடிகார எழுத்து வடிவ மாற்றங்களைச் செயல்தவிர்க்கும்"</string>
     <string name="grid_title" msgid="1688173478777254123">"ஆப்ஸ் கட்டம்"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ஆப்ஸ் வடிவம் &amp; தளவமைப்பு"</string>
+    <string name="grid_layout" msgid="370175667652663686">"தளவமைப்பு"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"பயன்படுத்து"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"\'தீமைத்\' திருத்த தட்டவும்"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"தற்போதைய வால்பேப்பரே இருக்கட்டும்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index c318952..6e984a4 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"గడియారం రంగు &amp; సైజు"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"గడియారం రంగు &amp; సైజు"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"స్టయిల్"</string>
     <string name="clock_color" msgid="8081608867289156163">"రంగు"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"ఎరుపు రంగు"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"నారింజ రంగు"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"పెద్దది"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"చిన్నది"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"మీ స్క్రీన్ మూలన ఒక చిన్న గడియారం కనిపిస్తుంది"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"క్లాక్ ఫాంట్ మార్పులను వర్తింపజేయండి"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"క్లాక్ ఫాంట్ మార్పులను చర్య రద్దు చేయండి"</string>
     <string name="grid_title" msgid="1688173478777254123">"యాప్ గ్రిడ్"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"యాప్ షేప్ &amp; లేఅవుట్"</string>
+    <string name="grid_layout" msgid="370175667652663686">"లేఅవుట్"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"వర్తింపజేయి"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ఎడిట్ చేయడానికి నొక్కండి"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"ప్రస్తుత వాల్‌పేపర్‌ను అలాగే ఉంచండి"</string>
@@ -104,7 +109,7 @@
     <string name="accessibility_custom_shape_title" msgid="7708408259374643129">"అనుకూల ఆకారం"</string>
     <string name="accessibility_custom_name_title" msgid="5494460518085463262">"అనుకూల స్టయిల్ పేరు"</string>
     <string name="accessibility_clock_slider_description" msgid="8374135133110681332">"రంగు తీవ్రత"</string>
-    <string name="mode_title" msgid="2394873501427436055">"ముదురు రంగు రూపం"</string>
+    <string name="mode_title" msgid="2394873501427436055">"డార్క్ థీమ్‌"</string>
     <string name="mode_disabled_msg" msgid="9196245518435936512">"బ్యాటరీ సేవర్ కారణంగా తాత్కాలికంగా డిజేబుల్‌ చేయబడింది"</string>
     <string name="mode_changed" msgid="2243581369395418584">"థీమ్ మార్చబడింది"</string>
     <string name="themed_icon_title" msgid="7312460430471956558">"రూపానికి తగిన చిహ్నాలు"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index b92fb2d..75986a9 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"สีและขนาดนาฬิกา"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"สีและขนาดนาฬิกา"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"รูปแบบ"</string>
     <string name="clock_color" msgid="8081608867289156163">"สี"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"แดง"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"ส้ม"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"ใหญ่"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"เล็ก"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"นาฬิกาขนาดเล็กจะแสดงที่มุมของหน้าจอ"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"ใช้การเปลี่ยนแปลงแบบอักษรของนาฬิกา"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"เลิกทำการเปลี่ยนแปลงแบบอักษรของนาฬิกา"</string>
     <string name="grid_title" msgid="1688173478777254123">"ตารางกริดแอป"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"รูปร่างและเลย์เอาต์แอป"</string>
+    <string name="grid_layout" msgid="370175667652663686">"เลย์เอาต์"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"ใช้"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"แตะเพื่อแก้ไข"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"ใช้วอลเปเปอร์ปัจจุบัน"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 3daa94a..35c6a8b 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Kulay, laki ng clock"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Kulay, laki ng clock"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Istilo"</string>
     <string name="clock_color" msgid="8081608867289156163">"Kulay"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Pula"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Orange"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Malaki"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Maliit"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"May makikitang maliit na orasan sa sulok ng iyong screen"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Ilapat ang mga pagbabago sa font ng orasan"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"I-undo ang mga pagbabago sa font ng orasan"</string>
     <string name="grid_title" msgid="1688173478777254123">"Grid ng app"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Shape ng app at layout"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Layout"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Ilapat"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"I-tap para ma-edit"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Gamitin ang kasalukuyang wallpaper"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 3cfce23..7d44690 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Saat rengi ve boyutu"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Saat rengi ve boyutu"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Stil"</string>
     <string name="clock_color" msgid="8081608867289156163">"Renk"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Kırmızı"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Turuncu"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Büyük"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Küçük"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Ekranınızın köşesinde küçük bir saat görünür"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Saat yazı tipi değişikliklerini uygula"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Saat yazı tipi değişikliklerini geri al"</string>
     <string name="grid_title" msgid="1688173478777254123">"Uygulama tablosu"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Uygulama şekli ve düzeni"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Düzen"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Uygula"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Düzenlemek için dokunun"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Geçerli duvar kağıdını sakla"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index f44ff5b..a675883 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Колір і розмір год."</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Колір і розмір годинника"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Стиль"</string>
     <string name="clock_color" msgid="8081608867289156163">"Колір"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Червоний"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Оранжевий"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Великий"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Малий"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"У куті екрана відображається маленький годинник"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Застосувати зміни шрифту годинника"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Скасувати зміни шрифту годинника"</string>
     <string name="grid_title" msgid="1688173478777254123">"Сітка додатків"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Форма й макет додатка"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Макет"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Застосувати"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Торкніться, щоб змінити"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Зберегти поточний фоновий малюнок"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 18eb802..8f5bb64 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"گھڑی کا رنگ و سائز"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"گھڑی کا رنگ اور سائز"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>، <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"اسٹائل"</string>
     <string name="clock_color" msgid="8081608867289156163">"رنگ"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"سرخ"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"نارنجی"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"بڑا"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"چھوٹا"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"آپ کی اسکرین کے کونے میں ایک چھوٹی گھڑی دکھائی دیتی ہے"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"گھڑی کے فونٹ کی تبدیلیاں لاگو کریں"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"گھڑی کے فونٹ کی تبدیلیاں کالعدم کریں"</string>
     <string name="grid_title" msgid="1688173478777254123">"ایپ گرڈ"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"ایپ شیپ و لے آؤٹ"</string>
+    <string name="grid_layout" msgid="370175667652663686">"لے آؤٹ"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"لاگو کریں"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"ترمیم کرنے کے لیے تھپتھپائيں"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"حالیہ وال پیپر رکھیں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 1295959..2f88265 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Soat rangi va hajmi"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Soat rangi va hajmi"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Uslub"</string>
     <string name="clock_color" msgid="8081608867289156163">"Rang"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Qizil"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Toʻq sariq"</string>
@@ -39,10 +40,14 @@
     <string name="clock_size" msgid="5028923902364418263">"Hajmi"</string>
     <string name="clock_size_dynamic" msgid="1023930312455061642">"Dinamik"</string>
     <string name="clock_size_dynamic_description" msgid="2776620745774561662">"Soat hajmi ekran qulfidagi kontent asosida oʻzgaradi"</string>
-    <string name="clock_size_large" msgid="3143248715744138979">"Yirik"</string>
+    <string name="clock_size_large" msgid="3143248715744138979">"Katta"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Kichik"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Ekran chekkasida kichik soat chiqishi"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Soat shrifti oʻzgarishlarini qoʻllash"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Soat shrifti oʻzgarishlarini bekor qilish"</string>
     <string name="grid_title" msgid="1688173478777254123">"Ilovalar jadvali"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Ilova shakli va maketi"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Maket"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Tatbiq etish"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Tahrirlash uchun tegining"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Joriy fon rasmini saqlab qolish"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 9c4bba6..060152c 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Màu và kích thước đồng hồ"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Màu và kích thước đồng hồ"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Kiểu"</string>
     <string name="clock_color" msgid="8081608867289156163">"Màu"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Đỏ"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Cam"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Lớn"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Nhỏ"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Một chiếc đồng hồ nhỏ hiển thị ở góc màn hình"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Áp dụng các thay đổi về phông chữ đồng hồ"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Huỷ các thay đổi về phông chữ đồng hồ"</string>
     <string name="grid_title" msgid="1688173478777254123">"Lưới ứng dụng"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Hình dạng ứng dụng và bố cục"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Bố cục"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Áp dụng"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Nhấn để chỉnh sửa"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Giữ hình nền hiện tại"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 3bf17dd..1e5278b 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"时钟颜色和尺寸"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"时钟颜色和尺寸"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>、<xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"样式"</string>
     <string name="clock_color" msgid="8081608867289156163">"颜色"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"红色"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"橙色"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"大"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"小"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"一个小型时钟显示在界面一角"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"应用时钟字体更改"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"撤消时钟字体更改"</string>
     <string name="grid_title" msgid="1688173478777254123">"应用网格"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"应用形状和布局"</string>
+    <string name="grid_layout" msgid="370175667652663686">"布局"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"应用"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"点按即可修改"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"保留当前壁纸"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 59cbd74..0fb7266 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"時鐘顏色及大小"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"時鐘顏色及大小"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>,<xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"樣式"</string>
     <string name="clock_color" msgid="8081608867289156163">"顏色"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"紅色"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"橙色"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"大"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"小"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"在螢幕角落顯示小時鐘"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"套用時鐘字型變更"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"復原時鐘字型變更"</string>
     <string name="grid_title" msgid="1688173478777254123">"應用程式網格"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"應用程式形狀與版面配置"</string>
+    <string name="grid_layout" msgid="370175667652663686">"版面配置"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"套用"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"輕按即可編輯"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"保留目前桌布"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 3143f29..93df262 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"時鐘顏色與大小"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"時鐘顏色與大小"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_2">%2$s</xliff:g>,<xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"樣式"</string>
     <string name="clock_color" msgid="8081608867289156163">"顏色"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"紅色"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"橘色"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"大"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"小"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"在畫面角落顯示小型時鐘"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"套用時鐘字型變更"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"取消時鐘字型變更"</string>
     <string name="grid_title" msgid="1688173478777254123">"應用程式排列顯示"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"應用程式的形狀和版面配置"</string>
+    <string name="grid_layout" msgid="370175667652663686">"版面配置"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"套用"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"輕觸這裡即可編輯"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"繼續使用目前的桌布"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index d1569db..9ef934c 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -26,6 +26,7 @@
     <string name="clock_settings_title" msgid="2050906379377120431">"Umbala wewashi nosayizi"</string>
     <string name="clock_color_and_size_title" msgid="7146791234905111351">"Umbala wewashi nosayizi"</string>
     <string name="clock_color_and_size_description" msgid="6578061553012886817">"<xliff:g id="ID_1">%1$s</xliff:g>, <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="clock_style" msgid="6847711178193804308">"Isitayela"</string>
     <string name="clock_color" msgid="8081608867289156163">"Umbala"</string>
     <string name="clock_color_red" msgid="3843504214807597810">"Okubomvu"</string>
     <string name="clock_color_orange" msgid="4175805201144275804">"Okuwolintshi"</string>
@@ -42,7 +43,11 @@
     <string name="clock_size_large" msgid="3143248715744138979">"Obukhulu"</string>
     <string name="clock_size_small" msgid="2280449912094164133">"Esincane"</string>
     <string name="clock_size_small_description" msgid="4089511196955732480">"Iwashi elincane livela ekhoneni lesikrini sakho"</string>
+    <string name="clock_font_editor_apply" msgid="5965611025879105293">"Faka izinguquko zefonti yewashi"</string>
+    <string name="clock_font_editor_revert" msgid="5307491447405753061">"Hlehlisa ushintsho lwefonti yewashi"</string>
     <string name="grid_title" msgid="1688173478777254123">"Igridi ye-app"</string>
+    <string name="shape_and_grid_title" msgid="9092477491363761054">"Umumo we-app nesakhiwo"</string>
+    <string name="grid_layout" msgid="370175667652663686">"Isakhiwo"</string>
     <string name="apply_theme_btn" msgid="6293081192321303991">"Faka"</string>
     <string name="edit_custom_theme_lbl" msgid="5211377705710775224">"Thepha ukuze uhlele"</string>
     <string name="keep_my_wallpaper" msgid="8012385376769568517">"Gcina isithombe sangemuva samanje"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 2f9daae..9c5e84d 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -53,6 +53,9 @@
     <dimen name="theme_option_font_sample_width">52dp</dimen>
     <dimen name="theme_option_sample_margin">10dp</dimen>
 
+    <!-- Dimensions for the color options -->
+    <dimen name="color_options_selected_option_height">102dp</dimen>
+
     <!-- Note, using dp instead of sp as this text is more like a "snapshot" of the font -->
     <dimen name="theme_option_font_text_size">20dp</dimen>
     <dimen name="theme_option_font_min_text_size">15dp</dimen>
@@ -119,8 +122,6 @@
     <!-- For a corner radius of this size or larger, we'll preview a rounded qsb widget. -->
     <dimen name="roundCornerThreshold">16dp</dimen>
 
-    <dimen name="min_taptarget_height">48dp</dimen>
-
     <!--  For the style info preview sheet. -->
     <dimen name="theme_info_margin">12dp</dimen>
     <dimen name="theme_info_icon_size">24dp</dimen>
@@ -156,6 +157,8 @@
     <dimen name="keyguard_quick_affordance_icon_container_size">74dp</dimen>
     <!-- Size for the icon of a quick affordance for the lock screen in the picker experience. -->
     <dimen name="keyguard_quick_affordance_icon_size">24dp</dimen>
+    <dimen name="keyguard_quick_affordance_background_size">64dp</dimen>
+    <dimen name="keyguard_quick_affordance_background_margin_bottom">8dp</dimen>
 
     <dimen name="clock_carousel_item_width">190dp</dimen>
     <dimen name="clock_carousel_item_margin">16dp</dimen>
@@ -175,4 +178,27 @@
     <!-- Notification item dimensions -->
     <dimen name="notification_section_title_padding">8dp</dimen>
 
+    <!-- Floating sheet dimensions -->
+    <dimen name="floating_sheet_content_vertical_padding">20dp</dimen>
+    <dimen name="floating_sheet_content_horizontal_padding">20dp</dimen>
+    <dimen name="floating_sheet_horizontal_padding">16dp</dimen>
+    <dimen name="floating_sheet_tab_toolbar_vertical_margin">8dp</dimen>
+    <dimen name="floating_sheet_tab_clock_font_toolbar_top_margin">16dp</dimen>
+    <dimen name="floating_sheet_tab_clock_font_toolbar_bottom_margin">8dp</dimen>
+    <dimen name="floating_sheet_list_item_horizontal_space">4dp</dimen>
+    <dimen name="floating_sheet_list_item_vertical_space">4dp</dimen>
+    <dimen name="floating_sheet_clock_style_option_size">82dp</dimen>
+    <dimen name="floating_sheet_clock_edit_icon_size">48dp</dimen>
+    <dimen name="floating_sheet_clock_style_thumbnail_margin">12dp</dimen>
+    <dimen name="floating_sheet_clock_style_clock_size_text_margin_end">16dp</dimen>
+    <dimen name="floating_sheet_color_option_size">54dp</dimen>
+    <dimen name="floating_sheet_color_option_stroke_width">3dp</dimen>
+    <dimen name="customization_option_entry_shortcut_icon_size">20dp</dimen>
+
+    <!-- Clock font control dimensions -->
+    <dimen name="clock_font_axis_name_width">64dp</dimen>
+    <dimen name="clock_axis_control_padding_start">16dp</dimen>
+    <dimen name="clock_axis_control_row_vertical_padding">10dp</dimen>
+    <dimen name="clock_font_control_switch_padding_horizontal">38dp</dimen>
+    <dimen name="clock_font_apply_padding_start">8dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 271a74c..586117f 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -45,6 +45,9 @@
     <!-- Description of a section of the customization picker where the user can configure clock color and size, e.g. Violet, small. [CHAR LIMIT=NONE] -->
     <string name="clock_color_and_size_description"><xliff:g name="color">%1$s</xliff:g>, <xliff:g name="size">%2$s</xliff:g></string>
 
+    <!-- Title of a tab to change the clock style. [CHAR LIMIT=15] -->
+    <string name="clock_style">Style</string>
+
     <!-- Title of a tab to change the clock color. [CHAR LIMIT=15] -->
     <string name="clock_color">Color</string>
 
@@ -93,10 +96,24 @@
     <!-- Description of a radio button to apply clock size small. [CHAR LIMIT=NONE] -->
     <string name="clock_size_small_description">A small clock shows in the corner of your screen</string>
 
+    <!-- Description for clock font editor axis apply button. [CHAR LIMIT=NONE] -->
+    <string name="clock_font_editor_apply">Apply clock font changes</string>
+
+    <!-- Description for clock font editor axis revert button. [CHAR LIMIT=NONE] -->
+    <string name="clock_font_editor_revert">Undo clock font changes</string>
+
     <!-- Title of a section of the customization picker where the user can select a Grid size for
         the home screen. [CHAR LIMIT=15] -->
     <string name="grid_title">App grid</string>
 
+    <!-- Title of a section of the customization picker where the user can select app shapes and
+        grid layouts for the home screen. [CHAR LIMIT=32] -->
+    <string name="shape_and_grid_title">App shape &amp; layout</string>
+
+    <!-- Tab title that switch to app grid customization section, where people can customization
+        the grid layout of the apps -->
+    <string name="grid_layout">Layout</string>
+
     <!-- Label for a button that allows the user to apply the currently selected Theme.
         [CHAR LIMIT=20] -->
     <string name="apply_theme_btn">Apply</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index c2710f6..fc2fd8a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -130,6 +130,18 @@
         <item name="android:lineHeight">16sp</item>
     </style>
 
+    <style name="CustomizationOptionEntryTitleTextStyle">
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:textColor">@color/system_on_surface</item>
+        <item name="android:textSize">20sp</item>
+    </style>
+
+    <style name="CustomizationOptionEntrySubtitleTextStyle">
+        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+        <item name="android:textColor">@color/system_on_surface_variant</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+
     <style name="BetaTagTextStyle" parent="SectionTitleTextStyle">
         <item name="android:textSize">12sp</item>
         <item name="android:lineHeight">15dp</item>
diff --git a/src/com/android/customization/model/color/ColorOption.java b/src/com/android/customization/model/color/ColorOption.java
index ae695dd..18414a4 100644
--- a/src/com/android/customization/model/color/ColorOption.java
+++ b/src/com/android/customization/model/color/ColorOption.java
@@ -19,10 +19,10 @@
 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SYSTEM_PALETTE;
 
 import android.content.Context;
-import android.graphics.Color;
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.ColorInt;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.customization.model.CustomizationManager;
@@ -59,11 +59,13 @@
     private final Style mStyle;
     private final int mIndex;
     private CharSequence mContentDescription;
+    private final @ColorInt int mSeedColor;
 
     protected ColorOption(String title, Map<String, String> overlayPackages, boolean isDefault,
-            Style style, int index) {
+            int seedColor, Style style, int index) {
         mTitle = title;
         mIsDefault = isDefault;
+        mSeedColor = seedColor;
         mStyle = style;
         mIndex = index;
         mPackagesByCategory = Collections.unmodifiableMap(removeNullValues(overlayPackages));
@@ -102,20 +104,8 @@
         }
     }
 
-    /**
-     * Gets the seed color from the overlay packages for logging.
-     *
-     * @return an int representing the seed color, or NULL_SEED_COLOR
-     */
-    public int getSeedColorForLogging() {
-        String seedColor = mPackagesByCategory.get(OVERLAY_CATEGORY_SYSTEM_PALETTE);
-        if (seedColor == null || seedColor.isEmpty()) {
-            return ThemesUserEventLogger.NULL_SEED_COLOR;
-        }
-        if (!seedColor.startsWith("#")) {
-            seedColor = "#" + seedColor;
-        }
-        return Color.parseColor(seedColor);
+    public @ColorInt int getSeedColor() {
+        return mSeedColor;
     }
 
     /**
diff --git a/src/com/android/customization/model/color/ColorOptionImpl.kt b/src/com/android/customization/model/color/ColorOptionImpl.kt
index ecef2a7..3b8fbc8 100644
--- a/src/com/android/customization/model/color/ColorOptionImpl.kt
+++ b/src/com/android/customization/model/color/ColorOptionImpl.kt
@@ -33,16 +33,15 @@
     overlayPackages: Map<String, String?>,
     isDefault: Boolean,
     private val source: String?,
+    seedColor: Int,
     style: Style,
     index: Int,
     private val previewInfo: PreviewInfo,
     val type: ColorType,
-) : ColorOption(title, overlayPackages, isDefault, style, index) {
+) : ColorOption(title, overlayPackages, isDefault, seedColor, style, index) {
 
-    class PreviewInfo(
-        @ColorInt val lightColors: IntArray,
-        @ColorInt val darkColors: IntArray,
-    ) : ColorOption.PreviewInfo {
+    class PreviewInfo(@ColorInt val lightColors: IntArray, @ColorInt val darkColors: IntArray) :
+        ColorOption.PreviewInfo {
         @ColorInt
         fun resolveColors(darkTheme: Boolean): IntArray {
             return if (darkTheme) darkColors else lightColors
@@ -89,6 +88,7 @@
 
         @ColorSource var source: String? = null
         var isDefault = false
+        @ColorInt var seedColor = 0
         var style = Style.TONAL_SPOT
         var index = 0
         var packages: MutableMap<String, String?> = HashMap()
@@ -100,10 +100,11 @@
                 packages,
                 isDefault,
                 source,
+                seedColor,
                 style,
                 index,
                 createPreviewInfo(),
-                type
+                type,
             )
         }
 
diff --git a/src/com/android/customization/model/color/ColorProvider.kt b/src/com/android/customization/model/color/ColorProvider.kt
index 2d7037e..fb9fcfc 100644
--- a/src/com/android/customization/model/color/ColorProvider.kt
+++ b/src/com/android/customization/model/color/ColorProvider.kt
@@ -39,6 +39,7 @@
 import com.android.systemui.monet.ColorScheme
 import com.android.systemui.monet.Style
 import com.android.themepicker.R
+import com.android.wallpaper.config.BaseFlags
 import com.android.wallpaper.module.InjectorProvider
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -96,16 +97,22 @@
         homeWallpaperColors: WallpaperColors?,
         lockWallpaperColors: WallpaperColors?,
     ) {
-        val wallpaperColorsChanged =
-            this.homeWallpaperColors != homeWallpaperColors ||
-                this.lockWallpaperColors != lockWallpaperColors
-        if (wallpaperColorsChanged || reload) {
-            loadSeedColors(
-                homeWallpaperColors,
-                lockWallpaperColors,
-            )
-            this.homeWallpaperColors = homeWallpaperColors
-            this.lockWallpaperColors = lockWallpaperColors
+        val isNewPickerUi = BaseFlags.get().isNewPickerUi()
+        if (isNewPickerUi) {
+            val wallpaperColorsChanged = this.homeWallpaperColors != homeWallpaperColors
+            if (wallpaperColorsChanged || reload) {
+                loadSeedColors(homeWallpaperColors)
+                this.homeWallpaperColors = homeWallpaperColors
+            }
+        } else {
+            val wallpaperColorsChanged =
+                this.homeWallpaperColors != homeWallpaperColors ||
+                    this.lockWallpaperColors != lockWallpaperColors
+            if (wallpaperColorsChanged || reload) {
+                loadSeedColors(homeWallpaperColors, lockWallpaperColors)
+                this.homeWallpaperColors = homeWallpaperColors
+                this.lockWallpaperColors = lockWallpaperColors
+            }
         }
 
         scope.launch {
@@ -135,7 +142,7 @@
 
     private fun loadSeedColors(
         homeWallpaperColors: WallpaperColors?,
-        lockWallpaperColors: WallpaperColors?,
+        lockWallpaperColors: WallpaperColors? = null,
     ) {
         if (homeWallpaperColors == null) return
 
@@ -166,13 +173,7 @@
                 bundles,
             )
         } else {
-            buildColorSeeds(
-                homeWallpaperColors,
-                colorsPerSource,
-                COLOR_SOURCE_HOME,
-                true,
-                bundles,
-            )
+            buildColorSeeds(homeWallpaperColors, colorsPerSource, COLOR_SOURCE_HOME, true, bundles)
         }
         wallpaperColorBundles = bundles
     }
@@ -206,9 +207,10 @@
             val builder = ColorOptionImpl.Builder()
             builder.lightColors = getLightColorPreview(lightColorScheme)
             builder.darkColors = getDarkColorPreview(darkColorScheme)
+            builder.seedColor = colorInt
             builder.addOverlayPackage(
                 OVERLAY_CATEGORY_SYSTEM_PALETTE,
-                if (isDefault) "" else toColorString(colorInt)
+                if (isDefault) "" else toColorString(colorInt),
             )
             builder.title =
                 when (style) {
@@ -312,12 +314,7 @@
                 Style.RAINBOW -> intArrayOf(colorScheme.accent1.s200, colorScheme.accent1.s200)
                 else -> intArrayOf(colorScheme.accent1.s100, colorScheme.accent1.s100)
             }
-        return intArrayOf(
-            colors[0],
-            colors[1],
-            colors[0],
-            colors[1],
-        )
+        return intArrayOf(colors[0], colors[1], colors[0], colors[1])
     }
 
     private suspend fun loadPreset() =
@@ -392,6 +389,7 @@
         val darkColor = darkColorScheme.accentColor
         var lightColors = intArrayOf(lightColor, lightColor, lightColor, lightColor)
         var darkColors = intArrayOf(darkColor, darkColor, darkColor, darkColor)
+        builder.seedColor = colorFromStub
         builder.addOverlayPackage(OVERLAY_CATEGORY_COLOR, toColorString(colorFromStub))
         builder.addOverlayPackage(OVERLAY_CATEGORY_SYSTEM_PALETTE, toColorString(colorFromStub))
         if (style != null) {
@@ -426,7 +424,7 @@
                 if (wallpaperColors.isNotEmpty()) {
                     wallpaperColors.add(
                         1,
-                        buildPreset(it, -1, Style.MONOCHROMATIC, ColorType.WALLPAPER_COLOR)
+                        buildPreset(it, -1, Style.MONOCHROMATIC, ColorType.WALLPAPER_COLOR),
                     )
                 }
             }
diff --git a/src/com/android/customization/model/grid/DefaultShapeGridManager.kt b/src/com/android/customization/model/grid/DefaultShapeGridManager.kt
new file mode 100644
index 0000000..966f68e
--- /dev/null
+++ b/src/com/android/customization/model/grid/DefaultShapeGridManager.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.model.grid
+
+import android.content.ContentValues
+import android.content.Context
+import com.android.wallpaper.R
+import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
+import com.android.wallpaper.util.PreviewUtils
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+@Singleton
+class DefaultShapeGridManager
+@Inject
+constructor(
+    @ApplicationContext private val context: Context,
+    @BackgroundDispatcher private val bgDispatcher: CoroutineDispatcher,
+) : ShapeGridManager {
+
+    private val authorityMetadataKey: String =
+        context.getString(R.string.grid_control_metadata_name)
+    private val previewUtils: PreviewUtils = PreviewUtils(context, authorityMetadataKey)
+
+    override suspend fun getGridOptions(): List<GridOptionModel>? =
+        withContext(bgDispatcher) {
+            if (previewUtils.supportsPreview()) {
+                context.contentResolver
+                    .query(previewUtils.getUri(GRID_OPTIONS), null, null, null, null)
+                    ?.use { cursor ->
+                        buildList {
+                            while (cursor.moveToNext()) {
+                                val rows = cursor.getInt(cursor.getColumnIndex(COL_ROWS))
+                                val cols = cursor.getInt(cursor.getColumnIndex(COL_COLS))
+                                val title =
+                                    cursor.getString(cursor.getColumnIndex(COL_GRID_TITLE))
+                                        ?: context.getString(
+                                            com.android.themepicker.R.string.grid_title_pattern,
+                                            cols,
+                                            rows,
+                                        )
+                                add(
+                                    GridOptionModel(
+                                        key = cursor.getString(cursor.getColumnIndex(COL_GRID_KEY)),
+                                        title = title,
+                                        isCurrent =
+                                            cursor
+                                                .getString(cursor.getColumnIndex(COL_IS_DEFAULT))
+                                                .toBoolean(),
+                                        rows = rows,
+                                        cols = cols,
+                                    )
+                                )
+                            }
+                        }
+                    }
+            } else {
+                null
+            }
+        }
+
+    override suspend fun getShapeOptions(): List<ShapeOptionModel>? =
+        withContext(bgDispatcher) {
+            if (previewUtils.supportsPreview()) {
+                context.contentResolver
+                    .query(previewUtils.getUri(SHAPE_OPTIONS), null, null, null, null)
+                    ?.use { cursor ->
+                        buildList {
+                            while (cursor.moveToNext()) {
+                                add(
+                                    ShapeOptionModel(
+                                        key =
+                                            cursor.getString(cursor.getColumnIndex(COL_SHAPE_KEY)),
+                                        title =
+                                            cursor.getString(
+                                                cursor.getColumnIndex(COL_SHAPE_TITLE)
+                                            ),
+                                        path = cursor.getString(cursor.getColumnIndex(COL_PATH)),
+                                        isCurrent =
+                                            cursor
+                                                .getString(cursor.getColumnIndex(COL_IS_DEFAULT))
+                                                .toBoolean(),
+                                    )
+                                )
+                            }
+                        }
+                    }
+            } else {
+                null
+            }
+        }
+
+    override fun applyShapeGridOption(shapeKey: String, gridKey: String): Int {
+        return context.contentResolver.update(
+            previewUtils.getUri(SHAPE_GRID),
+            ContentValues().apply {
+                put(COL_SHAPE_KEY, shapeKey)
+                put(COL_GRID_KEY, gridKey)
+            },
+            null,
+            null,
+        )
+    }
+
+    companion object {
+        const val SHAPE_OPTIONS: String = "shape_options"
+        const val GRID_OPTIONS: String = "list_options"
+        const val SHAPE_GRID: String = "default_grid"
+        const val COL_SHAPE_KEY: String = "shape_key"
+        const val COL_GRID_KEY: String = "name"
+        const val COL_GRID_NAME: String = "grid_name"
+        const val COL_GRID_TITLE: String = "grid_title"
+        const val COL_SHAPE_TITLE: String = "shape_title"
+        const val COL_ROWS: String = "rows"
+        const val COL_COLS: String = "cols"
+        const val COL_IS_DEFAULT: String = "is_default"
+        const val COL_PATH: String = "path"
+    }
+}
diff --git a/src/com/android/customization/model/grid/GridOptionModel.kt b/src/com/android/customization/model/grid/GridOptionModel.kt
new file mode 100644
index 0000000..3e10a01
--- /dev/null
+++ b/src/com/android/customization/model/grid/GridOptionModel.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.model.grid
+
+data class GridOptionModel(
+    val key: String,
+    val title: String,
+    val isCurrent: Boolean,
+    val rows: Int,
+    val cols: Int,
+)
diff --git a/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java b/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
index 8350248..f08acc9 100644
--- a/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
+++ b/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
@@ -47,6 +47,7 @@
     private static final String DEFAULT_GRID = "default_grid";
 
     private static final String COL_NAME = "name";
+    private static final String COL_GRID_TITLE = "grid_title";
     private static final String COL_ROWS = "rows";
     private static final String COL_COLS = "cols";
     private static final String COL_PREVIEW_COUNT = "preview_count";
@@ -91,11 +92,15 @@
             mOptions = new ArrayList<>();
             while(c.moveToNext()) {
                 String name = c.getString(c.getColumnIndex(COL_NAME));
+                String title = c.getString(c.getColumnIndex(COL_GRID_TITLE));
+
                 int rows = c.getInt(c.getColumnIndex(COL_ROWS));
                 int cols = c.getInt(c.getColumnIndex(COL_COLS));
                 int previewCount = c.getInt(c.getColumnIndex(COL_PREVIEW_COUNT));
                 boolean isSet = Boolean.parseBoolean(c.getString(c.getColumnIndex(COL_IS_DEFAULT)));
-                String title = mContext.getString(R.string.grid_title_pattern, cols, rows);
+                if (title == null) {
+                    title = mContext.getString(R.string.grid_title_pattern, cols, rows);
+                }
                 mOptions.add(new GridOption(title, name, isSet, rows, cols,
                         mPreviewUtils.getUri(PREVIEW), previewCount, iconPath));
             }
diff --git a/src/com/android/customization/model/grid/ShapeGridManager.kt b/src/com/android/customization/model/grid/ShapeGridManager.kt
new file mode 100644
index 0000000..0a23346
--- /dev/null
+++ b/src/com/android/customization/model/grid/ShapeGridManager.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.model.grid
+
+interface ShapeGridManager {
+
+    suspend fun getGridOptions(): List<GridOptionModel>?
+
+    suspend fun getShapeOptions(): List<ShapeOptionModel>?
+
+    fun applyShapeGridOption(shapeKey: String, gridKey: String): Int
+}
diff --git a/src/com/android/customization/model/grid/ShapeOptionModel.kt b/src/com/android/customization/model/grid/ShapeOptionModel.kt
new file mode 100644
index 0000000..c3ed192
--- /dev/null
+++ b/src/com/android/customization/model/grid/ShapeOptionModel.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.model.grid
+
+data class ShapeOptionModel(
+    val key: String,
+    val title: String,
+    val path: String,
+    val isCurrent: Boolean,
+)
diff --git a/src/com/android/customization/module/CustomizationInjector.kt b/src/com/android/customization/module/CustomizationInjector.kt
index d761598..ca42ef3 100644
--- a/src/com/android/customization/module/CustomizationInjector.kt
+++ b/src/com/android/customization/module/CustomizationInjector.kt
@@ -22,10 +22,8 @@
 import com.android.customization.picker.clock.ui.view.ClockViewFactory
 import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
 import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
-import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
 import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel
 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
-import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.wallpaper.module.Injector
 import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository
 
@@ -36,19 +34,7 @@
         context: Context,
     ): KeyguardQuickAffordancePickerInteractor
 
-    fun getClockRegistry(context: Context): ClockRegistry?
-
-    fun getClockPickerInteractor(context: Context): ClockPickerInteractor
-
-    fun getColorPickerInteractor(
-        context: Context,
-        wallpaperColorsRepository: WallpaperColorsRepository,
-    ): ColorPickerInteractor
-
-    fun getColorPickerViewModelFactory(
-        context: Context,
-        wallpaperColorsRepository: WallpaperColorsRepository,
-    ): ColorPickerViewModel.Factory
+    fun getColorPickerViewModelFactory(context: Context): ColorPickerViewModel.Factory
 
     fun getClockCarouselViewModelFactory(
         interactor: ClockPickerInteractor,
diff --git a/src/com/android/customization/module/DefaultCustomizationPreferences.kt b/src/com/android/customization/module/DefaultCustomizationPreferences.kt
index 49fd1a9..0ef4a1d 100644
--- a/src/com/android/customization/module/DefaultCustomizationPreferences.kt
+++ b/src/com/android/customization/module/DefaultCustomizationPreferences.kt
@@ -17,8 +17,14 @@
 
 import android.content.Context
 import com.android.wallpaper.module.DefaultWallpaperPreferences
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+import javax.inject.Singleton
 
-open class DefaultCustomizationPreferences(context: Context) :
+@Singleton
+open class DefaultCustomizationPreferences
+@Inject
+constructor(@ApplicationContext context: Context) :
     DefaultWallpaperPreferences(context), CustomizationPreferences {
 
     override fun getSerializedCustomThemes(): String? {
diff --git a/src/com/android/customization/module/DefaultCustomizationSections.java b/src/com/android/customization/module/DefaultCustomizationSections.java
index 33cb620..e9b7b2d 100644
--- a/src/com/android/customization/module/DefaultCustomizationSections.java
+++ b/src/com/android/customization/module/DefaultCustomizationSections.java
@@ -19,6 +19,7 @@
 import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor;
 import com.android.customization.picker.color.ui.section.ColorSectionController;
 import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel;
+import com.android.customization.picker.grid.domain.interactor.GridInteractor;
 import com.android.customization.picker.grid.ui.section.GridSectionController;
 import com.android.customization.picker.notifications.ui.section.NotificationSectionController;
 import com.android.customization.picker.notifications.ui.viewmodel.NotificationSectionViewModel;
@@ -61,6 +62,7 @@
     private final ClockViewFactory mClockViewFactory;
     private final ThemedIconSnapshotRestorer mThemedIconSnapshotRestorer;
     private final ThemedIconInteractor mThemedIconInteractor;
+    private final GridInteractor mGridInteractor;
     private final ColorPickerInteractor mColorPickerInteractor;
     private final ThemesUserEventLogger mThemesUserEventLogger;
 
@@ -75,6 +77,7 @@
             ClockViewFactory clockViewFactory,
             ThemedIconSnapshotRestorer themedIconSnapshotRestorer,
             ThemedIconInteractor themedIconInteractor,
+            GridInteractor gridInteractor,
             ColorPickerInteractor colorPickerInteractor,
             ThemesUserEventLogger themesUserEventLogger) {
         mColorPickerViewModelFactory = colorPickerViewModelFactory;
@@ -86,6 +89,7 @@
         mClockViewFactory = clockViewFactory;
         mThemedIconSnapshotRestorer = themedIconSnapshotRestorer;
         mThemedIconInteractor = themedIconInteractor;
+        mGridInteractor = gridInteractor;
         mColorPickerInteractor = colorPickerInteractor;
         mThemesUserEventLogger = themesUserEventLogger;
         mColorContrastSectionViewModelFactory = colorContrastSectionViewModelFactory;
@@ -125,6 +129,7 @@
                         sectionNavigationController,
                         wallpaperInteractor,
                         mThemedIconInteractor,
+                        mGridInteractor,
                         mColorPickerInteractor,
                         wallpaperManager,
                         isTwoPaneAndSmallWidth,
@@ -139,6 +144,7 @@
                                 wallpaperPreviewNavigator,
                                 wallpaperInteractor,
                                 mThemedIconInteractor,
+                                mGridInteractor,
                                 mColorPickerInteractor,
                                 wallpaperManager,
                                 isTwoPaneAndSmallWidth,
@@ -210,8 +216,7 @@
                         new GridSectionController(
                                 GridOptionsManager.getInstance(activity),
                                 sectionNavigationController,
-                                lifecycleOwner,
-                                /* isRevampedUiEnabled= */ true));
+                                lifecycleOwner));
                 break;
         }
 
diff --git a/src/com/android/customization/module/ThemePickerInjector.kt b/src/com/android/customization/module/ThemePickerInjector.kt
index da25950..a022d00 100644
--- a/src/com/android/customization/module/ThemePickerInjector.kt
+++ b/src/com/android/customization/module/ThemePickerInjector.kt
@@ -22,7 +22,6 @@
 import android.content.Intent
 import android.content.res.Resources
 import android.net.Uri
-import android.text.TextUtils
 import androidx.activity.ComponentActivity
 import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.LifecycleOwner
@@ -39,15 +38,12 @@
 import com.android.customization.model.themedicon.domain.interactor.ThemedIconInteractor
 import com.android.customization.model.themedicon.domain.interactor.ThemedIconSnapshotRestorer
 import com.android.customization.module.logging.ThemesUserEventLogger
-import com.android.customization.picker.clock.data.repository.ClockPickerRepositoryImpl
-import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
 import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
 import com.android.customization.picker.clock.domain.interactor.ClockPickerSnapshotRestorer
 import com.android.customization.picker.clock.ui.view.ClockViewFactory
-import com.android.customization.picker.clock.ui.view.ClockViewFactoryImpl
+import com.android.customization.picker.clock.ui.view.ThemePickerClockViewFactory
 import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
 import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
-import com.android.customization.picker.color.data.repository.ColorPickerRepositoryImpl
 import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
 import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer
 import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel
@@ -57,29 +53,34 @@
 import com.android.customization.picker.grid.ui.viewmodel.GridScreenViewModel
 import com.android.customization.picker.notifications.domain.interactor.NotificationsSnapshotRestorer
 import com.android.customization.picker.notifications.ui.viewmodel.NotificationSectionViewModel
-import com.android.customization.picker.quickaffordance.data.repository.KeyguardQuickAffordancePickerRepository
 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordanceSnapshotRestorer
 import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordancePickerViewModel
 import com.android.customization.picker.settings.ui.viewmodel.ColorContrastSectionViewModel
 import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
-import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
 import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
+import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
+import com.android.systemui.shared.settings.data.repository.SystemSettingsRepository
 import com.android.wallpaper.config.BaseFlags
 import com.android.wallpaper.module.CustomizationSections
 import com.android.wallpaper.module.FragmentFactory
+import com.android.wallpaper.module.NetworkStatusNotifier
+import com.android.wallpaper.module.PartnerProvider
 import com.android.wallpaper.module.WallpaperPicker2Injector
+import com.android.wallpaper.module.WallpaperPreferences
+import com.android.wallpaper.module.logging.UserEventLogger
+import com.android.wallpaper.network.Requester
 import com.android.wallpaper.picker.CustomizationPickerActivity
-import com.android.wallpaper.picker.customization.data.content.WallpaperClientImpl
+import com.android.wallpaper.picker.category.wrapper.WallpaperCategoryWrapper
+import com.android.wallpaper.picker.customization.data.content.WallpaperClient
 import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository
-import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository
 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor
 import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
 import com.android.wallpaper.picker.di.modules.MainDispatcher
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
-import com.android.wallpaper.util.ScreenSizeCalculator
+import com.android.wallpaper.system.UiModeManagerWrapper
+import com.android.wallpaper.util.DisplayUtils
 import dagger.Lazy
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -91,31 +92,59 @@
 @Inject
 constructor(
     @MainDispatcher private val mainScope: CoroutineScope,
-    @MainDispatcher private val mainDispatcher: CoroutineDispatcher,
     @BackgroundDispatcher private val bgScope: CoroutineScope,
     @BackgroundDispatcher private val bgDispatcher: CoroutineDispatcher,
-) : WallpaperPicker2Injector(mainScope, bgDispatcher), CustomizationInjector {
+    private val colorContrastSectionViewModelFactory: Lazy<ColorContrastSectionViewModel.Factory>,
+    private val keyguardQuickAffordancePickerInteractor:
+        Lazy<KeyguardQuickAffordancePickerInteractor>,
+    private val keyguardQuickAffordanceSnapshotRestorer:
+        Lazy<KeyguardQuickAffordanceSnapshotRestorer>,
+    private val themesUserEventLogger: Lazy<ThemesUserEventLogger>,
+    private val colorPickerInteractor: Lazy<ColorPickerInteractor>,
+    private val colorPickerSnapshotRestorer: Lazy<ColorPickerSnapshotRestorer>,
+    private val clockRegistry: Lazy<ClockRegistry>,
+    private val secureSettingsRepository: Lazy<SecureSettingsRepository>,
+    private val systemSettingsRepository: Lazy<SystemSettingsRepository>,
+    private val clockPickerInteractor: Lazy<ClockPickerInteractor>,
+    private val clockPickerSnapshotRestorer: Lazy<ClockPickerSnapshotRestorer>,
+    displayUtils: Lazy<DisplayUtils>,
+    requester: Lazy<Requester>,
+    networkStatusNotifier: Lazy<NetworkStatusNotifier>,
+    partnerProvider: Lazy<PartnerProvider>,
+    val uiModeManager: Lazy<UiModeManagerWrapper>,
+    userEventLogger: Lazy<UserEventLogger>,
+    injectedWallpaperClient: Lazy<WallpaperClient>,
+    private val injectedWallpaperInteractor: Lazy<WallpaperInteractor>,
+    prefs: Lazy<WallpaperPreferences>,
+    wallpaperColorsRepository: Lazy<WallpaperColorsRepository>,
+    defaultWallpaperCategoryWrapper: Lazy<WallpaperCategoryWrapper>,
+) :
+    WallpaperPicker2Injector(
+        mainScope,
+        displayUtils,
+        requester,
+        networkStatusNotifier,
+        partnerProvider,
+        uiModeManager,
+        userEventLogger,
+        injectedWallpaperClient,
+        injectedWallpaperInteractor,
+        prefs,
+        wallpaperColorsRepository,
+        defaultWallpaperCategoryWrapper,
+    ),
+    CustomizationInjector {
     private var customizationSections: CustomizationSections? = null
-    private var wallpaperInteractor: WallpaperInteractor? = null
-    private var keyguardQuickAffordancePickerInteractor: KeyguardQuickAffordancePickerInteractor? =
-        null
     private var keyguardQuickAffordancePickerViewModelFactory:
         KeyguardQuickAffordancePickerViewModel.Factory? =
         null
-    private var customizationProviderClient: CustomizationProviderClient? = null
     private var fragmentFactory: FragmentFactory? = null
-    private var keyguardQuickAffordanceSnapshotRestorer: KeyguardQuickAffordanceSnapshotRestorer? =
-        null
     private var notificationsSnapshotRestorer: NotificationsSnapshotRestorer? = null
-    private var clockPickerInteractor: ClockPickerInteractor? = null
     private var clockCarouselViewModelFactory: ClockCarouselViewModel.Factory? = null
     private var clockViewFactory: ClockViewFactory? = null
-    private var clockPickerSnapshotRestorer: ClockPickerSnapshotRestorer? = null
     private var notificationSettingsInteractor: NotificationSettingsInteractor? = null
     private var notificationSectionViewModelFactory: NotificationSectionViewModel.Factory? = null
-    private var colorPickerInteractor: ColorPickerInteractor? = null
     private var colorPickerViewModelFactory: ColorPickerViewModel.Factory? = null
-    private var colorPickerSnapshotRestorer: ColorPickerSnapshotRestorer? = null
     private var colorCustomizationManager: ColorCustomizationManager? = null
     private var darkModeSnapshotRestorer: DarkModeSnapshotRestorer? = null
     private var themedIconSnapshotRestorer: ThemedIconSnapshotRestorer? = null
@@ -124,12 +153,6 @@
     private var gridInteractor: GridInteractor? = null
     private var gridSnapshotRestorer: GridSnapshotRestorer? = null
     private var gridScreenViewModelFactory: GridScreenViewModel.Factory? = null
-    private var clockRegistryProvider: ClockRegistryProvider? = null
-
-    // Injected objects, sorted by type
-    @Inject
-    lateinit var colorContrastSectionViewModelFactory: Lazy<ColorContrastSectionViewModel.Factory>
-    @Inject lateinit var themesUserEventLogger: Lazy<ThemesUserEventLogger>
 
     override fun getCustomizationSections(activity: ComponentActivity): CustomizationSections {
         val appContext = activity.applicationContext
@@ -137,23 +160,21 @@
         val resources = activity.resources
         return customizationSections
             ?: DefaultCustomizationSections(
-                    getColorPickerViewModelFactory(
-                        context = appContext,
-                        wallpaperColorsRepository = getWallpaperColorsRepository(),
-                    ),
+                    getColorPickerViewModelFactory(appContext),
                     getKeyguardQuickAffordancePickerViewModelFactory(appContext),
                     colorContrastSectionViewModelFactory.get(),
                     getNotificationSectionViewModelFactory(appContext),
                     getFlags(),
                     getClockCarouselViewModelFactory(
-                        interactor = getClockPickerInteractor(appContext),
+                        interactor = clockPickerInteractor.get(),
                         clockViewFactory = clockViewFactory,
                         resources = resources,
                     ),
                     clockViewFactory,
                     getThemedIconSnapshotRestorer(appContext),
                     getThemedIconInteractor(),
-                    getColorPickerInteractor(appContext, getWallpaperColorsRepository()),
+                    getGridInteractor(appContext),
+                    colorPickerInteractor.get(),
                     getUserEventLogger(),
                 )
                 .also { customizationSections = it }
@@ -180,12 +201,10 @@
         return fragmentFactory ?: ThemePickerFragmentFactory().also { fragmentFactory }
     }
 
-    override fun getSnapshotRestorers(
-        context: Context,
-    ): Map<Int, SnapshotRestorer> {
+    override fun getSnapshotRestorers(context: Context): Map<Int, SnapshotRestorer> {
         return super<WallpaperPicker2Injector>.getSnapshotRestorers(context).toMutableMap().apply {
             this[KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER] =
-                getKeyguardQuickAffordanceSnapshotRestorer(context)
+                keyguardQuickAffordanceSnapshotRestorer.get()
             // TODO(b/285047815): Enable after adding wallpaper id for default static wallpaper
             if (getFlags().isWallpaperRestorerEnabled()) {
                 this[KEY_WALLPAPER_SNAPSHOT_RESTORER] = getWallpaperSnapshotRestorer(context)
@@ -194,9 +213,8 @@
             this[KEY_DARK_MODE_SNAPSHOT_RESTORER] = getDarkModeSnapshotRestorer(context)
             this[KEY_THEMED_ICON_SNAPSHOT_RESTORER] = getThemedIconSnapshotRestorer(context)
             this[KEY_APP_GRID_SNAPSHOT_RESTORER] = getGridSnapshotRestorer(context)
-            this[KEY_COLOR_PICKER_SNAPSHOT_RESTORER] =
-                getColorPickerSnapshotRestorer(context, getWallpaperColorsRepository())
-            this[KEY_CLOCKS_SNAPSHOT_RESTORER] = getClockPickerSnapshotRestorer(context)
+            this[KEY_COLOR_PICKER_SNAPSHOT_RESTORER] = colorPickerSnapshotRestorer.get()
+            this[KEY_CLOCKS_SNAPSHOT_RESTORER] = clockPickerSnapshotRestorer.get()
         }
     }
 
@@ -205,42 +223,13 @@
     }
 
     override fun getWallpaperInteractor(context: Context): WallpaperInteractor {
-        if (getFlags().isMultiCropEnabled()) {
-            return injectedWallpaperInteractor.get()
-        }
-
-        val appContext = context.applicationContext
-        return wallpaperInteractor
-            ?: WallpaperInteractor(
-                    repository =
-                        WallpaperRepository(
-                            scope = getApplicationCoroutineScope(),
-                            client =
-                                WallpaperClientImpl(
-                                    context = appContext,
-                                    wallpaperManager = WallpaperManager.getInstance(appContext),
-                                    wallpaperPreferences = getPreferences(appContext),
-                                ),
-                            wallpaperPreferences = getPreferences(context = appContext),
-                            backgroundDispatcher = bgDispatcher,
-                        ),
-                    shouldHandleReload = {
-                        TextUtils.equals(
-                            getColorCustomizationManager(appContext).currentColorSource,
-                            COLOR_SOURCE_PRESET,
-                        )
-                    }
-                )
-                .also { wallpaperInteractor = it }
+        return injectedWallpaperInteractor.get()
     }
 
     override fun getKeyguardQuickAffordancePickerInteractor(
         context: Context
     ): KeyguardQuickAffordancePickerInteractor {
-        return keyguardQuickAffordancePickerInteractor
-            ?: getKeyguardQuickAffordancePickerInteractorImpl(context).also {
-                keyguardQuickAffordancePickerInteractor = it
-            }
+        return keyguardQuickAffordancePickerInteractor.get()
     }
 
     fun getKeyguardQuickAffordancePickerViewModelFactory(
@@ -257,41 +246,8 @@
                 .also { keyguardQuickAffordancePickerViewModelFactory = it }
     }
 
-    private fun getKeyguardQuickAffordancePickerInteractorImpl(
-        context: Context
-    ): KeyguardQuickAffordancePickerInteractor {
-        val client = getKeyguardQuickAffordancePickerProviderClient(context)
-        val appContext = context.applicationContext
-        return KeyguardQuickAffordancePickerInteractor(
-            KeyguardQuickAffordancePickerRepository(client, getApplicationCoroutineScope()),
-            client
-        ) {
-            getKeyguardQuickAffordanceSnapshotRestorer(appContext)
-        }
-    }
-
-    private fun getKeyguardQuickAffordancePickerProviderClient(
-        context: Context
-    ): CustomizationProviderClient {
-        return customizationProviderClient
-            ?: CustomizationProviderClientImpl(context.applicationContext, bgDispatcher).also {
-                customizationProviderClient = it
-            }
-    }
-
-    private fun getKeyguardQuickAffordanceSnapshotRestorer(
-        context: Context
-    ): KeyguardQuickAffordanceSnapshotRestorer {
-        return keyguardQuickAffordanceSnapshotRestorer
-            ?: KeyguardQuickAffordanceSnapshotRestorer(
-                    getKeyguardQuickAffordancePickerInteractor(context),
-                    getKeyguardQuickAffordancePickerProviderClient(context)
-                )
-                .also { keyguardQuickAffordanceSnapshotRestorer = it }
-    }
-
     fun getNotificationSectionViewModelFactory(
-        context: Context,
+        context: Context
     ): NotificationSectionViewModel.Factory {
         return notificationSectionViewModelFactory
             ?: NotificationSectionViewModel.Factory(
@@ -301,17 +257,16 @@
                 .also { notificationSectionViewModelFactory = it }
     }
 
-    private fun getNotificationsInteractor(
-        context: Context,
-    ): NotificationSettingsInteractor {
+    private fun getNotificationsInteractor(context: Context): NotificationSettingsInteractor {
         return notificationSettingsInteractor
             ?: NotificationSettingsInteractor(
                     repository =
                         NotificationSettingsRepository(
-                            scope = getApplicationCoroutineScope(),
+                            backgroundScope = bgScope,
                             backgroundDispatcher = bgDispatcher,
-                            secureSettingsRepository = getSecureSettingsRepository(context),
-                        ),
+                            secureSettingsRepository = secureSettingsRepository.get(),
+                            systemSettingsRepository = systemSettingsRepository.get(),
+                        )
                 )
                 .also { notificationSettingsInteractor = it }
     }
@@ -319,45 +274,12 @@
     private fun getNotificationsSnapshotRestorer(context: Context): NotificationsSnapshotRestorer {
         return notificationsSnapshotRestorer
             ?: NotificationsSnapshotRestorer(
-                    interactor =
-                        getNotificationsInteractor(
-                            context = context,
-                        ),
+                    interactor = getNotificationsInteractor(context = context),
                     backgroundScope = bgScope,
                 )
                 .also { notificationsSnapshotRestorer = it }
     }
 
-    override fun getClockRegistry(context: Context): ClockRegistry {
-        return (clockRegistryProvider
-                ?: ClockRegistryProvider(
-                        context = context.applicationContext,
-                        coroutineScope = getApplicationCoroutineScope(),
-                        mainDispatcher = mainDispatcher,
-                        backgroundDispatcher = bgDispatcher,
-                    )
-                    .also { clockRegistryProvider = it })
-            .get()
-    }
-
-    override fun getClockPickerInteractor(
-        context: Context,
-    ): ClockPickerInteractor {
-        val appContext = context.applicationContext
-        return clockPickerInteractor
-            ?: ClockPickerInteractor(
-                    repository =
-                        ClockPickerRepositoryImpl(
-                            secureSettingsRepository = getSecureSettingsRepository(appContext),
-                            registry = getClockRegistry(appContext),
-                            scope = getApplicationCoroutineScope(),
-                            mainDispatcher = mainDispatcher,
-                        ),
-                    snapshotRestorer = { getClockPickerSnapshotRestorer(appContext) },
-                )
-                .also { clockPickerInteractor = it }
-    }
-
     override fun getClockCarouselViewModelFactory(
         interactor: ClockPickerInteractor,
         clockViewFactory: ClockViewFactory,
@@ -376,12 +298,10 @@
 
     override fun getClockViewFactory(activity: ComponentActivity): ClockViewFactory {
         return clockViewFactory
-            ?: ClockViewFactoryImpl(
-                    activity.applicationContext,
-                    ScreenSizeCalculator.getInstance()
-                        .getScreenSize(activity.windowManager.defaultDisplay),
+            ?: ThemePickerClockViewFactory(
+                    activity,
                     WallpaperManager.getInstance(activity.applicationContext),
-                    getClockRegistry(activity.applicationContext),
+                    clockRegistry.get(),
                 )
                 .also {
                     clockViewFactory = it
@@ -397,65 +317,23 @@
                 }
     }
 
-    private fun getClockPickerSnapshotRestorer(
-        context: Context,
-    ): ClockPickerSnapshotRestorer {
-        return clockPickerSnapshotRestorer
-            ?: ClockPickerSnapshotRestorer(getClockPickerInteractor(context)).also {
-                clockPickerSnapshotRestorer = it
-            }
-    }
-
     override fun getWallpaperColorResources(
         wallpaperColors: WallpaperColors,
-        context: Context
+        context: Context,
     ): WallpaperColorResources {
-        return ThemedWallpaperColorResources(wallpaperColors, getSecureSettingsRepository(context))
+        return ThemedWallpaperColorResources(wallpaperColors, secureSettingsRepository.get())
     }
 
-    override fun getColorPickerInteractor(
-        context: Context,
-        wallpaperColorsRepository: WallpaperColorsRepository,
-    ): ColorPickerInteractor {
-        val appContext = context.applicationContext
-        return colorPickerInteractor
-            ?: ColorPickerInteractor(
-                    repository =
-                        ColorPickerRepositoryImpl(
-                            wallpaperColorsRepository,
-                            getColorCustomizationManager(appContext)
-                        ),
-                    snapshotRestorer = {
-                        getColorPickerSnapshotRestorer(appContext, wallpaperColorsRepository)
-                    }
-                )
-                .also { colorPickerInteractor = it }
-    }
-
-    override fun getColorPickerViewModelFactory(
-        context: Context,
-        wallpaperColorsRepository: WallpaperColorsRepository,
-    ): ColorPickerViewModel.Factory {
+    override fun getColorPickerViewModelFactory(context: Context): ColorPickerViewModel.Factory {
         return colorPickerViewModelFactory
             ?: ColorPickerViewModel.Factory(
                     context.applicationContext,
-                    getColorPickerInteractor(context, wallpaperColorsRepository),
+                    colorPickerInteractor.get(),
                     getUserEventLogger(),
                 )
                 .also { colorPickerViewModelFactory = it }
     }
 
-    private fun getColorPickerSnapshotRestorer(
-        context: Context,
-        wallpaperColorsRepository: WallpaperColorsRepository,
-    ): ColorPickerSnapshotRestorer {
-        return colorPickerSnapshotRestorer
-            ?: ColorPickerSnapshotRestorer(
-                    getColorPickerInteractor(context, wallpaperColorsRepository)
-                )
-                .also { colorPickerSnapshotRestorer = it }
-    }
-
     private fun getColorCustomizationManager(context: Context): ColorCustomizationManager {
         return colorCustomizationManager
             ?: ColorCustomizationManager.getInstance(context, OverlayManagerCompat(context)).also {
@@ -463,9 +341,7 @@
             }
     }
 
-    fun getDarkModeSnapshotRestorer(
-        context: Context,
-    ): DarkModeSnapshotRestorer {
+    fun getDarkModeSnapshotRestorer(context: Context): DarkModeSnapshotRestorer {
         val appContext = context.applicationContext
         return darkModeSnapshotRestorer
             ?: DarkModeSnapshotRestorer(
@@ -476,9 +352,7 @@
                 .also { darkModeSnapshotRestorer = it }
     }
 
-    protected fun getThemedIconSnapshotRestorer(
-        context: Context,
-    ): ThemedIconSnapshotRestorer {
+    protected fun getThemedIconSnapshotRestorer(context: Context): ThemedIconSnapshotRestorer {
         val optionProvider = ThemedIconSwitchProvider.getInstance(context)
         return themedIconSnapshotRestorer
             ?: ThemedIconSnapshotRestorer(
@@ -493,10 +367,9 @@
 
     protected fun getThemedIconInteractor(): ThemedIconInteractor {
         return themedIconInteractor
-            ?: ThemedIconInteractor(
-                    repository = ThemeIconRepository(),
-                )
-                .also { themedIconInteractor = it }
+            ?: ThemedIconInteractor(repository = ThemeIconRepository()).also {
+                themedIconInteractor = it
+            }
     }
 
     override fun getClockSettingsViewModelFactory(
@@ -507,11 +380,8 @@
         return clockSettingsViewModelFactory
             ?: ClockSettingsViewModel.Factory(
                     context.applicationContext,
-                    getClockPickerInteractor(context),
-                    getColorPickerInteractor(
-                        context,
-                        wallpaperColorsRepository,
-                    ),
+                    clockPickerInteractor.get(),
+                    colorPickerInteractor.get(),
                     getUserEventLogger(),
                 ) { clockId ->
                     clockId?.let { clockViewFactory.getController(clockId).config.isReactiveToTone }
@@ -520,9 +390,7 @@
                 .also { clockSettingsViewModelFactory = it }
     }
 
-    fun getGridScreenViewModelFactory(
-        context: Context,
-    ): ViewModelProvider.Factory {
+    fun getGridScreenViewModelFactory(context: Context): ViewModelProvider.Factory {
         return gridScreenViewModelFactory
             ?: GridScreenViewModel.Factory(
                     context = context,
@@ -549,14 +417,11 @@
                 .also { gridInteractor = it }
     }
 
-    private fun getGridSnapshotRestorer(
-        context: Context,
-    ): GridSnapshotRestorer {
+    private fun getGridSnapshotRestorer(context: Context): GridSnapshotRestorer {
         return gridSnapshotRestorer
-            ?: GridSnapshotRestorer(
-                    interactor = getGridInteractor(context),
-                )
-                .also { gridSnapshotRestorer = it }
+            ?: GridSnapshotRestorer(interactor = getGridInteractor(context)).also {
+                gridSnapshotRestorer = it
+            }
     }
 
     override fun isCurrentSelectedColorPreset(context: Context): Boolean {
diff --git a/src/com/android/customization/module/logging/ThemesUserEventLoggerImpl.kt b/src/com/android/customization/module/logging/ThemesUserEventLoggerImpl.kt
index b28086b..0a639fb 100644
--- a/src/com/android/customization/module/logging/ThemesUserEventLoggerImpl.kt
+++ b/src/com/android/customization/module/logging/ThemesUserEventLoggerImpl.kt
@@ -56,7 +56,6 @@
 import com.android.wallpaper.module.logging.UserEventLogger.EffectStatus
 import com.android.wallpaper.module.logging.UserEventLogger.SetWallpaperEntryPoint
 import com.android.wallpaper.module.logging.UserEventLogger.WallpaperDestination
-import com.android.wallpaper.util.ActivityUtils
 import com.android.wallpaper.util.LaunchSourceUtils
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -124,7 +123,7 @@
         effect: String,
         @EffectStatus status: Int,
         timeElapsedMillis: Long,
-        resultCode: Int
+        resultCode: Int,
     ) {
         SysUiStatsLogger(WALLPAPER_EFFECT_APPLIED)
             .setAppSessionId(appSessionId.getId())
@@ -146,7 +145,7 @@
     override fun logEffectForegroundDownload(
         effect: String,
         @EffectStatus status: Int,
-        timeElapsedMillis: Long
+        timeElapsedMillis: Long,
     ) {
         SysUiStatsLogger(WALLPAPER_EFFECT_FG_DOWNLOAD)
             .setAppSessionId(appSessionId.getId())
@@ -164,11 +163,7 @@
         SysUiStatsLogger(WALLPAPER_EXPLORE).setAppSessionId(appSessionId.getId()).log()
     }
 
-    override fun logThemeColorApplied(
-        @ColorSource source: Int,
-        style: Int,
-        seedColor: Int,
-    ) {
+    override fun logThemeColorApplied(@ColorSource source: Int, style: Int, seedColor: Int) {
         SysUiStatsLogger(THEME_COLOR_APPLIED)
             .setAppSessionId(appSessionId.getId())
             .setColorSource(source)
@@ -251,10 +246,9 @@
                 LaunchSourceUtils.LAUNCH_SOURCE_TIPS -> LAUNCHED_TIPS
                 LaunchSourceUtils.LAUNCH_SOURCE_DEEP_LINK -> LAUNCHED_DEEP_LINK
                 LaunchSourceUtils.LAUNCH_SOURCE_KEYGUARD -> LAUNCHED_KEYGUARD
+                LaunchSourceUtils.LAUNCH_SOURCE_SETTINGS_SEARCH -> LAUNCHED_SETTINGS_SEARCH
                 else -> LAUNCHED_PREFERENCE_UNSPECIFIED
             }
-        } else if (ActivityUtils.isLaunchedFromSettingsSearch(this)) {
-            LAUNCHED_SETTINGS_SEARCH
         } else if (action != null && action == WallpaperManager.ACTION_CROP_AND_SET_WALLPAPER) {
             LAUNCHED_CROP_AND_SET_ACTION
         } else if (categories != null && categories.contains(Intent.CATEGORY_LAUNCHER)) {
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
index 57f77b0..710a1da 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
@@ -20,6 +20,7 @@
 import androidx.annotation.IntRange
 import com.android.customization.picker.clock.shared.ClockSize
 import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 import kotlinx.coroutines.flow.Flow
 
 /**
@@ -49,4 +50,6 @@
     )
 
     suspend fun setClockSize(size: ClockSize)
+
+    suspend fun setClockFontAxes(axisSettings: List<ClockFontAxisSetting>)
 }
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
index 4a4aae1..90bb6e6 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -16,14 +16,20 @@
  */
 package com.android.customization.picker.clock.data.repository
 
+import android.graphics.drawable.Drawable
 import android.provider.Settings
 import androidx.annotation.ColorInt
 import androidx.annotation.IntRange
 import com.android.customization.picker.clock.shared.ClockSize
 import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.systemui.plugins.clocks.ClockFontAxis
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 import com.android.systemui.plugins.clocks.ClockMetadata
 import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
+import com.android.wallpaper.picker.di.modules.MainDispatcher
+import javax.inject.Inject
+import javax.inject.Singleton
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -42,11 +48,14 @@
 import org.json.JSONObject
 
 /** Implementation of [ClockPickerRepository], using [ClockRegistry]. */
-class ClockPickerRepositoryImpl(
+@Singleton
+class ClockPickerRepositoryImpl
+@Inject
+constructor(
     private val secureSettingsRepository: SecureSettingsRepository,
     private val registry: ClockRegistry,
-    scope: CoroutineScope,
-    mainDispatcher: CoroutineDispatcher,
+    @MainDispatcher mainScope: CoroutineScope,
+    @MainDispatcher mainDispatcher: CoroutineDispatcher,
 ) : ClockPickerRepository {
 
     @OptIn(ExperimentalCoroutinesApi::class)
@@ -55,8 +64,19 @@
                 fun send() {
                     val activeClockId = registry.activeClockId
                     val allClocks =
-                        registry.getClocks().map {
-                            it.toModel(isSelected = it.clockId == activeClockId)
+                        registry.getClocks().mapNotNull {
+                            val clockConfig = registry.getClockPickerConfig(it.clockId)
+                            if (clockConfig != null) {
+                                it.toModel(
+                                    isSelected = it.clockId == activeClockId,
+                                    description = clockConfig.description,
+                                    thumbnail = clockConfig.thumbnail,
+                                    isReactiveToTone = clockConfig.isReactiveToTone,
+                                    fontAxes = clockConfig.axes,
+                                )
+                            } else {
+                                null
+                            }
                         }
 
                     trySend(allClocks)
@@ -87,17 +107,25 @@
                 fun send() {
                     val activeClockId = registry.activeClockId
                     val metadata = registry.settings?.metadata
+                    val clockConfig = registry.getClockPickerConfig(activeClockId)
                     val model =
-                        registry
-                            .getClocks()
-                            .find { clockMetadata -> clockMetadata.clockId == activeClockId }
-                            ?.toModel(
-                                isSelected = true,
-                                selectedColorId = metadata?.getSelectedColorId(),
-                                colorTone = metadata?.getColorTone()
-                                        ?: ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS,
-                                seedColor = registry.seedColor
-                            )
+                        clockConfig?.let {
+                            registry
+                                .getClocks()
+                                .find { clockMetadata -> clockMetadata.clockId == activeClockId }
+                                ?.toModel(
+                                    isSelected = true,
+                                    description = it.description,
+                                    thumbnail = it.thumbnail,
+                                    isReactiveToTone = it.isReactiveToTone,
+                                    fontAxes = it.axes,
+                                    selectedColorId = metadata?.getSelectedColorId(),
+                                    colorTone =
+                                        metadata?.getColorTone()
+                                            ?: ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS,
+                                    seedColor = registry.seedColor,
+                                )
+                        }
                     trySend(model)
                 }
 
@@ -150,11 +178,7 @@
             .map { setting -> setting == 1 }
             .map { isDynamic -> if (isDynamic) ClockSize.DYNAMIC else ClockSize.SMALL }
             .distinctUntilChanged()
-            .shareIn(
-                scope = scope,
-                started = SharingStarted.Eagerly,
-                replay = 1,
-            )
+            .shareIn(scope = mainScope, started = SharingStarted.Eagerly, replay = 1)
 
     override suspend fun setClockSize(size: ClockSize) {
         secureSettingsRepository.setInt(
@@ -163,6 +187,14 @@
         )
     }
 
+    override suspend fun setClockFontAxes(axisSettings: List<ClockFontAxisSetting>) {
+        registry.mutateSetting { oldSettings ->
+            val newSettings = oldSettings.copy(axes = axisSettings)
+            newSettings.metadata = oldSettings.metadata
+            newSettings
+        }
+    }
+
     private fun JSONObject.getSelectedColorId(): String? {
         return if (this.isNull(KEY_METADATA_SELECTED_COLOR_ID)) {
             null
@@ -174,13 +206,17 @@
     private fun JSONObject.getColorTone(): Int {
         return this.optInt(
             KEY_METADATA_COLOR_TONE_PROGRESS,
-            ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS
+            ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS,
         )
     }
 
     /** By default, [ClockMetadataModel] has no color information unless specified. */
     private fun ClockMetadata.toModel(
         isSelected: Boolean,
+        description: String,
+        thumbnail: Drawable,
+        isReactiveToTone: Boolean,
+        fontAxes: List<ClockFontAxis>,
         selectedColorId: String? = null,
         @IntRange(from = 0, to = 100) colorTone: Int = 0,
         @ColorInt seedColor: Int? = null,
@@ -188,6 +224,10 @@
         return ClockMetadataModel(
             clockId = clockId,
             isSelected = isSelected,
+            description = description,
+            thumbnail = thumbnail,
+            isReactiveToTone = isReactiveToTone,
+            fontAxes = fontAxes,
             selectedColorId = selectedColorId,
             colorToneProgress = colorTone,
             seedColor = seedColor,
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
index b197edf..15d9088 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
@@ -19,6 +19,7 @@
 import android.content.ComponentName
 import android.content.Context
 import android.view.LayoutInflater
+import com.android.systemui.Flags
 import com.android.systemui.plugins.Plugin
 import com.android.systemui.plugins.PluginManager
 import com.android.systemui.shared.clocks.ClockRegistry
@@ -29,7 +30,6 @@
 import com.android.systemui.shared.plugins.PluginManagerImpl
 import com.android.systemui.shared.plugins.PluginPrefs
 import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager_Factory
-import com.android.wallpaper.module.InjectorProvider
 import java.util.concurrent.Executors
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
@@ -53,11 +53,14 @@
             backgroundDispatcher,
             isEnabled = true,
             handleAllUsers = false,
-            DefaultClockProvider(context, LayoutInflater.from(context), context.resources),
+            DefaultClockProvider(
+                ctx = context,
+                layoutInflater = LayoutInflater.from(context),
+                resources = context.resources,
+                isClockReactiveVariantsEnabled = Flags.clockReactiveVariants(),
+            ),
             keepAllLoaded = true,
             subTag = "Picker",
-            isTransitClockEnabled =
-                InjectorProvider.getInjector().getFlags().isTransitClockEnabled(context)
         )
     }
 
diff --git a/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt b/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt
index 30887e5..678de5e 100644
--- a/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt
+++ b/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt
@@ -23,7 +23,9 @@
 import com.android.customization.picker.clock.shared.ClockSize
 import com.android.customization.picker.clock.shared.model.ClockMetadataModel
 import com.android.customization.picker.clock.shared.model.ClockSnapshotModel
-import javax.inject.Provider
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
+import javax.inject.Inject
+import javax.inject.Singleton
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.firstOrNull
@@ -33,9 +35,12 @@
  * Interactor for accessing application clock settings, as well as selecting and configuring custom
  * clocks.
  */
-class ClockPickerInteractor(
+@Singleton
+class ClockPickerInteractor
+@Inject
+constructor(
     private val repository: ClockPickerRepository,
-    private val snapshotRestorer: Provider<ClockPickerSnapshotRestorer>,
+    private val snapshotRestorer: ClockPickerSnapshotRestorer,
 ) {
 
     val allClocks: Flow<List<ClockMetadataModel>> = repository.allClocks
@@ -43,6 +48,8 @@
     val selectedClockId: Flow<String> =
         repository.selectedClock.map { clock -> clock.clockId }.distinctUntilChanged()
 
+    val selectedClock: Flow<ClockMetadataModel> = repository.selectedClock
+
     val selectedColorId: Flow<String?> =
         repository.selectedClock.map { clock -> clock.selectedColorId }.distinctUntilChanged()
 
@@ -51,6 +58,9 @@
 
     val seedColor: Flow<Int?> = repository.selectedClock.map { clock -> clock.seedColor }
 
+    val axisSettings: Flow<List<ClockFontAxisSetting>?> =
+        repository.selectedClock.map { clock -> clock.fontAxes.map { it.toSetting() } }
+
     val selectedClockSize: Flow<ClockSize> = repository.selectedClockSize
 
     suspend fun setSelectedClock(clockId: String) {
@@ -78,7 +88,31 @@
         setClockOption(ClockSnapshotModel(clockSize = size))
     }
 
-    suspend fun setClockOption(clockSnapshotModel: ClockSnapshotModel) {
+    suspend fun setClockFontAxes(axisSettings: List<ClockFontAxisSetting>) {
+        setClockOption(ClockSnapshotModel(axisSettings = axisSettings))
+    }
+
+    suspend fun applyClock(
+        clockId: String?,
+        size: ClockSize?,
+        selectedColorId: String?,
+        @IntRange(from = 0, to = 100) colorToneProgress: Int?,
+        @ColorInt seedColor: Int?,
+        axisSettings: List<ClockFontAxisSetting>,
+    ) {
+        setClockOption(
+            ClockSnapshotModel(
+                clockId = clockId,
+                clockSize = size,
+                selectedColorId = selectedColorId,
+                colorToneProgress = colorToneProgress,
+                seedColor = seedColor,
+                axisSettings = axisSettings,
+            )
+        )
+    }
+
+    private suspend fun setClockOption(clockSnapshotModel: ClockSnapshotModel) {
         // [ClockCarouselViewModel] is monitoring the [ClockPickerInteractor.setSelectedClock] job,
         // so it needs to finish last.
         storeCurrentClockOption(clockSnapshotModel)
@@ -88,10 +122,16 @@
             repository.setClockColor(
                 selectedColorId = clockSnapshotModel.selectedColorId,
                 colorToneProgress = clockSnapshotModel.colorToneProgress,
-                seedColor = clockSnapshotModel.seedColor
+                seedColor = clockSnapshotModel.seedColor,
             )
         }
         clockSnapshotModel.clockId?.let { repository.setSelectedClock(it) }
+        clockSnapshotModel.axisSettings?.let { repository.setClockFontAxes(it) }
+    }
+
+    private suspend fun storeCurrentClockOption(clockSnapshotModel: ClockSnapshotModel) {
+        val option = getCurrentClockToRestore(clockSnapshotModel)
+        snapshotRestorer.storeSnapshot(option)
     }
 
     /**
@@ -103,19 +143,17 @@
      * [selectedColorId] and [seedColor] have null state collide with nullable type, but we know
      * they are presented whenever there's a [colorToneProgress].
      */
-    suspend fun getCurrentClockToRestore(latestOption: ClockSnapshotModel? = null) =
+    private suspend fun getCurrentClockToRestore(latestOption: ClockSnapshotModel) =
         ClockSnapshotModel(
-            clockId = latestOption?.clockId ?: selectedClockId.firstOrNull(),
-            clockSize = latestOption?.clockSize ?: selectedClockSize.firstOrNull(),
-            colorToneProgress = latestOption?.colorToneProgress ?: colorToneProgress.firstOrNull(),
-            selectedColorId = latestOption?.colorToneProgress?.let { latestOption.selectedColorId }
+            clockId = latestOption.clockId ?: selectedClockId.firstOrNull(),
+            clockSize = latestOption.clockSize ?: selectedClockSize.firstOrNull(),
+            colorToneProgress = latestOption.colorToneProgress ?: colorToneProgress.firstOrNull(),
+            selectedColorId =
+                latestOption.colorToneProgress?.let { latestOption.selectedColorId }
                     ?: selectedColorId.firstOrNull(),
-            seedColor = latestOption?.colorToneProgress?.let { latestOption.seedColor }
+            seedColor =
+                latestOption.colorToneProgress?.let { latestOption.seedColor }
                     ?: seedColor.firstOrNull(),
+            axisSettings = latestOption.axisSettings ?: axisSettings.firstOrNull(),
         )
-
-    private suspend fun storeCurrentClockOption(clockSnapshotModel: ClockSnapshotModel) {
-        val option = getCurrentClockToRestore(clockSnapshotModel)
-        snapshotRestorer.get().storeSnapshot(option)
-    }
 }
diff --git a/src/com/android/customization/picker/clock/domain/interactor/ClockPickerSnapshotRestorer.kt b/src/com/android/customization/picker/clock/domain/interactor/ClockPickerSnapshotRestorer.kt
index ecaf10f..2a74276 100644
--- a/src/com/android/customization/picker/clock/domain/interactor/ClockPickerSnapshotRestorer.kt
+++ b/src/com/android/customization/picker/clock/domain/interactor/ClockPickerSnapshotRestorer.kt
@@ -19,22 +19,50 @@
 
 import android.text.TextUtils
 import android.util.Log
+import com.android.customization.picker.clock.data.repository.ClockPickerRepository
 import com.android.customization.picker.clock.shared.model.ClockSnapshotModel
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore
 import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.firstOrNull
+import kotlinx.coroutines.flow.map
+import org.json.JSONArray
 
 /** Handles state restoration for clocks. */
-class ClockPickerSnapshotRestorer(private val interactor: ClockPickerInteractor) :
-    SnapshotRestorer {
+@Singleton
+class ClockPickerSnapshotRestorer
+@Inject
+constructor(private val repository: ClockPickerRepository) : SnapshotRestorer {
     private var snapshotStore: SnapshotStore = SnapshotStore.NOOP
     private var originalOption: ClockSnapshotModel? = null
 
-    override suspend fun setUpSnapshotRestorer(
-        store: SnapshotStore,
-    ): RestorableSnapshot {
+    override suspend fun setUpSnapshotRestorer(store: SnapshotStore): RestorableSnapshot {
         snapshotStore = store
-        originalOption = interactor.getCurrentClockToRestore()
+        originalOption =
+            ClockSnapshotModel(
+                clockId =
+                    repository.selectedClock
+                        .map { clock -> clock.clockId }
+                        .distinctUntilChanged()
+                        .firstOrNull(),
+                clockSize = repository.selectedClockSize.firstOrNull(),
+                colorToneProgress =
+                    repository.selectedClock.map { clock -> clock.colorToneProgress }.firstOrNull(),
+                selectedColorId =
+                    repository.selectedClock
+                        .map { clock -> clock.selectedColorId }
+                        .distinctUntilChanged()
+                        .firstOrNull(),
+                seedColor = repository.selectedClock.map { clock -> clock.seedColor }.firstOrNull(),
+                axisSettings =
+                    repository.selectedClock
+                        .map { clock -> clock.fontAxes.map { it.toSetting() } }
+                        .firstOrNull(),
+            )
         return snapshot(originalOption)
     }
 
@@ -47,7 +75,9 @@
                     optionToRestore.colorToneProgress?.toString() !=
                         snapshot.args[KEY_COLOR_TONE_PROGRESS] ||
                     optionToRestore.seedColor?.toString() != snapshot.args[KEY_SEED_COLOR] ||
-                    optionToRestore.selectedColorId != snapshot.args[KEY_COLOR_ID]
+                    optionToRestore.selectedColorId != snapshot.args[KEY_COLOR_ID] ||
+                    (optionToRestore.axisSettings ?: listOf()) !=
+                        ClockFontAxisSetting.fromJson(JSONArray(snapshot.args[KEY_FONT_AXES]))
             ) {
                 Log.wtf(
                     TAG,
@@ -58,7 +88,16 @@
                 )
             }
 
-            interactor.setClockOption(optionToRestore)
+            optionToRestore.clockSize?.let { repository.setClockSize(it) }
+            optionToRestore.colorToneProgress?.let {
+                repository.setClockColor(
+                    selectedColorId = optionToRestore.selectedColorId,
+                    colorToneProgress = optionToRestore.colorToneProgress,
+                    seedColor = optionToRestore.seedColor,
+                )
+            }
+            optionToRestore.clockId?.let { repository.setSelectedClock(it) }
+            optionToRestore.axisSettings?.let { repository.setClockFontAxes(it) }
         }
     }
 
@@ -69,7 +108,7 @@
     private fun snapshot(clockSnapshotModel: ClockSnapshotModel? = null): RestorableSnapshot {
         val options =
             if (clockSnapshotModel == null) emptyMap()
-            else
+            else {
                 buildMap {
                     clockSnapshotModel.clockId?.let { put(KEY_CLOCK_ID, it) }
                     clockSnapshotModel.clockSize?.let { put(KEY_CLOCK_SIZE, it.toString()) }
@@ -78,7 +117,11 @@
                         put(KEY_COLOR_TONE_PROGRESS, it.toString())
                     }
                     clockSnapshotModel.seedColor?.let { put(KEY_SEED_COLOR, it.toString()) }
+                    clockSnapshotModel.axisSettings?.let {
+                        put(KEY_FONT_AXES, ClockFontAxisSetting.toJson(it).toString())
+                    }
                 }
+            }
 
         return RestorableSnapshot(options)
     }
@@ -90,5 +133,6 @@
         private const val KEY_COLOR_ID = "color_id"
         private const val KEY_COLOR_TONE_PROGRESS = "color_tone_progress"
         private const val KEY_SEED_COLOR = "seed_color"
+        private const val KEY_FONT_AXES = "font_axes"
     }
 }
diff --git a/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt b/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
index 6e2bfb3..8a2edfb 100644
--- a/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
+++ b/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
@@ -17,13 +17,19 @@
 
 package com.android.customization.picker.clock.shared.model
 
+import android.graphics.drawable.Drawable
 import androidx.annotation.ColorInt
 import androidx.annotation.IntRange
+import com.android.systemui.plugins.clocks.ClockFontAxis
 
 /** Model for clock metadata. */
 data class ClockMetadataModel(
     val clockId: String,
     val isSelected: Boolean,
+    val description: String,
+    val thumbnail: Drawable,
+    val isReactiveToTone: Boolean,
+    val fontAxes: List<ClockFontAxis>,
     val selectedColorId: String?,
     @IntRange(from = 0, to = 100) val colorToneProgress: Int,
     @ColorInt val seedColor: Int?,
diff --git a/src/com/android/customization/picker/clock/shared/model/ClockSnapshotModel.kt b/src/com/android/customization/picker/clock/shared/model/ClockSnapshotModel.kt
index 942cc59..6817ec1 100644
--- a/src/com/android/customization/picker/clock/shared/model/ClockSnapshotModel.kt
+++ b/src/com/android/customization/picker/clock/shared/model/ClockSnapshotModel.kt
@@ -20,6 +20,7 @@
 import androidx.annotation.ColorInt
 import androidx.annotation.IntRange
 import com.android.customization.picker.clock.shared.ClockSize
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 
 /** Models application state for a clock option in a picker experience. */
 data class ClockSnapshotModel(
@@ -28,4 +29,5 @@
     val selectedColorId: String? = null,
     @IntRange(from = 0, to = 100) val colorToneProgress: Int? = null,
     @ColorInt val seedColor: Int? = null,
+    val axisSettings: List<ClockFontAxisSetting>? = null,
 )
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
index 7de25e7..764c671 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
@@ -41,13 +41,12 @@
 import com.android.customization.picker.clock.shared.ClockSize
 import com.android.customization.picker.clock.ui.adapter.ClockSettingsTabAdapter
 import com.android.customization.picker.clock.ui.view.ClockCarouselView
-import com.android.customization.picker.clock.ui.view.ClockHostView
 import com.android.customization.picker.clock.ui.view.ClockViewFactory
 import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
 import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder
-import com.android.customization.picker.common.ui.view.ItemSpacing
+import com.android.systemui.shared.Flags
 import com.android.themepicker.R
-import com.android.wallpaper.config.BaseFlags
+import com.android.wallpaper.picker.common.ui.view.ItemSpacing
 import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.mapNotNull
@@ -65,7 +64,10 @@
         clockViewFactory: ClockViewFactory,
         lifecycleOwner: LifecycleOwner,
     ) {
-        val clockHostView: ClockHostView = view.requireViewById(R.id.clock_host_view)
+        if (Flags.newCustomizationPickerUi()) {
+            return
+        }
+        val clockHostView: ViewGroup = view.requireViewById(R.id.clock_host_view)
         val tabView: RecyclerView = view.requireViewById(R.id.tabs)
         val tabAdapter = ClockSettingsTabAdapter()
         tabView.adapter = tabAdapter
@@ -82,6 +84,7 @@
                 }
 
                 override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit
+
                 override fun onStopTrackingTouch(seekBar: SeekBar?) {
                     seekBar?.progress?.let {
                         lifecycleOwner.lifecycleScope.launch { viewModel.onSliderProgressStop(it) }
@@ -103,13 +106,13 @@
             getRadioText(
                 view.context.applicationContext,
                 view.resources.getString(R.string.clock_size_dynamic),
-                view.resources.getString(R.string.clock_size_dynamic_description)
+                view.resources.getString(R.string.clock_size_dynamic_description),
             )
         view.requireViewById<RadioButton>(R.id.radio_small).text =
             getRadioText(
                 view.context.applicationContext,
                 view.resources.getString(R.string.clock_size_small),
-                view.resources.getString(R.string.clock_size_small_description)
+                view.resources.getString(R.string.clock_size_small_description),
             )
 
         val colorOptionContainer = view.requireViewById<View>(R.id.color_picker_container)
@@ -159,7 +162,7 @@
                                 ColorOptionIconBinder.bind(
                                     item.requireViewById(R.id.foreground),
                                     payload,
-                                    darkMode
+                                    darkMode,
                                 )
                                 OptionItemBinder.bind(
                                     view = item,
@@ -199,18 +202,16 @@
                         )
                         .collect { (clockId, size) ->
                             clockHostView.removeAllViews()
-                            if (BaseFlags.get().isClockReactiveVariantsEnabled()) {
-                                clockViewFactory.setReactiveTouchInteractionEnabled(clockId, true)
-                            }
                             val clockView =
                                 when (size) {
                                     ClockSize.DYNAMIC -> clockViewFactory.getLargeView(clockId)
                                     ClockSize.SMALL -> clockViewFactory.getSmallView(clockId)
                                 }
-                            // The clock view might still be attached to an existing parent. Detach
-                            // before adding to another parent.
+                            // The clock view might still be attached to an existing parent.
+                            // Detach before adding to another parent.
                             (clockView.parent as? ViewGroup)?.removeView(clockView)
                             clockHostView.addView(clockView)
+
                             when (size) {
                                 ClockSize.DYNAMIC -> {
                                     // When clock size data flow emits clock size signal, we want
@@ -278,20 +279,20 @@
     private fun getRadioText(
         context: Context,
         title: String,
-        description: String
+        description: String,
     ): SpannableString {
         val text = SpannableString(title + "\n" + description)
         text.setSpan(
             TextAppearanceSpan(context, R.style.SectionTitleTextStyle),
             0,
             title.length,
-            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE,
         )
         text.setSpan(
             TextAppearanceSpan(context, R.style.SectionSubtitleTextStyle),
             title.length + 1,
             title.length + 1 + description.length,
-            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE,
         )
         return text
     }
diff --git a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
index c2e6717..b66150f 100644
--- a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
@@ -19,9 +19,13 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.view.ViewGroup.MarginLayoutParams
 import androidx.cardview.widget.CardView
 import androidx.core.content.ContextCompat
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.isVisible
+import androidx.core.view.updateLayoutParams
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.get
 import androidx.transition.Transition
@@ -61,6 +65,14 @@
                 container,
                 false,
             )
+        ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
+            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            v.updateLayoutParams<MarginLayoutParams> {
+                topMargin = insets.top
+                bottomMargin = insets.bottom
+            }
+            WindowInsetsCompat.CONSUMED
+        }
         setUpToolbar(view)
 
         val context = requireContext()
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
index 6cbb0f5..1fbdede 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
@@ -33,18 +33,10 @@
 import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselItemViewModel
 import com.android.systemui.plugins.clocks.ClockController
 import com.android.themepicker.R
-import com.android.wallpaper.config.BaseFlags
 import com.android.wallpaper.picker.FixedWidthDisplayRatioFrameLayout
 import java.lang.Float.max
 
-class ClockCarouselView(
-    context: Context,
-    attrs: AttributeSet,
-) :
-    FrameLayout(
-        context,
-        attrs,
-    ) {
+class ClockCarouselView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) {
 
     val carousel: Carousel
     private val motionLayout: MotionLayout
@@ -145,8 +137,7 @@
             clocks
                 .indexOfFirst { it.isSelected }
                 // If not found, default to the first clock as selected:
-                .takeIf { it != -1 }
-                ?: 0
+                .takeIf { it != -1 } ?: 0
         carousel.jumpToIndex(indexOfSelectedClock)
         motionLayout.setTransitionListener(
             object : MotionLayout.TransitionListener {
@@ -154,7 +145,7 @@
                 override fun onTransitionStarted(
                     motionLayout: MotionLayout?,
                     startId: Int,
-                    endId: Int
+                    endId: Int,
                 ) {
                     if (motionLayout == null) {
                         return
@@ -247,15 +238,13 @@
                             offCenterClockHostView[0]
                         } else {
                             null
-                        }
-                            ?: return
+                        } ?: return
                     val toCenterClockFrame =
                         if (toCenterClockHostView.isNotEmpty()) {
                             toCenterClockHostView[0]
                         } else {
                             null
-                        }
-                            ?: return
+                        } ?: return
                     offCenterClockHostView.doOnPreDraw {
                         it.pivotX =
                             progress * it.width / 2 + (1 - progress) * getCenteredHostViewPivotX(it)
@@ -304,15 +293,13 @@
                     motionLayout: MotionLayout?,
                     triggerId: Int,
                     positive: Boolean,
-                    progress: Float
+                    progress: Float,
                 ) {}
             }
         )
     }
 
-    fun setSelectedClockIndex(
-        index: Int,
-    ) {
+    fun setSelectedClockIndex(index: Int) {
         // 1. setUpClockCarouselView() can possibly not be called before setSelectedClockIndex().
         //    We need to check if index out of bound.
         // 2. jumpToIndex() to the same position can cause the views unnecessarily populate again.
@@ -351,12 +338,12 @@
             }
         }
 
-        val previousConstaintSet = motionLayout.getConstraintSet(R.id.previous)
-        val startConstaintSet = motionLayout.getConstraintSet(R.id.start)
-        val nextConstaintSet = motionLayout.getConstraintSet(R.id.next)
-        val constaintSetList =
-            listOf<ConstraintSet>(previousConstaintSet, startConstaintSet, nextConstaintSet)
-        constaintSetList.forEach { constraintSet ->
+        val previousConstraintSet = motionLayout.getConstraintSet(R.id.previous)
+        val startConstraintSet = motionLayout.getConstraintSet(R.id.start)
+        val nextConstraintSet = motionLayout.getConstraintSet(R.id.next)
+        val constraintSetList =
+            listOf<ConstraintSet>(previousConstraintSet, startConstraintSet, nextConstraintSet)
+        constraintSetList.forEach { constraintSet ->
             itemViewIds.forEach { id ->
                 constraintSet.getConstraint(id)?.let { constraint ->
                     val layout = constraint.layout
@@ -385,9 +372,19 @@
         val clockSize: ClockSize,
         val clocks: List<ClockCarouselItemViewModel>,
         private val clockViewFactory: ClockViewFactory,
-        private val onClockSelected: (clock: ClockCarouselItemViewModel) -> Unit
+        private val onClockSelected: (clock: ClockCarouselItemViewModel) -> Unit,
     ) : Carousel.Adapter {
 
+        // This map is used to eagerly save the translation X and Y of each small clock view, so
+        // that the next time we need it, we do not need to wait for onPreDraw to obtain the
+        // translation X and Y.
+        // This is to solve the issue that when Fragment transition triggers another attach of the
+        // view for animation purposes. We need to obtain the translation X and Y quick enough so
+        // that the outgoing carousel view that shows this the small clock views are correctly
+        // positioned.
+        private val smallClockTranslationMap: MutableMap<String, Pair<Float, Float>> =
+            mutableMapOf()
+
         fun getContentDescription(index: Int, resources: Resources): String {
             return clocks[index].contentDescription
         }
@@ -411,9 +408,6 @@
 
             // Add the clock view to the clock host view
             clockHostView.removeAllViews()
-            if (BaseFlags.get().isClockReactiveVariantsEnabled()) {
-                clockViewFactory.setReactiveTouchInteractionEnabled(clockId, false)
-            }
             val clockView =
                 when (clockSize) {
                     ClockSize.DYNAMIC -> clockViewFactory.getLargeView(clockId)
@@ -432,18 +426,9 @@
 
             when (clockSize) {
                 ClockSize.DYNAMIC ->
-                    initializeDynamicClockView(
-                        isMiddleView,
-                        clockScaleView,
-                        clockId,
-                        clockHostView,
-                    )
+                    initializeDynamicClockView(isMiddleView, clockScaleView, clockId, clockHostView)
                 ClockSize.SMALL ->
-                    initializeSmallClockView(
-                        isMiddleView,
-                        clockHostView,
-                        clockView,
-                    )
+                    initializeSmallClockView(clockId, isMiddleView, clockHostView, clockView)
             }
             cardView.alpha = if (isMiddleView) 0f else 1f
         }
@@ -472,10 +457,18 @@
         }
 
         private fun initializeSmallClockView(
+            clockId: String,
             isMiddleView: Boolean,
             clockHostView: ClockHostView,
             clockView: View,
         ) {
+            smallClockTranslationMap[clockId]?.let {
+                // If isMiddleView, the translation X and Y should both be 0
+                if (!isMiddleView) {
+                    clockView.translationX = it.first
+                    clockView.translationY = it.second
+                }
+            }
             clockHostView.doOnPreDraw {
                 if (isMiddleView) {
                     it.pivotX = getCenteredHostViewPivotX(it)
@@ -485,18 +478,17 @@
                 } else {
                     it.pivotX = it.width / 2F
                     it.pivotY = it.height / 2F
-                    clockView.translationX =
-                        getTranslationDistance(
-                            clockHostView.width,
-                            clockView.width,
-                            clockView.left,
-                        )
-                    clockView.translationY =
+                    val translationX =
+                        getTranslationDistance(clockHostView.width, clockView.width, clockView.left)
+                    val translationY =
                         getTranslationDistance(
                             clockHostView.height,
                             clockView.height,
                             clockView.top,
                         )
+                    clockView.translationX = translationX
+                    clockView.translationY = translationY
+                    smallClockTranslationMap[clockId] = Pair(translationX, translationY)
                 }
             }
         }
@@ -518,7 +510,7 @@
                 R.id.item_view_1,
                 R.id.item_view_2,
                 R.id.item_view_3,
-                R.id.item_view_4
+                R.id.item_view_4,
             )
 
         fun getScalingUpScale(progress: Float) =
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockConstraintLayoutHostView.kt b/src/com/android/customization/picker/clock/ui/view/ClockConstraintLayoutHostView.kt
new file mode 100644
index 0000000..de5fbd5
--- /dev/null
+++ b/src/com/android/customization/picker/clock/ui/view/ClockConstraintLayoutHostView.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.clock.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.view.View.MeasureSpec.EXACTLY
+import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.customization.picker.clock.shared.ClockSize
+import com.android.systemui.plugins.clocks.ClockController
+import com.android.wallpaper.util.ScreenSizeCalculator
+
+/**
+ * Parent view for the clock view. We will calculate the current display size and the preview size
+ * and scale down the clock view to fit in the preview.
+ */
+class ClockConstraintLayoutHostView(context: Context, attrs: AttributeSet?) :
+    ConstraintLayout(context, attrs) {
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        val screenSize = ScreenSizeCalculator.getInstance().getScreenSize(display)
+        super.onMeasure(
+            MeasureSpec.makeMeasureSpec(screenSize.x, EXACTLY),
+            MeasureSpec.makeMeasureSpec(screenSize.y, EXACTLY),
+        )
+        val ratio = MeasureSpec.getSize(widthMeasureSpec) / screenSize.x.toFloat()
+        scaleX = ratio
+        scaleY = ratio
+    }
+
+    companion object {
+        fun addClockViews(
+            clockController: ClockController,
+            rootView: ClockConstraintLayoutHostView,
+            size: ClockSize,
+        ) {
+            clockController.let { clock ->
+                when (size) {
+                    ClockSize.DYNAMIC -> {
+                        clock.largeClock.layout.views.forEach {
+                            if (it.parent != null) {
+                                (it.parent as ViewGroup).removeView(it)
+                            }
+                            rootView.addView(it).apply { it.visibility = View.VISIBLE }
+                        }
+                    }
+
+                    ClockSize.SMALL -> {
+                        clock.smallClock.layout.views.forEach {
+                            if (it.parent != null) {
+                                (it.parent as ViewGroup).removeView(it)
+                            }
+                            rootView.addView(it).apply { it.visibility = View.VISIBLE }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockHostView.kt b/src/com/android/customization/picker/clock/ui/view/ClockHostView.kt
index 512fcd1..2db52f1 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockHostView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockHostView.kt
@@ -12,10 +12,7 @@
  * same size of lockscreen to layout clock and scale down it to the size in picker carousel
  * according to ratio of preview to LS
  */
-class ClockHostView(
-    context: Context,
-    attrs: AttributeSet?,
-) : FrameLayout(context, attrs) {
+class ClockHostView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
     private var previewRatio: Float = 1F
         set(value) {
             if (field != value) {
@@ -41,15 +38,16 @@
         parentWidthMeasureSpec: Int,
         widthUsed: Int,
         parentHeightMeasureSpec: Int,
-        heightUsed: Int
+        heightUsed: Int,
     ) {
+
         val screenSize = ScreenSizeCalculator.getInstance().getScreenSize(display)
         super.measureChildWithMargins(
             child,
             MeasureSpec.makeMeasureSpec(screenSize.x, EXACTLY),
             widthUsed,
             MeasureSpec.makeMeasureSpec(screenSize.y, EXACTLY),
-            heightUsed
+            heightUsed,
         )
     }
 }
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt b/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
deleted file mode 100644
index 8e5992e..0000000
--- a/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.customization.picker.clock.ui.view
-
-import android.view.View
-import androidx.annotation.ColorInt
-import androidx.lifecycle.LifecycleOwner
-import com.android.systemui.plugins.clocks.ClockController
-
-interface ClockViewFactory {
-
-    fun getController(clockId: String): ClockController
-
-    /**
-     * Reset the large view to its initial state when getting the view. This is because some view
-     * configs, e.g. animation state, might change during the reuse of the clock view in the app.
-     */
-    fun getLargeView(clockId: String): View
-
-    /**
-     * Reset the small view to its initial state when getting the view. This is because some view
-     * configs, e.g. translation X, might change during the reuse of the clock view in the app.
-     */
-    fun getSmallView(clockId: String): View
-
-    /** Enables or disables the reactive swipe interaction */
-    fun setReactiveTouchInteractionEnabled(clockId: String, enable: Boolean)
-
-    fun updateColorForAllClocks(@ColorInt seedColor: Int?)
-
-    fun updateColor(clockId: String, @ColorInt seedColor: Int?)
-
-    fun updateRegionDarkness()
-
-    fun updateTimeFormat(clockId: String)
-
-    fun registerTimeTicker(owner: LifecycleOwner)
-
-    fun onDestroy()
-
-    fun unregisterTimeTicker(owner: LifecycleOwner)
-}
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockViewFactoryImpl.kt b/src/com/android/customization/picker/clock/ui/view/ThemePickerClockViewFactory.kt
similarity index 76%
rename from src/com/android/customization/picker/clock/ui/view/ClockViewFactoryImpl.kt
rename to src/com/android/customization/picker/clock/ui/view/ThemePickerClockViewFactory.kt
index dea6777..72b0f19 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockViewFactoryImpl.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ThemePickerClockViewFactory.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,37 +15,42 @@
  */
 package com.android.customization.picker.clock.ui.view
 
+import android.app.Activity
 import android.app.WallpaperColors
 import android.app.WallpaperManager
 import android.content.Context
-import android.content.res.Resources
-import android.graphics.Point
 import android.graphics.Rect
 import android.view.View
 import android.widget.FrameLayout
 import androidx.annotation.ColorInt
-import androidx.core.text.util.LocalePreferences
 import androidx.lifecycle.LifecycleOwner
+import com.android.internal.policy.SystemBarUtils
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 import com.android.systemui.plugins.clocks.WeatherData
+import com.android.systemui.shared.Flags
 import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.themepicker.R
-import com.android.wallpaper.config.BaseFlags
+import com.android.wallpaper.util.ScreenSizeCalculator
 import com.android.wallpaper.util.TimeUtils.TimeTicker
 import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
 
 /**
  * Provide reusable clock view and related util functions.
  *
  * @property screenSize The Activity or Fragment's window size.
  */
-class ClockViewFactoryImpl(
-    private val appContext: Context,
-    val screenSize: Point,
+class ThemePickerClockViewFactory
+@Inject
+constructor(
+    activity: Activity,
     private val wallpaperManager: WallpaperManager,
     private val registry: ClockRegistry,
 ) : ClockViewFactory {
+    private val appContext = activity.applicationContext
     private val resources = appContext.resources
+    private val screenSize =
+        ScreenSizeCalculator.getInstance().getScreenSize(activity.windowManager.defaultDisplay)
     private val timeTickListeners: ConcurrentHashMap<Int, TimeTicker> = ConcurrentHashMap()
     private val clockControllers: ConcurrentHashMap<String, ClockController> = ConcurrentHashMap()
     private val smallClockFrames: HashMap<String, FrameLayout> = HashMap()
@@ -60,6 +65,7 @@
      * configs, e.g. animation state, might change during the reuse of the clock view in the app.
      */
     override fun getLargeView(clockId: String): View {
+        assert(!Flags.newCustomizationPickerUi())
         return getController(clockId).largeClock.let {
             it.animations.onPickerCarouselSwiping(1F)
             it.view
@@ -71,6 +77,7 @@
      * configs, e.g. translation X, might change during the reuse of the clock view in the app.
      */
     override fun getSmallView(clockId: String): View {
+        assert(!Flags.newCustomizationPickerUi())
         val smallClockFrame =
             smallClockFrames[clockId]
                 ?: createSmallClockFrame().also {
@@ -82,14 +89,6 @@
         return smallClockFrame
     }
 
-    /** Enables or disables the reactive swipe interaction */
-    override fun setReactiveTouchInteractionEnabled(clockId: String, enable: Boolean) {
-        check(BaseFlags.get().isClockReactiveVariantsEnabled()) {
-            "isClockReactiveVariantsEnabled is disabled"
-        }
-        getController(clockId).events.isReactiveTouchInteractionEnabled = enable
-    }
-
     private fun createSmallClockFrame(): FrameLayout {
         val smallClockFrame = FrameLayout(appContext)
         val layoutParams =
@@ -97,7 +96,7 @@
                 FrameLayout.LayoutParams.WRAP_CONTENT,
                 resources.getDimensionPixelSize(
                     com.android.systemui.customization.R.dimen.small_clock_height
-                )
+                ),
             )
         layoutParams.topMargin = getSmallClockTopMargin()
         layoutParams.marginStart = getSmallClockStartPadding()
@@ -107,7 +106,7 @@
     }
 
     private fun getSmallClockTopMargin() =
-        getStatusBarHeight(appContext.resources) +
+        getStatusBarHeight(appContext) +
             appContext.resources.getDimensionPixelSize(
                 com.android.systemui.customization.R.dimen.small_clock_padding_top
             )
@@ -118,18 +117,28 @@
         )
 
     override fun updateColorForAllClocks(@ColorInt seedColor: Int?) {
-        clockControllers.values.forEach { it.events.onSeedColorChanged(seedColor = seedColor) }
+        clockControllers.values.forEach {
+            it.largeClock.run { events.onThemeChanged(theme.copy(seedColor = seedColor)) }
+            it.smallClock.run { events.onThemeChanged(theme.copy(seedColor = seedColor)) }
+        }
     }
 
     override fun updateColor(clockId: String, @ColorInt seedColor: Int?) {
-        clockControllers[clockId]?.events?.onSeedColorChanged(seedColor)
+        getController(clockId).let {
+            it.largeClock.run { events.onThemeChanged(theme.copy(seedColor = seedColor)) }
+            it.smallClock.run { events.onThemeChanged(theme.copy(seedColor = seedColor)) }
+        }
+    }
+
+    override fun updateFontAxes(clockId: String, settings: List<ClockFontAxisSetting>) {
+        getController(clockId).let { it.events.onFontAxesChanged(settings) }
     }
 
     override fun updateRegionDarkness() {
         val isRegionDark = isLockscreenWallpaperDark()
         clockControllers.values.forEach {
-            it.largeClock.events.onRegionDarknessChanged(isRegionDark)
-            it.smallClock.events.onRegionDarknessChanged(isRegionDark)
+            it.largeClock.run { events.onThemeChanged(theme.copy(isDarkTheme = isRegionDark)) }
+            it.smallClock.run { events.onThemeChanged(theme.copy(isDarkTheme = isRegionDark)) }
         }
     }
 
@@ -176,13 +185,12 @@
     }
 
     private fun initClockController(clockId: String): ClockController {
+        val isWallpaperDark = isLockscreenWallpaperDark()
         val controller =
-            registry.createExampleClock(clockId).also { it?.initialize(resources, 0f, 0f) }
+            registry.createExampleClock(clockId).also { it?.initialize(isWallpaperDark, 0f, 0f) }
         checkNotNull(controller)
 
-        val isWallpaperDark = isLockscreenWallpaperDark()
         // Initialize large clock
-        controller.largeClock.events.onRegionDarknessChanged(isWallpaperDark)
         controller.largeClock.events.onFontSettingChanged(
             resources
                 .getDimensionPixelSize(
@@ -193,7 +201,6 @@
         controller.largeClock.events.onTargetRegionChanged(getLargeClockRegion())
 
         // Initialize small clock
-        controller.smallClock.events.onRegionDarknessChanged(isWallpaperDark)
         controller.smallClock.events.onFontSettingChanged(
             resources
                 .getDimensionPixelSize(
@@ -202,21 +209,7 @@
                 .toFloat()
         )
         controller.smallClock.events.onTargetRegionChanged(getSmallClockRegion())
-
-        // Use placeholder for weather clock preview in picker.
-        // Use locale default temp unit since assistant default is not available in this context.
-        val useCelsius =
-            LocalePreferences.getTemperatureUnit() == LocalePreferences.TemperatureUnit.CELSIUS
-        controller.events.onWeatherDataChanged(
-            WeatherData(
-                description = DESCRIPTION_PLACEHODLER,
-                state = WEATHERICON_PLACEHOLDER,
-                temperature =
-                    if (useCelsius) TEMPERATURE_CELSIUS_PLACEHOLDER
-                    else TEMPERATURE_FAHRENHEIT_PLACEHOLDER,
-                useCelsius = useCelsius,
-            )
-        )
+        controller.events.onWeatherDataChanged(WeatherData.getPlaceholderWeatherData())
         return controller
     }
 
@@ -253,17 +246,17 @@
     }
 
     companion object {
-        const val DESCRIPTION_PLACEHODLER = ""
-        const val TEMPERATURE_FAHRENHEIT_PLACEHOLDER = 58
-        const val TEMPERATURE_CELSIUS_PLACEHOLDER = 21
-        val WEATHERICON_PLACEHOLDER = WeatherData.WeatherStateIcon.MOSTLY_SUNNY
-        const val USE_CELSIUS_PLACEHODLER = false
+        private fun getStatusBarHeight(context: Context): Int {
+            val display = context.displayNoVerify
+            if (display != null) {
+                return SystemBarUtils.getStatusBarHeight(context.resources, display.cutout)
+            }
 
-        private fun getStatusBarHeight(resource: Resources): Int {
             var result = 0
-            val resourceId: Int = resource.getIdentifier("status_bar_height", "dimen", "android")
+            val resourceId: Int =
+                context.resources.getIdentifier("status_bar_height", "dimen", "android")
             if (resourceId > 0) {
-                result = resource.getDimensionPixelSize(resourceId)
+                result = context.resources.getDimensionPixelSize(resourceId)
             }
             return result
         }
diff --git a/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl.kt b/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl.kt
index 942a846..f393880 100644
--- a/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl.kt
@@ -24,8 +24,11 @@
 import com.android.customization.picker.color.shared.model.ColorOptionModel
 import com.android.customization.picker.color.shared.model.ColorType
 import com.android.systemui.monet.Style
+import com.android.wallpaper.config.BaseFlags
 import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository
 import com.android.wallpaper.picker.customization.shared.model.WallpaperColorsModel
+import javax.inject.Inject
+import javax.inject.Singleton
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -36,11 +39,16 @@
 
 // TODO (b/262924623): refactor to remove dependency on ColorCustomizationManager & ColorOption
 // TODO (b/268203200): Create test for ColorPickerRepositoryImpl
-class ColorPickerRepositoryImpl(
+@Singleton
+class ColorPickerRepositoryImpl
+@Inject
+constructor(
     wallpaperColorsRepository: WallpaperColorsRepository,
     private val colorManager: ColorCustomizationManager,
 ) : ColorPickerRepository {
 
+    private val isNewPickerUi = BaseFlags.get().isNewPickerUi()
+
     private val homeWallpaperColors: StateFlow<WallpaperColorsModel?> =
         wallpaperColorsRepository.homeWallpaperColors
     private val lockWallpaperColors: StateFlow<WallpaperColorsModel?> =
@@ -51,8 +59,7 @@
     private val _isApplyingSystemColor = MutableStateFlow(false)
     override val isApplyingSystemColor = _isApplyingSystemColor.asStateFlow()
 
-    // TODO (b/299510645): update color options on selected option change after restart is disabled
-    override val colorOptions: Flow<Map<ColorType, List<ColorOptionModel>>> =
+    private val generatedColorOptions: Flow<Map<ColorType, List<ColorOptionImpl>>> =
         combine(homeWallpaperColors, lockWallpaperColors) { homeColors, lockColors ->
                 homeColors to lockColors
             }
@@ -66,7 +73,7 @@
                             Result.success(
                                 mapOf(
                                     ColorType.WALLPAPER_COLOR to listOf(),
-                                    ColorType.PRESET_COLOR to listOf()
+                                    ColorType.PRESET_COLOR to listOf(),
                                 )
                             )
                         )
@@ -76,28 +83,27 @@
                     val lockColorsLoaded = lockColors as WallpaperColorsModel.Loaded
                     colorManager.setWallpaperColors(
                         homeColorsLoaded.colors,
-                        lockColorsLoaded.colors
+                        lockColorsLoaded.colors,
                     )
                     colorManager.fetchOptions(
                         object : CustomizationManager.OptionsFetchedListener<ColorOption?> {
                             override fun onOptionsLoaded(options: MutableList<ColorOption?>?) {
-                                val wallpaperColorOptions: MutableList<ColorOptionModel> =
+                                val wallpaperColorOptions: MutableList<ColorOptionImpl> =
                                     mutableListOf()
-                                val presetColorOptions: MutableList<ColorOptionModel> =
+                                val presetColorOptions: MutableList<ColorOptionImpl> =
                                     mutableListOf()
                                 options?.forEach { option ->
                                     when ((option as ColorOptionImpl).type) {
                                         ColorType.WALLPAPER_COLOR ->
-                                            wallpaperColorOptions.add(option.toModel())
-                                        ColorType.PRESET_COLOR ->
-                                            presetColorOptions.add(option.toModel())
+                                            wallpaperColorOptions.add(option)
+                                        ColorType.PRESET_COLOR -> presetColorOptions.add(option)
                                     }
                                 }
                                 continuation.resumeWith(
                                     Result.success(
                                         mapOf(
                                             ColorType.WALLPAPER_COLOR to wallpaperColorOptions,
-                                            ColorType.PRESET_COLOR to presetColorOptions
+                                            ColorType.PRESET_COLOR to presetColorOptions,
                                         )
                                     )
                                 )
@@ -112,11 +118,88 @@
                                 )
                             }
                         },
-                        /* reload= */ false
+                        /* reload= */ false,
                     )
                 }
             }
 
+    override val colorOptions: Flow<Map<ColorType, List<ColorOptionModel>>> =
+        if (isNewPickerUi) {
+            // Convert to ColorOptionModel. When the selected color option changes, update each
+            // ColorOptionModel's isSelected by calling toModel again.
+            combine(generatedColorOptions, selectedColorOption) { generatedColorOptions, _ ->
+                generatedColorOptions
+                    .map { entry ->
+                        entry.key to entry.value.map { colorOption -> colorOption.toModel() }
+                    }
+                    .toMap()
+            }
+        } else {
+            combine(homeWallpaperColors, lockWallpaperColors) { homeColors, lockColors ->
+                    homeColors to lockColors
+                }
+                .map { (homeColors, lockColors) ->
+                    suspendCancellableCoroutine { continuation ->
+                        if (
+                            homeColors is WallpaperColorsModel.Loading ||
+                                lockColors is WallpaperColorsModel.Loading
+                        ) {
+                            continuation.resumeWith(
+                                Result.success(
+                                    mapOf(
+                                        ColorType.WALLPAPER_COLOR to listOf(),
+                                        ColorType.PRESET_COLOR to listOf(),
+                                    )
+                                )
+                            )
+                            return@suspendCancellableCoroutine
+                        }
+                        val homeColorsLoaded = homeColors as WallpaperColorsModel.Loaded
+                        val lockColorsLoaded = lockColors as WallpaperColorsModel.Loaded
+                        colorManager.setWallpaperColors(
+                            homeColorsLoaded.colors,
+                            lockColorsLoaded.colors,
+                        )
+                        colorManager.fetchOptions(
+                            object : CustomizationManager.OptionsFetchedListener<ColorOption?> {
+                                override fun onOptionsLoaded(options: MutableList<ColorOption?>?) {
+                                    val wallpaperColorOptions: MutableList<ColorOptionModel> =
+                                        mutableListOf()
+                                    val presetColorOptions: MutableList<ColorOptionModel> =
+                                        mutableListOf()
+                                    options?.forEach { option ->
+                                        when ((option as ColorOptionImpl).type) {
+                                            ColorType.WALLPAPER_COLOR ->
+                                                wallpaperColorOptions.add(option.toModel())
+                                            ColorType.PRESET_COLOR ->
+                                                presetColorOptions.add(option.toModel())
+                                        }
+                                    }
+                                    continuation.resumeWith(
+                                        Result.success(
+                                            mapOf(
+                                                ColorType.WALLPAPER_COLOR to wallpaperColorOptions,
+                                                ColorType.PRESET_COLOR to presetColorOptions,
+                                            )
+                                        )
+                                    )
+                                }
+
+                                override fun onError(throwable: Throwable?) {
+                                    Log.e(TAG, "Error loading theme bundles", throwable)
+                                    continuation.resumeWith(
+                                        Result.failure(
+                                            throwable ?: Throwable("Error loading theme bundles")
+                                        )
+                                    )
+                                }
+                            },
+                            /* reload= */ false,
+                        )
+                    }
+                }
+        }
+
     override suspend fun select(colorOptionModel: ColorOptionModel) {
         _isApplyingSystemColor.value = true
         suspendCancellableCoroutine { continuation ->
@@ -136,7 +219,7 @@
                             Result.failure(throwable ?: Throwable("Error loading theme bundles"))
                         )
                     }
-                }
+                },
             )
         }
     }
@@ -153,11 +236,7 @@
             colorOptionBuilder.addOverlayPackage(overlay.key, overlay.value)
         }
         val colorOption = colorOptionBuilder.build()
-        return ColorOptionModel(
-            key = "",
-            colorOption = colorOption,
-            isSelected = false,
-        )
+        return ColorOptionModel(key = "", colorOption = colorOption, isSelected = false)
     }
 
     override fun getCurrentColorSource(): String? {
@@ -168,6 +247,8 @@
         return ColorOptionModel(
             key = "${this.type}::${this.style}::${this.serializedPackages}",
             colorOption = this,
+            // Instead of using the selectedColorOption flow to determine isSelected, we check the
+            // source of truth, which is the settings, using ColorOption::isActive
             isSelected = isActive(colorManager),
         )
     }
diff --git a/src/com/android/customization/picker/color/data/repository/FakeColorPickerRepository.kt b/src/com/android/customization/picker/color/data/repository/FakeColorPickerRepository.kt
index f35d934..3f120ce 100644
--- a/src/com/android/customization/picker/color/data/repository/FakeColorPickerRepository.kt
+++ b/src/com/android/customization/picker/color/data/repository/FakeColorPickerRepository.kt
@@ -22,6 +22,7 @@
 import com.android.customization.model.ResourceConstants
 import com.android.customization.model.color.ColorOptionImpl
 import com.android.customization.model.color.ColorOptionsProvider
+import com.android.customization.model.color.ColorUtils.toColorString
 import com.android.customization.picker.color.shared.model.ColorOptionModel
 import com.android.customization.picker.color.shared.model.ColorType
 import com.android.systemui.monet.Style
@@ -40,7 +41,7 @@
         MutableStateFlow(
             mapOf<ColorType, List<ColorOptionModel>>(
                 ColorType.WALLPAPER_COLOR to listOf(),
-                ColorType.PRESET_COLOR to listOf()
+                ColorType.PRESET_COLOR to listOf(),
             )
         )
     override val colorOptions: StateFlow<Map<ColorType, List<ColorOptionModel>>> =
@@ -54,7 +55,7 @@
         wallpaperOptions: List<ColorOptionImpl>,
         presetOptions: List<ColorOptionImpl>,
         selectedColorOptionType: ColorType,
-        selectedColorOptionIndex: Int
+        selectedColorOptionIndex: Int,
     ) {
         _colorOptions.value =
             mapOf(
@@ -68,7 +69,7 @@
                                 ColorOptionModel(
                                     key = "${ColorType.WALLPAPER_COLOR}::$index",
                                     colorOption = colorOption,
-                                    isSelected = isSelected
+                                    isSelected = isSelected,
                                 )
                             if (isSelected) {
                                 selectedColorOption = colorOptionModel
@@ -86,7 +87,7 @@
                                 ColorOptionModel(
                                     key = "${ColorType.PRESET_COLOR}::$index",
                                     colorOption = colorOption,
-                                    isSelected = isSelected
+                                    isSelected = isSelected,
                                 )
                             if (isSelected) {
                                 selectedColorOption = colorOptionModel
@@ -101,7 +102,7 @@
         numWallpaperOptions: Int,
         numPresetOptions: Int,
         selectedColorOptionType: ColorType,
-        selectedColorOptionIndex: Int
+        selectedColorOptionIndex: Int,
     ) {
         _colorOptions.value =
             mapOf(
@@ -140,7 +141,7 @@
                             }
                             add(colorOption)
                         }
-                    }
+                    },
             )
     }
 
@@ -160,7 +161,7 @@
         return builder.build()
     }
 
-    fun buildPresetOption(style: Style, seedColor: String): ColorOptionImpl {
+    fun buildPresetOption(style: Style, seedColor: Int): ColorOptionImpl {
         val builder = ColorOptionImpl.Builder()
         builder.lightColors =
             intArrayOf(Color.TRANSPARENT, Color.TRANSPARENT, Color.TRANSPARENT, Color.TRANSPARENT)
@@ -170,9 +171,13 @@
         builder.source = ColorOptionsProvider.COLOR_SOURCE_PRESET
         builder.style = style
         builder.title = "Preset"
+        builder.seedColor = seedColor
         builder
             .addOverlayPackage("TEST_PACKAGE_TYPE", "preset_color")
-            .addOverlayPackage(ResourceConstants.OVERLAY_CATEGORY_SYSTEM_PALETTE, seedColor)
+            .addOverlayPackage(
+                ResourceConstants.OVERLAY_CATEGORY_SYSTEM_PALETTE,
+                toColorString(seedColor),
+            )
         return builder.build()
     }
 
@@ -192,7 +197,7 @@
         return builder.build()
     }
 
-    fun buildWallpaperOption(source: String, style: Style, seedColor: String): ColorOptionImpl {
+    fun buildWallpaperOption(source: String, style: Style, seedColor: Int): ColorOptionImpl {
         val builder = ColorOptionImpl.Builder()
         builder.lightColors =
             intArrayOf(Color.TRANSPARENT, Color.TRANSPARENT, Color.TRANSPARENT, Color.TRANSPARENT)
@@ -202,9 +207,13 @@
         builder.source = source
         builder.style = style
         builder.title = "Dynamic"
+        builder.seedColor = seedColor
         builder
             .addOverlayPackage("TEST_PACKAGE_TYPE", "wallpaper_color")
-            .addOverlayPackage(ResourceConstants.OVERLAY_CATEGORY_SYSTEM_PALETTE, seedColor)
+            .addOverlayPackage(
+                ResourceConstants.OVERLAY_CATEGORY_SYSTEM_PALETTE,
+                toColorString(seedColor),
+            )
         return builder.build()
     }
 
@@ -237,7 +246,7 @@
         _colorOptions.value =
             mapOf(
                 ColorType.WALLPAPER_COLOR to newWallpaperColorOptions,
-                ColorType.PRESET_COLOR to newBasicColorOptions
+                ColorType.PRESET_COLOR to newBasicColorOptions,
             )
     }
 
diff --git a/src/com/android/customization/picker/color/data/util/MaterialColorsGenerator.kt b/src/com/android/customization/picker/color/data/util/MaterialColorsGenerator.kt
new file mode 100644
index 0000000..a921365
--- /dev/null
+++ b/src/com/android/customization/picker/color/data/util/MaterialColorsGenerator.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.color.data.util
+
+import android.app.WallpaperColors
+import android.content.Context
+import android.content.res.Configuration
+import android.provider.Settings
+import android.util.Log
+import android.util.SparseIntArray
+import com.android.customization.model.ResourceConstants
+import com.android.systemui.monet.ColorScheme
+import com.android.systemui.monet.Style
+import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+import javax.inject.Singleton
+import org.json.JSONException
+import org.json.JSONObject
+
+/**
+ * Extract material next colors from wallpaper colors. Based on Nexus Launcher's
+ * MaterialColorsGenerator, nexuslauncher/widget/MaterialColorsGenerator.java
+ */
+@Singleton
+class MaterialColorsGenerator
+@Inject
+constructor(
+    @ApplicationContext private val applicationContext: Context,
+    private val secureSettingsRepository: SecureSettingsRepository,
+) {
+    private fun addShades(shades: List<Int>, resources: IntArray, output: SparseIntArray) {
+        if (shades.size != resources.size) {
+            Log.e(TAG, "The number of shades computed doesn't match the number of resources.")
+            return
+        }
+        for (i in resources.indices) {
+            output.put(resources[i], 0xff000000.toInt() or shades[i])
+        }
+    }
+
+    /**
+     * Generates the mapping from system color resources to values from wallpaper colors.
+     *
+     * @return a list of color resource IDs and a corresponding list of their color values
+     */
+    suspend fun generate(colors: WallpaperColors): Pair<IntArray, IntArray> {
+        val isDarkMode =
+            (applicationContext.resources.configuration.uiMode and
+                Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
+        val colorScheme = ColorScheme(colors, isDarkMode, fetchThemeStyleFromSetting())
+        return generate(colorScheme)
+    }
+
+    /**
+     * Generates the mapping from system color resources to values from color seed and style.
+     *
+     * @return a list of color resource IDs and a corresponding list of their color values
+     */
+    fun generate(colorSeed: Int, style: Style): Pair<IntArray, IntArray> {
+        val isDarkMode =
+            (applicationContext.resources.configuration.uiMode and
+                Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
+        val colorScheme = ColorScheme(colorSeed, isDarkMode, style)
+        return generate(colorScheme)
+    }
+
+    private fun generate(colorScheme: ColorScheme): Pair<IntArray, IntArray> {
+        val allNeutralColors: MutableList<Int> = ArrayList()
+        allNeutralColors.addAll(colorScheme.neutral1.allShades)
+        allNeutralColors.addAll(colorScheme.neutral2.allShades)
+
+        val allAccentColors: MutableList<Int> = ArrayList()
+        allAccentColors.addAll(colorScheme.accent1.allShades)
+        allAccentColors.addAll(colorScheme.accent2.allShades)
+        allAccentColors.addAll(colorScheme.accent3.allShades)
+
+        return Pair(
+            NEUTRAL_RESOURCES + ACCENT_RESOURCES,
+            (allNeutralColors + allAccentColors).toIntArray(),
+        )
+    }
+
+    private suspend fun fetchThemeStyleFromSetting(): Style {
+        val overlayPackageJson =
+            secureSettingsRepository.getString(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES)
+        return if (!overlayPackageJson.isNullOrEmpty()) {
+            try {
+                val jsonObject = JSONObject(overlayPackageJson)
+                Style.valueOf(jsonObject.getString(ResourceConstants.OVERLAY_CATEGORY_THEME_STYLE))
+            } catch (e: (JSONException)) {
+                Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e)
+                Style.TONAL_SPOT
+            } catch (e: IllegalArgumentException) {
+                Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e)
+                Style.TONAL_SPOT
+            }
+        } else {
+            Style.TONAL_SPOT
+        }
+    }
+
+    companion object {
+        private const val TAG = "MaterialColorsGenerator"
+
+        private val ACCENT_RESOURCES =
+            intArrayOf(
+                android.R.color.system_accent1_0,
+                android.R.color.system_accent1_10,
+                android.R.color.system_accent1_50,
+                android.R.color.system_accent1_100,
+                android.R.color.system_accent1_200,
+                android.R.color.system_accent1_300,
+                android.R.color.system_accent1_400,
+                android.R.color.system_accent1_500,
+                android.R.color.system_accent1_600,
+                android.R.color.system_accent1_700,
+                android.R.color.system_accent1_800,
+                android.R.color.system_accent1_900,
+                android.R.color.system_accent1_1000,
+                android.R.color.system_accent2_0,
+                android.R.color.system_accent2_10,
+                android.R.color.system_accent2_50,
+                android.R.color.system_accent2_100,
+                android.R.color.system_accent2_200,
+                android.R.color.system_accent2_300,
+                android.R.color.system_accent2_400,
+                android.R.color.system_accent2_500,
+                android.R.color.system_accent2_600,
+                android.R.color.system_accent2_700,
+                android.R.color.system_accent2_800,
+                android.R.color.system_accent2_900,
+                android.R.color.system_accent2_1000,
+                android.R.color.system_accent3_0,
+                android.R.color.system_accent3_10,
+                android.R.color.system_accent3_50,
+                android.R.color.system_accent3_100,
+                android.R.color.system_accent3_200,
+                android.R.color.system_accent3_300,
+                android.R.color.system_accent3_400,
+                android.R.color.system_accent3_500,
+                android.R.color.system_accent3_600,
+                android.R.color.system_accent3_700,
+                android.R.color.system_accent3_800,
+                android.R.color.system_accent3_900,
+                android.R.color.system_accent3_1000,
+            )
+        private val NEUTRAL_RESOURCES =
+            intArrayOf(
+                android.R.color.system_neutral1_0,
+                android.R.color.system_neutral1_10,
+                android.R.color.system_neutral1_50,
+                android.R.color.system_neutral1_100,
+                android.R.color.system_neutral1_200,
+                android.R.color.system_neutral1_300,
+                android.R.color.system_neutral1_400,
+                android.R.color.system_neutral1_500,
+                android.R.color.system_neutral1_600,
+                android.R.color.system_neutral1_700,
+                android.R.color.system_neutral1_800,
+                android.R.color.system_neutral1_900,
+                android.R.color.system_neutral1_1000,
+                android.R.color.system_neutral2_0,
+                android.R.color.system_neutral2_10,
+                android.R.color.system_neutral2_50,
+                android.R.color.system_neutral2_100,
+                android.R.color.system_neutral2_200,
+                android.R.color.system_neutral2_300,
+                android.R.color.system_neutral2_400,
+                android.R.color.system_neutral2_500,
+                android.R.color.system_neutral2_600,
+                android.R.color.system_neutral2_700,
+                android.R.color.system_neutral2_800,
+                android.R.color.system_neutral2_900,
+                android.R.color.system_neutral2_1000,
+            )
+    }
+}
diff --git a/src/com/android/customization/picker/color/domain/interactor/ColorPickerInteractor.kt b/src/com/android/customization/picker/color/domain/interactor/ColorPickerInteractor.kt
index e7759ce..4f779f8 100644
--- a/src/com/android/customization/picker/color/domain/interactor/ColorPickerInteractor.kt
+++ b/src/com/android/customization/picker/color/domain/interactor/ColorPickerInteractor.kt
@@ -18,15 +18,19 @@
 
 import com.android.customization.picker.color.data.repository.ColorPickerRepository
 import com.android.customization.picker.color.shared.model.ColorOptionModel
-import javax.inject.Provider
+import javax.inject.Inject
+import javax.inject.Singleton
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.onEach
 
 /** Single entry-point for all application state and business logic related to system color. */
-class ColorPickerInteractor(
+@Singleton
+class ColorPickerInteractor
+@Inject
+constructor(
     private val repository: ColorPickerRepository,
-    private val snapshotRestorer: Provider<ColorPickerSnapshotRestorer>,
+    private val snapshotRestorer: ColorPickerSnapshotRestorer,
 ) {
     val isApplyingSystemColor = repository.isApplyingSystemColor
 
@@ -51,11 +55,9 @@
             // actually updated until the picker restarts. Wait to do so when updated color options
             // become available
             repository.select(colorOptionModel)
-            snapshotRestorer.get().storeSnapshot(colorOptionModel)
+            snapshotRestorer.storeSnapshot(colorOptionModel)
         } catch (e: Exception) {
             _selectingColorOption.value = null
         }
     }
-
-    fun getCurrentColorOption(): ColorOptionModel = repository.getCurrentColorOption()
 }
diff --git a/src/com/android/customization/picker/color/domain/interactor/ColorPickerSnapshotRestorer.kt b/src/com/android/customization/picker/color/domain/interactor/ColorPickerSnapshotRestorer.kt
index dce59eb..656663c 100644
--- a/src/com/android/customization/picker/color/domain/interactor/ColorPickerSnapshotRestorer.kt
+++ b/src/com/android/customization/picker/color/domain/interactor/ColorPickerSnapshotRestorer.kt
@@ -18,14 +18,20 @@
 package com.android.customization.picker.color.domain.interactor
 
 import android.util.Log
+import com.android.customization.picker.color.data.repository.ColorPickerRepository
 import com.android.customization.picker.color.shared.model.ColorOptionModel
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore
 import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot
+import javax.inject.Inject
+import javax.inject.Singleton
 
 /** Handles state restoration for the color picker system. */
-class ColorPickerSnapshotRestorer(
-    private val interactor: ColorPickerInteractor,
+@Singleton
+class ColorPickerSnapshotRestorer
+@Inject
+constructor(
+    private val repository: ColorPickerRepository,
 ) : SnapshotRestorer {
 
     private var snapshotStore: SnapshotStore = SnapshotStore.NOOP
@@ -39,7 +45,7 @@
         store: SnapshotStore,
     ): RestorableSnapshot {
         snapshotStore = store
-        originalOption = interactor.getCurrentColorOption()
+        originalOption = repository.getCurrentColorOption()
         return snapshot(originalOption)
     }
 
@@ -60,7 +66,7 @@
                 )
             }
 
-            interactor.select(optionToRestore)
+            repository.select(optionToRestore)
         }
     }
 
diff --git a/src/com/android/customization/picker/color/shared/model/ColorOptionModel.kt b/src/com/android/customization/picker/color/shared/model/ColorOptionModel.kt
index 5fde08e..ba477bc 100644
--- a/src/com/android/customization/picker/color/shared/model/ColorOptionModel.kt
+++ b/src/com/android/customization/picker/color/shared/model/ColorOptionModel.kt
@@ -27,5 +27,5 @@
     val colorOption: ColorOption,
 
     /** Whether this color option is selected. */
-    var isSelected: Boolean,
+    val isSelected: Boolean,
 )
diff --git a/src/com/android/customization/picker/color/ui/binder/ColorOptionIconBinder2.kt b/src/com/android/customization/picker/color/ui/binder/ColorOptionIconBinder2.kt
new file mode 100644
index 0000000..2c197ad
--- /dev/null
+++ b/src/com/android/customization/picker/color/ui/binder/ColorOptionIconBinder2.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.customization.picker.color.ui.binder
+
+import com.android.customization.picker.color.ui.view.ColorOptionIconView2
+import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
+
+object ColorOptionIconBinder2 {
+    fun bind(view: ColorOptionIconView2, viewModel: ColorOptionIconViewModel, darkTheme: Boolean) {
+        if (darkTheme) {
+            view.bindColor(
+                view.resources.getColor(android.R.color.system_primary_dark, view.context.theme),
+                viewModel.darkThemeColor0,
+                viewModel.darkThemeColor1,
+                viewModel.darkThemeColor2,
+                viewModel.darkThemeColor3,
+            )
+        } else {
+            view.bindColor(
+                view.resources.getColor(android.R.color.system_primary_light, view.context.theme),
+                viewModel.lightThemeColor0,
+                viewModel.lightThemeColor1,
+                viewModel.lightThemeColor2,
+                viewModel.lightThemeColor3,
+            )
+        }
+    }
+}
diff --git a/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt b/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt
index 7b5b598..82ce77b 100644
--- a/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt
+++ b/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt
@@ -32,8 +32,8 @@
 import com.android.customization.picker.color.ui.view.ColorOptionIconView
 import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
 import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel
-import com.android.customization.picker.common.ui.view.ItemSpacing
 import com.android.themepicker.R
+import com.android.wallpaper.picker.common.ui.view.ItemSpacing
 import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
@@ -133,9 +133,10 @@
 
     interface Binding {
         fun saveInstanceState(savedState: Bundle)
+
         fun restoreInstanceState(savedState: Bundle)
     }
 
-    private val LAYOUT_MANAGER_SAVED_STATE: String = "layout_manager_state"
+    private const val LAYOUT_MANAGER_SAVED_STATE: String = "layout_manager_state"
     private var layoutManagerSavedState: Parcelable? = null
 }
diff --git a/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt b/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
index c2dc381..3adc913 100644
--- a/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
+++ b/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
@@ -20,6 +20,7 @@
 import android.content.res.Configuration
 import android.view.LayoutInflater
 import android.view.View
+import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.LinearLayout
 import androidx.core.view.isVisible
@@ -50,12 +51,34 @@
     ) {
         val optionContainer: LinearLayout =
             view.requireViewById(R.id.color_section_option_container)
+        val optionContainerLayoutParams = optionContainer.layoutParams
         val moreColorsButton: View = view.requireViewById(R.id.more_colors)
         if (isConnectedHorizontallyToOtherSections) {
             moreColorsButton.isVisible = true
             moreColorsButton.setOnClickListener(navigationOnClick)
+
+            // Match the height of option container and the other sections when connected
+            // horizontally.
+            optionContainerLayoutParams.height =
+                view.resources.getDimensionPixelSize(R.dimen.color_options_selected_option_height)
+            optionContainer.layoutParams = optionContainerLayoutParams
+            optionContainer.setPadding(
+                optionContainer.paddingLeft,
+                16,
+                optionContainer.paddingRight,
+                16
+            )
         } else {
             moreColorsButton.isVisible = false
+
+            optionContainerLayoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
+            optionContainer.layoutParams = optionContainerLayoutParams
+            optionContainer.setPadding(
+                optionContainer.paddingLeft,
+                20,
+                optionContainer.paddingRight,
+                20
+            )
         }
         lifecycleOwner.lifecycleScope.launch {
             lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
diff --git a/src/com/android/customization/picker/color/ui/fragment/ColorPickerFragment.kt b/src/com/android/customization/picker/color/ui/fragment/ColorPickerFragment.kt
index a2dc526..3f4bf57 100644
--- a/src/com/android/customization/picker/color/ui/fragment/ColorPickerFragment.kt
+++ b/src/com/android/customization/picker/color/ui/fragment/ColorPickerFragment.kt
@@ -20,10 +20,14 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.view.ViewGroup.MarginLayoutParams
 import android.widget.FrameLayout
 import androidx.cardview.widget.CardView
 import androidx.core.content.ContextCompat
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.isVisible
+import androidx.core.view.updateLayoutParams
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.get
 import androidx.lifecycle.lifecycleScope
@@ -70,7 +74,16 @@
                 container,
                 false,
             )
+        ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
+            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            v.updateLayoutParams<MarginLayoutParams> {
+                topMargin = insets.top
+                bottomMargin = insets.bottom
+            }
+            WindowInsetsCompat.CONSUMED
+        }
         setUpToolbar(view)
+
         val injector = InjectorProvider.getInjector() as ThemePickerInjector
         val lockScreenView: CardView = view.requireViewById(R.id.lock_preview)
         val homeScreenView: CardView = view.requireViewById(R.id.home_preview)
@@ -85,10 +98,7 @@
                 viewModel =
                     ViewModelProvider(
                             requireActivity(),
-                            injector.getColorPickerViewModelFactory(
-                                context = requireContext(),
-                                wallpaperColorsRepository = wallpaperColorsRepository,
-                            ),
+                            injector.getColorPickerViewModelFactory(requireContext()),
                         )
                         .get(),
                 lifecycleOwner = this,
diff --git a/src/com/android/customization/picker/color/ui/view/ColorOptionIconView2.kt b/src/com/android/customization/picker/color/ui/view/ColorOptionIconView2.kt
new file mode 100644
index 0000000..3fc6324
--- /dev/null
+++ b/src/com/android/customization/picker/color/ui/view/ColorOptionIconView2.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.color.ui.view
+
+import android.annotation.ColorInt
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.util.AttributeSet
+import com.android.themepicker.R
+import com.android.wallpaper.picker.option.ui.view.OptionItemBackground
+
+/**
+ * Draw a color option icon, which is a quadrant circle that can show at most 4 different colors.
+ */
+class ColorOptionIconView2(context: Context, attrs: AttributeSet) :
+    OptionItemBackground(context, attrs) {
+
+    private val paint = Paint().apply { style = Paint.Style.FILL }
+
+    private val path = Path()
+
+    private var color0 = DEFAULT_PLACEHOLDER_COLOR
+    private var color1 = DEFAULT_PLACEHOLDER_COLOR
+    private var color2 = DEFAULT_PLACEHOLDER_COLOR
+    private var color3 = DEFAULT_PLACEHOLDER_COLOR
+    private var strokeColor = DEFAULT_PLACEHOLDER_COLOR
+    private val strokeWidth =
+        context.resources
+            .getDimensionPixelSize(R.dimen.floating_sheet_color_option_stroke_width)
+            .toFloat()
+
+    private var w = 0
+    private var h = 0
+
+    /**
+     * @param color0 the color in the top left quadrant
+     * @param color1 the color in the top right quadrant
+     * @param color2 the color in the bottom left quadrant
+     * @param color3 the color in the bottom right quadrant
+     */
+    fun bindColor(
+        @ColorInt strokeColor: Int,
+        @ColorInt color0: Int,
+        @ColorInt color1: Int,
+        @ColorInt color2: Int,
+        @ColorInt color3: Int,
+    ) {
+        this.strokeColor = strokeColor
+        this.color0 = color0
+        this.color1 = color1
+        this.color2 = color2
+        this.color3 = color3
+        invalidate()
+    }
+
+    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+        this.w = w
+        this.h = h
+        super.onSizeChanged(w, h, oldw, oldh)
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        // The w and h need to be an even number to avoid tiny pixel-level gaps between the pies
+        w = w.roundDownToEven()
+        h = h.roundDownToEven()
+
+        val width = w.toFloat()
+        val height = h.toFloat()
+
+        val left = 2 * strokeWidth
+        val right = width - 2 * strokeWidth
+        val top = 2 * strokeWidth
+        val bottom = height - 2 * strokeWidth
+        val cornerRadius = ((right - left) / 2) * (1f - 0.25f * progress)
+        val save = canvas.save()
+        path.reset()
+        path.addRoundRect(left, top, right, bottom, cornerRadius, cornerRadius, Path.Direction.CW)
+        path.close()
+        canvas.clipPath(path)
+
+        canvas.apply {
+            paint.style = Paint.Style.FILL
+            // top left
+            paint.color = color0
+            drawRect(0f, 0f, width / 2, height / 2, paint)
+            // top right
+            paint.color = color1
+            drawRect(width / 2, 0f, width, height / 2, paint)
+            // bottom left
+            paint.color = color2
+            drawRect(0f, height / 2, width / 2, height, paint)
+            // bottom right
+            paint.color = color3
+            drawRect(width / 2, height / 2, width, height, paint)
+        }
+
+        canvas.restoreToCount(save)
+        paint.style = Paint.Style.STROKE
+        paint.color = strokeColor
+        paint.alpha = (255 * progress).toInt()
+        paint.strokeWidth = this.strokeWidth
+        val strokeCornerRadius = ((width - strokeWidth) / 2) * (1f - 0.25f * progress)
+        val halfStrokeWidth = 0.5f * strokeWidth
+        // Stroke is centered along the path, so account for half strokeWidth to stay within View
+        canvas.drawRoundRect(
+            halfStrokeWidth,
+            halfStrokeWidth,
+            width - halfStrokeWidth,
+            height - halfStrokeWidth,
+            strokeCornerRadius,
+            strokeCornerRadius,
+            paint,
+        )
+    }
+
+    companion object {
+        const val DEFAULT_PLACEHOLDER_COLOR = Color.BLACK
+
+        fun Int.roundDownToEven(): Int {
+            return if (this % 2 == 0) this else this - 1
+        }
+    }
+}
diff --git a/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt b/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
index 52df31a..9dba4bb 100644
--- a/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
+++ b/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
@@ -49,10 +49,9 @@
 
     /** View-models for each color tab. */
     val colorTypeTabs: Flow<Map<ColorType, ColorTypeTabViewModel>> =
-        combine(
-            interactor.colorOptions,
-            selectedColorTypeTabId,
-        ) { colorOptions, selectedColorTypeIdOrNull ->
+        combine(interactor.colorOptions, selectedColorTypeTabId) {
+            colorOptions,
+            selectedColorTypeIdOrNull ->
             colorOptions.keys
                 .mapIndexed { index, colorType ->
                     val isSelected =
@@ -143,8 +142,7 @@
                                                             .sourceForLogging,
                                                         colorOptionModel.colorOption
                                                             .styleForLogging,
-                                                        colorOptionModel.colorOption
-                                                            .seedColorForLogging,
+                                                        colorOptionModel.colorOption.seedColor,
                                                     )
                                                 }
                                             }
@@ -180,7 +178,7 @@
                     min(
                         max(0, COLOR_SECTION_OPTION_SIZE - wallpaperOptions.size),
                         presetOptions.size,
-                    )
+                    ),
                 )
             subOptions + additionalSubOptions
         }
@@ -192,16 +190,12 @@
     ) : ViewModelProvider.Factory {
         override fun <T : ViewModel> create(modelClass: Class<T>): T {
             @Suppress("UNCHECKED_CAST")
-            return ColorPickerViewModel(
-                context = context,
-                interactor = interactor,
-                logger = logger,
-            )
+            return ColorPickerViewModel(context = context, interactor = interactor, logger = logger)
                 as T
         }
     }
 
     companion object {
-        private const val COLOR_SECTION_OPTION_SIZE = 5
+        private const val COLOR_SECTION_OPTION_SIZE = 6
     }
 }
diff --git a/src/com/android/customization/picker/common/ui/view/DoubleRowListItemSpacing.kt b/src/com/android/customization/picker/common/ui/view/DoubleRowListItemSpacing.kt
new file mode 100644
index 0000000..9868073
--- /dev/null
+++ b/src/com/android/customization/picker/common/ui/view/DoubleRowListItemSpacing.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.customization.picker.common.ui.view
+
+import android.graphics.Rect
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+
+/** Item spacing used by the horizontal RecyclerView with 2 rows. */
+class DoubleRowListItemSpacing(
+    private val edgeItemSpacePx: Int,
+    private val itemHorizontalSpacePx: Int,
+    private val itemVerticalSpacePx: Int,
+) : RecyclerView.ItemDecoration() {
+    override fun getItemOffsets(
+        outRect: Rect,
+        view: View,
+        parent: RecyclerView,
+        state: RecyclerView.State,
+    ) {
+        val itemIndex = parent.getChildAdapterPosition(view)
+        val columnIndex = itemIndex / 2
+        val isRtl = parent.layoutManager?.layoutDirection == View.LAYOUT_DIRECTION_RTL
+
+        val itemCount = parent.adapter?.itemCount ?: 0
+        val columnCount = (itemCount + 1) / 2
+        when {
+            columnCount == 1 -> {
+                outRect.left = edgeItemSpacePx
+                outRect.right = edgeItemSpacePx
+            }
+            columnIndex > 0 && columnIndex < columnCount - 1 -> {
+                outRect.left = itemHorizontalSpacePx
+                outRect.right = itemHorizontalSpacePx
+            }
+            columnIndex == 0 -> {
+                outRect.left = if (!isRtl) edgeItemSpacePx else itemHorizontalSpacePx
+                outRect.right = if (isRtl) edgeItemSpacePx else itemHorizontalSpacePx
+            }
+            columnIndex == columnCount - 1 -> {
+                outRect.right = if (!isRtl) edgeItemSpacePx else itemHorizontalSpacePx
+                outRect.left = if (isRtl) edgeItemSpacePx else itemHorizontalSpacePx
+            }
+        }
+
+        if (itemIndex % 2 == 0) {
+            outRect.bottom = itemVerticalSpacePx
+        }
+    }
+}
diff --git a/src/com/android/customization/picker/common/ui/view/ItemSpacing.kt b/src/com/android/customization/picker/common/ui/view/ItemSpacing.kt
deleted file mode 100644
index ca689aa..0000000
--- a/src/com/android/customization/picker/common/ui/view/ItemSpacing.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.customization.picker.common.ui.view
-
-import android.graphics.Rect
-import androidx.core.view.ViewCompat
-import androidx.recyclerview.widget.RecyclerView
-
-/** Item spacing used by the RecyclerView. */
-class ItemSpacing(
-    private val itemSpacingDp: Int,
-) : RecyclerView.ItemDecoration() {
-    override fun getItemOffsets(outRect: Rect, itemPosition: Int, parent: RecyclerView) {
-        val addSpacingToStart = itemPosition > 0
-        val addSpacingToEnd = itemPosition < (parent.adapter?.itemCount ?: 0) - 1
-        val isRtl = parent.layoutManager?.layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL
-        val density = parent.context.resources.displayMetrics.density
-        val halfItemSpacingPx = itemSpacingDp.toPx(density) / 2
-        if (!isRtl) {
-            outRect.left = if (addSpacingToStart) halfItemSpacingPx else 0
-            outRect.right = if (addSpacingToEnd) halfItemSpacingPx else 0
-        } else {
-            outRect.left = if (addSpacingToEnd) halfItemSpacingPx else 0
-            outRect.right = if (addSpacingToStart) halfItemSpacingPx else 0
-        }
-    }
-
-    private fun Int.toPx(density: Float): Int {
-        return (this * density).toInt()
-    }
-
-    companion object {
-        const val TAB_ITEM_SPACING_DP = 12
-        const val ITEM_SPACING_DP = 8
-    }
-}
diff --git a/src/com/android/customization/picker/common/ui/view/SingleRowListItemSpacing.kt b/src/com/android/customization/picker/common/ui/view/SingleRowListItemSpacing.kt
new file mode 100644
index 0000000..5faf248
--- /dev/null
+++ b/src/com/android/customization/picker/common/ui/view/SingleRowListItemSpacing.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.common.ui.view
+
+import android.graphics.Rect
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+
+/** Item spacing used by the horizontal RecyclerView with only 1 row. */
+class SingleRowListItemSpacing(
+    private val edgeItemSpacePx: Int,
+    private val itemHorizontalSpacePx: Int,
+) : RecyclerView.ItemDecoration() {
+    override fun getItemOffsets(
+        outRect: Rect,
+        view: View,
+        parent: RecyclerView,
+        state: RecyclerView.State,
+    ) {
+        val itemIndex = parent.getChildAdapterPosition(view)
+        val itemCount = parent.adapter?.itemCount ?: 0
+        val isRtl = parent.layoutManager?.layoutDirection == View.LAYOUT_DIRECTION_RTL
+        when (itemIndex) {
+            0 -> {
+                outRect.left = if (!isRtl) edgeItemSpacePx else itemHorizontalSpacePx
+                outRect.right = if (isRtl) edgeItemSpacePx else itemHorizontalSpacePx
+            }
+            itemCount - 1 -> {
+                outRect.right = if (!isRtl) edgeItemSpacePx else itemHorizontalSpacePx
+                outRect.left = if (isRtl) edgeItemSpacePx else itemHorizontalSpacePx
+            }
+            else -> {
+                outRect.left = itemHorizontalSpacePx
+                outRect.right = itemHorizontalSpacePx
+            }
+        }
+    }
+}
diff --git a/src/com/android/customization/picker/grid/data/repository/GridRepository.kt b/src/com/android/customization/picker/grid/data/repository/GridRepository.kt
index f384429..dc308db 100644
--- a/src/com/android/customization/picker/grid/data/repository/GridRepository.kt
+++ b/src/com/android/customization/picker/grid/data/repository/GridRepository.kt
@@ -30,6 +30,8 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.suspendCancellableCoroutine
@@ -37,11 +39,17 @@
 
 interface GridRepository {
     suspend fun isAvailable(): Boolean
+
     fun getOptionChanges(): Flow<Unit>
+
     suspend fun getOptions(): GridOptionItemsModel
-    fun getSelectedOption(): GridOption?
+
+    fun getSelectedOption(): StateFlow<GridOption?>
+
     fun applySelectedOption(callback: Callback)
+
     fun clearSelectedOption()
+
     fun isSelectedOptionApplied(): Boolean
 }
 
@@ -63,7 +71,7 @@
 
     private var appliedOption: GridOption? = null
 
-    override fun getSelectedOption() = selectedOption.value
+    override fun getSelectedOption() = selectedOption.asStateFlow()
 
     override suspend fun getOptions(): GridOptionItemsModel {
         return withContext(backgroundDispatcher) {
@@ -133,6 +141,7 @@
                         option,
                         object : CustomizationManager.Callback {
                             override fun onSuccess() {
+                                selectedOption.value = option
                                 continuation.resume(true)
                             }
 
@@ -147,7 +156,7 @@
     }
 
     override fun applySelectedOption(callback: Callback) {
-        val option = getSelectedOption()
+        val option = getSelectedOption().value
         manager.apply(
             option,
             if (isGridApplyButtonEnabled) {
diff --git a/src/com/android/customization/picker/grid/data/repository/ShapeGridRepository.kt b/src/com/android/customization/picker/grid/data/repository/ShapeGridRepository.kt
new file mode 100644
index 0000000..86c455e
--- /dev/null
+++ b/src/com/android/customization/picker/grid/data/repository/ShapeGridRepository.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.customization.picker.grid.data.repository
+
+import com.android.customization.model.grid.GridOptionModel
+import com.android.customization.model.grid.ShapeGridManager
+import com.android.customization.model.grid.ShapeOptionModel
+import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+@Singleton
+class ShapeGridRepository
+@Inject
+constructor(
+    private val manager: ShapeGridManager,
+    @BackgroundDispatcher private val bgScope: CoroutineScope,
+    @BackgroundDispatcher private val bgDispatcher: CoroutineDispatcher,
+) {
+
+    private val _shapeOptions = MutableStateFlow<List<ShapeOptionModel>?>(null)
+    private val _gridOptions = MutableStateFlow<List<GridOptionModel>?>(null)
+
+    init {
+        bgScope.launch {
+            _gridOptions.value = manager.getGridOptions()
+            _shapeOptions.value = manager.getShapeOptions()
+        }
+    }
+
+    val shapeOptions: StateFlow<List<ShapeOptionModel>?> = _shapeOptions.asStateFlow()
+
+    val selectedShapeOption: Flow<ShapeOptionModel?> =
+        shapeOptions.map { shapeOptions -> shapeOptions?.firstOrNull { it.isCurrent } }
+
+    val gridOptions: StateFlow<List<GridOptionModel>?> = _gridOptions.asStateFlow()
+
+    val selectedGridOption: Flow<GridOptionModel?> =
+        gridOptions.map { gridOptions -> gridOptions?.firstOrNull { it.isCurrent } }
+
+    suspend fun applySelectedOption(shapeKey: String, gridKey: String) =
+        withContext(bgDispatcher) {
+            manager.applyShapeGridOption(shapeKey, gridKey)
+            // After applying, we should query and update shape and grid options again.
+            _gridOptions.value = manager.getGridOptions()
+            _shapeOptions.value = manager.getShapeOptions()
+        }
+}
diff --git a/src/com/android/customization/picker/grid/domain/interactor/GridInteractor.kt b/src/com/android/customization/picker/grid/domain/interactor/GridInteractor.kt
index 02e16dd..015bcdf 100644
--- a/src/com/android/customization/picker/grid/domain/interactor/GridInteractor.kt
+++ b/src/com/android/customization/picker/grid/domain/interactor/GridInteractor.kt
@@ -18,7 +18,6 @@
 package com.android.customization.picker.grid.domain.interactor
 
 import com.android.customization.model.CustomizationManager
-import com.android.customization.model.grid.GridOption
 import com.android.customization.picker.grid.data.repository.GridRepository
 import com.android.customization.picker.grid.shared.model.GridOptionItemModel
 import com.android.customization.picker.grid.shared.model.GridOptionItemsModel
@@ -75,7 +74,7 @@
         }
     }
 
-    fun getSelectOptionNonSuspend(): GridOption? = repository.getSelectedOption()
+    fun getSelectOptionStateFlow() = repository.getSelectedOption()
 
     fun clearSelectedOption() = repository.clearSelectedOption()
 
diff --git a/src/com/android/customization/picker/grid/domain/interactor/ShapeGridInteractor.kt b/src/com/android/customization/picker/grid/domain/interactor/ShapeGridInteractor.kt
new file mode 100644
index 0000000..8c4522e
--- /dev/null
+++ b/src/com/android/customization/picker/grid/domain/interactor/ShapeGridInteractor.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.customization.picker.grid.domain.interactor
+
+import com.android.customization.picker.grid.data.repository.ShapeGridRepository
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ShapeGridInteractor @Inject constructor(private val repository: ShapeGridRepository) {
+
+    val shapeOptions = repository.shapeOptions
+
+    val selectedShapeOption = repository.selectedShapeOption
+
+    val gridOptions = repository.gridOptions
+
+    val selectedGridOption = repository.selectedGridOption
+
+    suspend fun applySelectedOption(shapeKey: String, gridKey: String) =
+        repository.applySelectedOption(shapeKey, gridKey)
+}
diff --git a/src/com/android/customization/picker/grid/ui/binder/GridScreenBinder.kt b/src/com/android/customization/picker/grid/ui/binder/GridScreenBinder.kt
index 9948dee..36d16cd 100644
--- a/src/com/android/customization/picker/grid/ui/binder/GridScreenBinder.kt
+++ b/src/com/android/customization/picker/grid/ui/binder/GridScreenBinder.kt
@@ -26,10 +26,10 @@
 import androidx.lifecycle.repeatOnLifecycle
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
-import com.android.customization.picker.common.ui.view.ItemSpacing
 import com.android.customization.picker.grid.ui.viewmodel.GridIconViewModel
 import com.android.customization.picker.grid.ui.viewmodel.GridScreenViewModel
 import com.android.themepicker.R
+import com.android.wallpaper.picker.common.ui.view.ItemSpacing
 import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter
 import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder
 import kotlinx.coroutines.CoroutineDispatcher
diff --git a/src/com/android/customization/picker/grid/ui/fragment/GridFragment.kt b/src/com/android/customization/picker/grid/ui/fragment/GridFragment.kt
index b48f41a..7637994 100644
--- a/src/com/android/customization/picker/grid/ui/fragment/GridFragment.kt
+++ b/src/com/android/customization/picker/grid/ui/fragment/GridFragment.kt
@@ -22,10 +22,14 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.view.ViewGroup.MarginLayoutParams
 import android.widget.Button
 import android.widget.Toast
 import androidx.core.content.ContextCompat
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.isVisible
+import androidx.core.view.updateLayoutParams
 import androidx.lifecycle.ViewModelProvider
 import androidx.transition.Transition
 import androidx.transition.doOnStart
@@ -66,6 +70,14 @@
                 container,
                 false,
             )
+        ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
+            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            v.updateLayoutParams<MarginLayoutParams> {
+                topMargin = insets.top
+                bottomMargin = insets.bottom
+            }
+            WindowInsetsCompat.CONSUMED
+        }
         setUpToolbar(view)
 
         val isGridApplyButtonEnabled = BaseFlags.get().isGridApplyButtonEnabled(requireContext())
@@ -115,7 +127,7 @@
                                     context,
                                     getString(
                                         R.string.toast_of_changing_grid,
-                                        gridInteractor.getSelectOptionNonSuspend()?.title
+                                        gridInteractor.getSelectOptionStateFlow().value?.title
                                     ),
                                     Toast.LENGTH_SHORT
                                 )
@@ -128,7 +140,7 @@
                             val errorMsg =
                                 getString(
                                     R.string.toast_of_failure_to_change_grid,
-                                    gridInteractor.getSelectOptionNonSuspend()?.title
+                                    gridInteractor.getSelectOptionStateFlow().value?.title
                                 )
                             Toast.makeText(context, errorMsg, Toast.LENGTH_SHORT).show()
                             Log.e(TAG, errorMsg, throwable)
@@ -178,7 +190,10 @@
                         ),
                     initialExtrasProvider = {
                         val bundle = Bundle()
-                        bundle.putString("name", gridInteractor.getSelectOptionNonSuspend()?.name)
+                        bundle.putString(
+                            "name",
+                            gridInteractor.getSelectOptionStateFlow().value?.name
+                        )
                         bundle
                     },
                     wallpaperInfoProvider = {
diff --git a/src/com/android/customization/picker/grid/ui/section/GridSectionController.java b/src/com/android/customization/picker/grid/ui/section/GridSectionController.java
index 0e15609..bc66812 100644
--- a/src/com/android/customization/picker/grid/ui/section/GridSectionController.java
+++ b/src/com/android/customization/picker/grid/ui/section/GridSectionController.java
@@ -51,8 +51,7 @@
     public GridSectionController(
             GridOptionsManager gridOptionsManager,
             CustomizationSectionNavigationController sectionNavigationController,
-            LifecycleOwner lifecycleOwner,
-            boolean isRevampedUiEnabled) {
+            LifecycleOwner lifecycleOwner) {
         mGridOptionsManager = gridOptionsManager;
         mSectionNavigationController = sectionNavigationController;
         mLifecycleOwner = lifecycleOwner;
diff --git a/src/com/android/customization/picker/grid/ui/viewmodel/ShapeIconViewModel.kt b/src/com/android/customization/picker/grid/ui/viewmodel/ShapeIconViewModel.kt
new file mode 100644
index 0000000..1283603
--- /dev/null
+++ b/src/com/android/customization/picker/grid/ui/viewmodel/ShapeIconViewModel.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.grid.ui.viewmodel
+
+data class ShapeIconViewModel(val key: String, val path: String)
diff --git a/src/com/android/customization/picker/mode/data/repository/DarkModeRepository.kt b/src/com/android/customization/picker/mode/data/repository/DarkModeRepository.kt
new file mode 100644
index 0000000..28f5017
--- /dev/null
+++ b/src/com/android/customization/picker/mode/data/repository/DarkModeRepository.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.data.repository
+
+import com.android.customization.picker.mode.shared.util.DarkModeUtil
+import com.android.wallpaper.system.PowerManagerWrapper
+import com.android.wallpaper.system.UiModeManagerWrapper
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+@Singleton
+class DarkModeRepository
+@Inject
+constructor(
+    darkModeUtil: DarkModeUtil,
+    private val uiModeManager: UiModeManagerWrapper,
+    private val powerManager: PowerManagerWrapper,
+) {
+    private val isPowerSaveMode = MutableStateFlow(powerManager.getIsPowerSaveMode() ?: false)
+
+    private val isAvailable = darkModeUtil.isAvailable()
+
+    val isEnabled =
+        if (isAvailable) {
+            isPowerSaveMode.map { !it }
+        } else flowOf(false)
+
+    private val _isDarkMode = MutableStateFlow(uiModeManager.getIsNightModeActivated())
+    val isDarkMode = _isDarkMode.asStateFlow()
+
+    fun setDarkModeActivated(isActive: Boolean) {
+        uiModeManager.setNightModeActivated(isActive)
+        refreshIsDarkModeActivated()
+    }
+
+    fun refreshIsDarkModeActivated() {
+        _isDarkMode.value = uiModeManager.getIsNightModeActivated()
+    }
+
+    fun refreshIsPowerSaveModeActivated() {
+        powerManager.getIsPowerSaveMode()?.let { isPowerSaveMode.value = it }
+    }
+}
diff --git a/src/com/android/customization/picker/mode/domain/interactor/DarkModeInteractor.kt b/src/com/android/customization/picker/mode/domain/interactor/DarkModeInteractor.kt
new file mode 100644
index 0000000..1b74e33
--- /dev/null
+++ b/src/com/android/customization/picker/mode/domain/interactor/DarkModeInteractor.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.domain.interactor
+
+import com.android.customization.picker.mode.data.repository.DarkModeRepository
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class DarkModeInteractor @Inject constructor(private val repository: DarkModeRepository) {
+    val isEnabled = repository.isEnabled
+    val isDarkMode = repository.isDarkMode
+
+    fun setDarkModeActivated(isActive: Boolean) = repository.setDarkModeActivated(isActive)
+}
diff --git a/src/com/android/customization/picker/mode/shared/util/DarkModeLifecycleUtil.kt b/src/com/android/customization/picker/mode/shared/util/DarkModeLifecycleUtil.kt
new file mode 100644
index 0000000..749ac2e
--- /dev/null
+++ b/src/com/android/customization/picker/mode/shared/util/DarkModeLifecycleUtil.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.shared.util
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.PowerManager
+import android.text.TextUtils
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import com.android.customization.picker.mode.data.repository.DarkModeRepository
+import dagger.hilt.android.qualifiers.ActivityContext
+import dagger.hilt.android.scopes.ActivityScoped
+import javax.inject.Inject
+
+/**
+ * This class observes the activity lifecycle and updates the DarkModeRepositoryImpl based on
+ * lifecycle phases.
+ */
+@ActivityScoped
+class DarkModeLifecycleUtil
+@Inject
+constructor(
+    @ActivityContext private val activityContext: Context,
+    private val darkModeRepository: DarkModeRepository,
+) {
+    private val lifecycleOwner = activityContext as LifecycleOwner
+
+    private val batterySaverStateReceiver =
+        object : BroadcastReceiver() {
+            override fun onReceive(context: Context?, intent: Intent?) {
+                if (
+                    intent != null &&
+                        TextUtils.equals(intent.action, PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
+                ) {
+                    darkModeRepository.refreshIsPowerSaveModeActivated()
+                }
+            }
+        }
+    private val lifecycleObserver =
+        object : DefaultLifecycleObserver {
+            @Synchronized
+            override fun onStart(owner: LifecycleOwner) {
+                super.onStart(owner)
+                darkModeRepository.refreshIsDarkModeActivated()
+                darkModeRepository.refreshIsPowerSaveModeActivated()
+                if (lifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
+                    activityContext.registerReceiver(
+                        batterySaverStateReceiver,
+                        IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED),
+                    )
+                }
+            }
+
+            @Synchronized
+            override fun onStop(owner: LifecycleOwner) {
+                super.onStop(owner)
+                activityContext.unregisterReceiver(batterySaverStateReceiver)
+            }
+
+            @Synchronized
+            override fun onDestroy(owner: LifecycleOwner) {
+                super.onDestroy(owner)
+                lifecycleOwner.lifecycle.removeObserver(this)
+            }
+        }
+
+    init {
+        lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
+    }
+}
diff --git a/src/com/android/customization/picker/mode/shared/util/DarkModeUtil.kt b/src/com/android/customization/picker/mode/shared/util/DarkModeUtil.kt
new file mode 100644
index 0000000..9ad514d
--- /dev/null
+++ b/src/com/android/customization/picker/mode/shared/util/DarkModeUtil.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.shared.util
+
+interface DarkModeUtil {
+    fun isAvailable(): Boolean
+}
diff --git a/src/com/android/customization/picker/mode/shared/util/DarkModeUtilImpl.kt b/src/com/android/customization/picker/mode/shared/util/DarkModeUtilImpl.kt
new file mode 100644
index 0000000..a8e8535
--- /dev/null
+++ b/src/com/android/customization/picker/mode/shared/util/DarkModeUtilImpl.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.shared.util
+
+import android.Manifest
+import android.content.Context
+import android.content.pm.PackageManager
+import androidx.core.content.ContextCompat
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class DarkModeUtilImpl @Inject constructor(@ApplicationContext private val context: Context) :
+    DarkModeUtil {
+    override fun isAvailable(): Boolean {
+        return (ContextCompat.checkSelfPermission(
+            context,
+            Manifest.permission.MODIFY_DAY_NIGHT_MODE,
+        ) == PackageManager.PERMISSION_GRANTED)
+    }
+}
diff --git a/src/com/android/customization/picker/mode/shared/util/FakeDarkModeUtil.kt b/src/com/android/customization/picker/mode/shared/util/FakeDarkModeUtil.kt
new file mode 100644
index 0000000..f0225ef
--- /dev/null
+++ b/src/com/android/customization/picker/mode/shared/util/FakeDarkModeUtil.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.shared.util
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class FakeDarkModeUtil @Inject constructor() : DarkModeUtil {
+    override fun isAvailable(): Boolean {
+        return true
+    }
+}
diff --git a/src/com/android/customization/picker/mode/ui/binder/DarkModeBinder.kt b/src/com/android/customization/picker/mode/ui/binder/DarkModeBinder.kt
new file mode 100644
index 0000000..b9c7041
--- /dev/null
+++ b/src/com/android/customization/picker/mode/ui/binder/DarkModeBinder.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.ui.binder
+
+import android.widget.Switch
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.customization.picker.mode.ui.viewmodel.DarkModeViewModel
+import kotlinx.coroutines.launch
+
+object DarkModeBinder {
+    fun bind(darkModeToggle: Switch, viewModel: DarkModeViewModel, lifecycleOwner: LifecycleOwner) {
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch { viewModel.isEnabled.collect { darkModeToggle.isEnabled = it } }
+                launch { viewModel.previewingIsDarkMode.collect { darkModeToggle.isChecked = it } }
+                launch {
+                    viewModel.toggleDarkMode.collect {
+                        darkModeToggle.setOnCheckedChangeListener { _, _ -> it.invoke() }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/com/android/customization/picker/mode/ui/viewmodel/DarkModeViewModel.kt b/src/com/android/customization/picker/mode/ui/viewmodel/DarkModeViewModel.kt
new file mode 100644
index 0000000..f51d966
--- /dev/null
+++ b/src/com/android/customization/picker/mode/ui/viewmodel/DarkModeViewModel.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.ui.viewmodel
+
+import com.android.customization.module.logging.ThemesUserEventLogger
+import com.android.customization.picker.mode.domain.interactor.DarkModeInteractor
+import dagger.hilt.android.scopes.ViewModelScoped
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+
+@ViewModelScoped
+class DarkModeViewModel
+@Inject
+constructor(private val interactor: DarkModeInteractor, private val logger: ThemesUserEventLogger) {
+    private val isDarkMode = interactor.isDarkMode
+    val isEnabled = interactor.isEnabled
+
+    private val _overridingIsDarkMode = MutableStateFlow<Boolean?>(null)
+    val overridingIsDarkMode = _overridingIsDarkMode.asStateFlow()
+    val previewingIsDarkMode =
+        combine(overridingIsDarkMode, isDarkMode, isEnabled) { override, current, isEnabled ->
+            if (isEnabled) {
+                override ?: current
+            } else current
+        }
+
+    val toggleDarkMode =
+        combine(overridingIsDarkMode, isDarkMode) { override, current ->
+            // Only set override if its value is different from current, else set to null
+            { _overridingIsDarkMode.value = if (override == null) !current else null }
+        }
+
+    val onApply: Flow<(suspend () -> Unit)?> =
+        combine(overridingIsDarkMode, isDarkMode, isEnabled) { override, current, isEnabled ->
+            if (override != null && override != current && isEnabled) {
+                {
+                    interactor.setDarkModeActivated(override)
+                    logger.logDarkThemeApplied(override)
+                }
+            } else null
+        }
+
+    fun resetPreview() {
+        _overridingIsDarkMode.value = null
+    }
+}
diff --git a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
index e1f8df2..32b28ad 100644
--- a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
+++ b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
@@ -39,6 +39,7 @@
 import com.android.customization.picker.clock.ui.view.ClockViewFactory
 import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
 import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.grid.domain.interactor.GridInteractor
 import com.android.themepicker.R
 import com.android.wallpaper.model.CustomizationSectionController
 import com.android.wallpaper.model.CustomizationSectionController.CustomizationSectionNavigationController
@@ -72,6 +73,7 @@
     private val navigationController: CustomizationSectionNavigationController,
     wallpaperInteractor: WallpaperInteractor,
     themedIconInteractor: ThemedIconInteractor,
+    gridInteractor: GridInteractor,
     colorPickerInteractor: ColorPickerInteractor,
     wallpaperManager: WallpaperManager,
     private val isTwoPaneAndSmallWidth: Boolean,
@@ -87,6 +89,7 @@
         wallpaperPreviewNavigator,
         wallpaperInteractor,
         themedIconInteractor,
+        gridInteractor,
         colorPickerInteractor,
         wallpaperManager,
         isTwoPaneAndSmallWidth,
@@ -94,11 +97,7 @@
     ) {
 
     private val viewModel =
-        ViewModelProvider(
-                activity,
-                clockCarouselViewModelFactory,
-            )
-            .get() as ClockCarouselViewModel
+        ViewModelProvider(activity, clockCarouselViewModelFactory).get() as ClockCarouselViewModel
 
     private var clockColorAndSizeButton: View? = null
 
@@ -181,7 +180,7 @@
                                 )
                                 if (onAttachStateChangeListener != null) {
                                     carouselView.carousel.removeOnAttachStateChangeListener(
-                                        onAttachStateChangeListener,
+                                        onAttachStateChangeListener
                                     )
                                 }
                             }
diff --git a/src/com/android/customization/picker/preview/ui/section/PreviewWithThemeSectionController.kt b/src/com/android/customization/picker/preview/ui/section/PreviewWithThemeSectionController.kt
index 78e3745..cd3e702 100644
--- a/src/com/android/customization/picker/preview/ui/section/PreviewWithThemeSectionController.kt
+++ b/src/com/android/customization/picker/preview/ui/section/PreviewWithThemeSectionController.kt
@@ -23,6 +23,7 @@
 import androidx.lifecycle.LifecycleOwner
 import com.android.customization.model.themedicon.domain.interactor.ThemedIconInteractor
 import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.grid.domain.interactor.GridInteractor
 import com.android.customization.picker.preview.ui.viewmodel.PreviewWithThemeViewModel
 import com.android.wallpaper.R
 import com.android.wallpaper.model.Screen
@@ -52,6 +53,7 @@
     wallpaperPreviewNavigator: WallpaperPreviewNavigator,
     private val wallpaperInteractor: WallpaperInteractor,
     private val themedIconInteractor: ThemedIconInteractor,
+    private val gridInteractor: GridInteractor,
     private val colorPickerInteractor: ColorPickerInteractor,
     wallpaperManager: WallpaperManager,
     isTwoPaneAndSmallWidth: Boolean,
@@ -121,6 +123,7 @@
             initialExtrasProvider = { getInitialExtras(isOnLockScreen) },
             wallpaperInteractor = wallpaperInteractor,
             themedIconInteractor = themedIconInteractor,
+            gridInteractor = gridInteractor,
             colorPickerInteractor = colorPickerInteractor,
             screen = screen,
         )
diff --git a/src/com/android/customization/picker/preview/ui/viewmodel/PreviewWithThemeViewModel.kt b/src/com/android/customization/picker/preview/ui/viewmodel/PreviewWithThemeViewModel.kt
index 7877f11..331ec2e 100644
--- a/src/com/android/customization/picker/preview/ui/viewmodel/PreviewWithThemeViewModel.kt
+++ b/src/com/android/customization/picker/preview/ui/viewmodel/PreviewWithThemeViewModel.kt
@@ -21,6 +21,7 @@
 import android.os.Bundle
 import com.android.customization.model.themedicon.domain.interactor.ThemedIconInteractor
 import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.grid.domain.interactor.GridInteractor
 import com.android.wallpaper.model.Screen
 import com.android.wallpaper.model.WallpaperInfo
 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor
@@ -28,6 +29,8 @@
 import com.android.wallpaper.util.PreviewUtils
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
 
 /** A ThemePicker version of the [ScreenPreviewViewModel] */
 class PreviewWithThemeViewModel(
@@ -36,7 +39,8 @@
     wallpaperInfoProvider: suspend (forceReload: Boolean) -> WallpaperInfo?,
     onWallpaperColorChanged: (WallpaperColors?) -> Unit = {},
     wallpaperInteractor: WallpaperInteractor,
-    private val themedIconInteractor: ThemedIconInteractor? = null,
+    private val themedIconInteractor: ThemedIconInteractor,
+    private val gridInteractor: GridInteractor,
     colorPickerInteractor: ColorPickerInteractor? = null,
     screen: Screen,
 ) :
@@ -48,7 +52,11 @@
         wallpaperInteractor,
         screen,
     ) {
-    override fun workspaceUpdateEvents(): Flow<Boolean>? = themedIconInteractor?.isActivated
+    override fun workspaceUpdateEvents(): Flow<Unit> =
+        merge(
+            themedIconInteractor.isActivated.map {},
+            gridInteractor.getSelectOptionStateFlow().map {}
+        )
 
     private val wallpaperIsLoading = super.isLoading
 
diff --git a/src/com/android/customization/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepository.kt b/src/com/android/customization/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepository.kt
index 6bfe348..ff5f828 100644
--- a/src/com/android/customization/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepository.kt
+++ b/src/com/android/customization/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepository.kt
@@ -20,7 +20,10 @@
 import com.android.customization.picker.quickaffordance.shared.model.KeyguardQuickAffordancePickerAffordanceModel as AffordanceModel
 import com.android.customization.picker.quickaffordance.shared.model.KeyguardQuickAffordancePickerSelectionModel as SelectionModel
 import com.android.customization.picker.quickaffordance.shared.model.KeyguardQuickAffordancePickerSlotModel as SlotModel
-import com.android.systemui.shared.customization.data.content.CustomizationProviderClient as Client
+import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
+import com.android.wallpaper.picker.di.modules.MainDispatcher
+import javax.inject.Inject
+import javax.inject.Singleton
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
@@ -31,10 +34,10 @@
  * Abstracts access to application state related to functionality for selecting, picking, or setting
  * lock screen quick affordances.
  */
-class KeyguardQuickAffordancePickerRepository(
-    private val client: Client,
-    private val scope: CoroutineScope
-) {
+@Singleton
+class KeyguardQuickAffordancePickerRepository
+@Inject
+constructor(client: CustomizationProviderClient, @MainDispatcher mainScope: CoroutineScope) {
     /** List of slots available on the device. */
     val slots: Flow<List<SlotModel>> =
         client.observeSlots().map { slots -> slots.map { slot -> slot.toModel() } }
@@ -44,23 +47,23 @@
         client
             .observeAffordances()
             .map { affordances -> affordances.map { affordance -> affordance.toModel() } }
-            .shareIn(scope, replay = 1, started = SharingStarted.Lazily)
+            .shareIn(mainScope, replay = 1, started = SharingStarted.Lazily)
 
     /** List of slot-affordance pairs, modeling what the user has currently chosen for each slot. */
     val selections: Flow<List<SelectionModel>> =
         client
             .observeSelections()
             .map { selections -> selections.map { selection -> selection.toModel() } }
-            .shareIn(scope, replay = 1, started = SharingStarted.Lazily)
+            .shareIn(mainScope, replay = 1, started = SharingStarted.Lazily)
 
-    private fun Client.Slot.toModel(): SlotModel {
+    private fun CustomizationProviderClient.Slot.toModel(): SlotModel {
         return SlotModel(
             id = id,
             maxSelectedQuickAffordances = capacity,
         )
     }
 
-    private fun Client.Affordance.toModel(): AffordanceModel {
+    private fun CustomizationProviderClient.Affordance.toModel(): AffordanceModel {
         return AffordanceModel(
             id = id,
             name = name,
@@ -73,7 +76,7 @@
         )
     }
 
-    private fun Client.Selection.toModel(): SelectionModel {
+    private fun CustomizationProviderClient.Selection.toModel(): SelectionModel {
         return SelectionModel(
             slotId = slotId,
             affordanceId = affordanceId,
diff --git a/src/com/android/customization/picker/quickaffordance/domain/interactor/KeyguardQuickAffordancePickerInteractor.kt b/src/com/android/customization/picker/quickaffordance/domain/interactor/KeyguardQuickAffordancePickerInteractor.kt
index 3eca624..b17b939 100644
--- a/src/com/android/customization/picker/quickaffordance/domain/interactor/KeyguardQuickAffordancePickerInteractor.kt
+++ b/src/com/android/customization/picker/quickaffordance/domain/interactor/KeyguardQuickAffordancePickerInteractor.kt
@@ -23,18 +23,22 @@
 import com.android.customization.picker.quickaffordance.shared.model.KeyguardQuickAffordancePickerAffordanceModel as AffordanceModel
 import com.android.customization.picker.quickaffordance.shared.model.KeyguardQuickAffordancePickerSelectionModel as SelectionModel
 import com.android.customization.picker.quickaffordance.shared.model.KeyguardQuickAffordancePickerSlotModel as SlotModel
-import com.android.systemui.shared.customization.data.content.CustomizationProviderClient as Client
-import javax.inject.Provider
+import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
+import javax.inject.Inject
+import javax.inject.Singleton
 import kotlinx.coroutines.flow.Flow
 
 /**
  * Single entry-point for all application state and business logic related to quick affordances on
  * the lock screen.
  */
-class KeyguardQuickAffordancePickerInteractor(
-    private val repository: KeyguardQuickAffordancePickerRepository,
-    private val client: Client,
-    private val snapshotRestorer: Provider<KeyguardQuickAffordanceSnapshotRestorer>,
+@Singleton
+class KeyguardQuickAffordancePickerInteractor
+@Inject
+constructor(
+    repository: KeyguardQuickAffordancePickerRepository,
+    private val client: CustomizationProviderClient,
+    private val snapshotRestorer: KeyguardQuickAffordanceSnapshotRestorer,
 ) {
     /** List of slots available on the device. */
     val slots: Flow<List<SlotModel>> = repository.slots
@@ -60,7 +64,7 @@
             affordanceId = affordanceId,
         )
 
-        snapshotRestorer.get().storeSnapshot()
+        snapshotRestorer.storeSnapshot()
     }
 
     /** Unselects all affordances from the slot with the given ID. */
@@ -69,7 +73,7 @@
             slotId = slotId,
         )
 
-        snapshotRestorer.get().storeSnapshot()
+        snapshotRestorer.storeSnapshot()
     }
 
     /** Unselects all affordances from all slots. */
diff --git a/src/com/android/customization/picker/quickaffordance/domain/interactor/KeyguardQuickAffordanceSnapshotRestorer.kt b/src/com/android/customization/picker/quickaffordance/domain/interactor/KeyguardQuickAffordanceSnapshotRestorer.kt
index fee0cb5..f467989 100644
--- a/src/com/android/customization/picker/quickaffordance/domain/interactor/KeyguardQuickAffordanceSnapshotRestorer.kt
+++ b/src/com/android/customization/picker/quickaffordance/domain/interactor/KeyguardQuickAffordanceSnapshotRestorer.kt
@@ -21,10 +21,14 @@
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore
 import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot
+import javax.inject.Inject
+import javax.inject.Singleton
 
 /** Handles state restoration for the quick affordances system. */
-class KeyguardQuickAffordanceSnapshotRestorer(
-    private val interactor: KeyguardQuickAffordancePickerInteractor,
+@Singleton
+class KeyguardQuickAffordanceSnapshotRestorer
+@Inject
+constructor(
     private val client: CustomizationProviderClient,
 ) : SnapshotRestorer {
 
@@ -43,7 +47,7 @@
 
     override suspend fun restoreToSnapshot(snapshot: RestorableSnapshot) {
         // reset all current selections
-        interactor.unselectAll()
+        client.querySlots().forEach { client.deleteAllSelections(it.id) }
 
         val allSelections = checkNotNull(snapshot.args[KEY_SELECTIONS])
         if (allSelections.isEmpty()) return
@@ -55,9 +59,9 @@
             }
 
         selections.forEach { (slotId, affordanceId) ->
-            interactor.select(
-                slotId,
-                affordanceId,
+            client.insertSelection(
+                slotId = slotId,
+                affordanceId = affordanceId,
             )
         }
     }
diff --git a/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt b/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
index 3b583f3..9f3458c 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
@@ -31,7 +31,6 @@
 import androidx.lifecycle.repeatOnLifecycle
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
-import com.android.customization.picker.common.ui.view.ItemSpacing
 import com.android.customization.picker.quickaffordance.ui.adapter.SlotTabAdapter
 import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordancePickerViewModel
 import com.android.themepicker.R
@@ -39,6 +38,7 @@
 import com.android.wallpaper.picker.common.dialog.ui.viewmodel.DialogViewModel
 import com.android.wallpaper.picker.common.icon.ui.viewbinder.IconViewBinder
 import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
+import com.android.wallpaper.picker.common.ui.view.ItemSpacing
 import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.collectIndexed
diff --git a/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt b/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt
index 8b1c44a..f9925b4 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt
@@ -21,8 +21,12 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.view.ViewGroup.MarginLayoutParams
 import androidx.core.content.ContextCompat
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.isVisible
+import androidx.core.view.updateLayoutParams
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.get
 import androidx.transition.Transition
@@ -38,6 +42,7 @@
 class KeyguardQuickAffordancePickerFragment : AppbarFragment() {
     companion object {
         const val DESTINATION_ID = "quick_affordances"
+
         @JvmStatic
         fun newInstance(): KeyguardQuickAffordancePickerFragment {
             return KeyguardQuickAffordancePickerFragment()
@@ -55,7 +60,16 @@
                 container,
                 false,
             )
+        ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets ->
+            val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+            v.updateLayoutParams<MarginLayoutParams> {
+                topMargin = insets.top
+                bottomMargin = insets.bottom
+            }
+            WindowInsetsCompat.CONSUMED
+        }
         setUpToolbar(view)
+
         val injector = InjectorProvider.getInjector() as ThemePickerInjector
         val viewModel: KeyguardQuickAffordancePickerViewModel =
             ViewModelProvider(
diff --git a/src/com/android/customization/picker/settings/data/repository/ColorContrastSectionRepository.kt b/src/com/android/customization/picker/settings/data/repository/ColorContrastSectionRepository.kt
index 85cf307..6d5b0bc 100644
--- a/src/com/android/customization/picker/settings/data/repository/ColorContrastSectionRepository.kt
+++ b/src/com/android/customization/picker/settings/data/repository/ColorContrastSectionRepository.kt
@@ -17,6 +17,7 @@
 package com.android.customization.picker.settings.data.repository
 
 import android.app.UiModeManager
+import android.app.UiModeManager.ContrastUtils
 import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
 import com.android.wallpaper.system.UiModeManagerWrapper
 import java.util.concurrent.Executor
@@ -35,16 +36,18 @@
     uiModeManager: UiModeManagerWrapper,
     @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
 ) {
-    var contrast: Flow<Float> = callbackFlow {
+    var contrast: Flow<Int> = callbackFlow {
         val executor: Executor = bgDispatcher.asExecutor()
         val listener =
             UiModeManager.ContrastChangeListener { contrast ->
                 // Emit the new contrast value whenever it changes
-                trySend(contrast)
+                trySend(ContrastUtils.toContrastLevel(contrast))
             }
 
         // Emit the current contrast value immediately
-        uiModeManager.getContrast()?.let { currentContrast -> trySend(currentContrast) }
+        uiModeManager.getContrast()?.let { currentContrast ->
+            trySend(ContrastUtils.toContrastLevel(currentContrast))
+        }
 
         uiModeManager.addContrastChangeListener(executor, listener)
 
diff --git a/src/com/android/customization/picker/settings/domain/interactor/ColorContrastSectionInteractor.kt b/src/com/android/customization/picker/settings/domain/interactor/ColorContrastSectionInteractor.kt
index 003d4d0..c4ccfb3 100644
--- a/src/com/android/customization/picker/settings/domain/interactor/ColorContrastSectionInteractor.kt
+++ b/src/com/android/customization/picker/settings/domain/interactor/ColorContrastSectionInteractor.kt
@@ -25,5 +25,5 @@
 class ColorContrastSectionInteractor
 @Inject
 constructor(colorContrastSectionRepository: ColorContrastSectionRepository) {
-    val contrast: Flow<Float> = colorContrastSectionRepository.contrast
+    val contrast: Flow<Int> = colorContrastSectionRepository.contrast
 }
diff --git a/src/com/android/customization/picker/settings/ui/viewmodel/ColorContrastSectionViewModel.kt b/src/com/android/customization/picker/settings/ui/viewmodel/ColorContrastSectionViewModel.kt
index ecbe9d1..3ea63cb 100644
--- a/src/com/android/customization/picker/settings/ui/viewmodel/ColorContrastSectionViewModel.kt
+++ b/src/com/android/customization/picker/settings/ui/viewmodel/ColorContrastSectionViewModel.kt
@@ -16,6 +16,10 @@
 
 package com.android.customization.picker.settings.ui.viewmodel
 
+import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_HIGH
+import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_MEDIUM
+import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_STANDARD
+import android.util.Log
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import com.android.customization.picker.settings.domain.interactor.ColorContrastSectionInteractor
@@ -28,62 +32,54 @@
 import kotlinx.coroutines.flow.map
 
 class ColorContrastSectionViewModel
-private constructor(
-    colorContrastSectionInteractor: ColorContrastSectionInteractor,
-) : ViewModel() {
+private constructor(colorContrastSectionInteractor: ColorContrastSectionInteractor) : ViewModel() {
 
     val summary: Flow<ColorContrastSectionDataViewModel> =
         colorContrastSectionInteractor.contrast.map { contrastValue ->
             when (contrastValue) {
-                ContrastValue.STANDARD.value ->
+                CONTRAST_LEVEL_STANDARD ->
                     ColorContrastSectionDataViewModel(
                         Text.Resource(R.string.color_contrast_default_title),
                         Icon.Resource(
                             res = R.drawable.ic_contrast_standard,
                             contentDescription = null,
-                        )
+                        ),
                     )
-                ContrastValue.MEDIUM.value ->
+                CONTRAST_LEVEL_MEDIUM ->
                     ColorContrastSectionDataViewModel(
                         Text.Resource(R.string.color_contrast_medium_title),
                         Icon.Resource(
                             res = R.drawable.ic_contrast_medium,
                             contentDescription = null,
-                        )
+                        ),
                     )
-                ContrastValue.HIGH.value ->
+                CONTRAST_LEVEL_HIGH ->
                     ColorContrastSectionDataViewModel(
                         Text.Resource(R.string.color_contrast_high_title),
-                        Icon.Resource(
-                            res = R.drawable.ic_contrast_high,
-                            contentDescription = null,
-                        )
+                        Icon.Resource(res = R.drawable.ic_contrast_high, contentDescription = null),
                     )
                 else -> {
-                    println("Invalid contrast value: $contrastValue")
-                    throw IllegalArgumentException("Invalid contrast value")
+                    Log.e(TAG, "Invalid contrast value: $contrastValue")
+                    throw IllegalArgumentException("Invalid contrast value: $contrastValue")
                 }
             }
         }
 
-    enum class ContrastValue(val value: Float) {
-        STANDARD(0f),
-        MEDIUM(0.5f),
-        HIGH(1f)
-    }
-
     @Singleton
     class Factory
     @Inject
-    constructor(
-        private val colorContrastSectionInteractor: ColorContrastSectionInteractor,
-    ) : ViewModelProvider.Factory {
+    constructor(private val colorContrastSectionInteractor: ColorContrastSectionInteractor) :
+        ViewModelProvider.Factory {
         override fun <T : ViewModel> create(modelClass: Class<T>): T {
             @Suppress("UNCHECKED_CAST")
             return ColorContrastSectionViewModel(
-                colorContrastSectionInteractor = colorContrastSectionInteractor,
+                colorContrastSectionInteractor = colorContrastSectionInteractor
             )
                 as T
         }
     }
+
+    companion object {
+        private const val TAG = "ColorContrastSectionViewModel"
+    }
 }
diff --git a/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt
new file mode 100644
index 0000000..5f982e2
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/binder/ClockFloatingSheetBinder.kt
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.binder
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.content.res.Configuration
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver.OnGlobalLayoutListener
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.SeekBar
+import android.widget.Switch
+import android.widget.TextView
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder
+import com.android.customization.picker.color.ui.view.ColorOptionIconView
+import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
+import com.android.customization.picker.common.ui.view.SingleRowListItemSpacing
+import com.android.systemui.plugins.clocks.AxisType
+import com.android.systemui.plugins.clocks.ClockFontAxis
+import com.android.systemui.plugins.clocks.ClockId
+import com.android.themepicker.R
+import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption.CLOCK
+import com.android.wallpaper.customization.ui.viewmodel.ClockFloatingSheetHeightsViewModel
+import com.android.wallpaper.customization.ui.viewmodel.ClockPickerViewModel
+import com.android.wallpaper.customization.ui.viewmodel.ClockPickerViewModel.ClockStyleModel
+import com.android.wallpaper.customization.ui.viewmodel.ClockPickerViewModel.Tab
+import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
+import com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
+import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter
+import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
+import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter
+import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter2
+import java.lang.ref.WeakReference
+import kotlin.math.abs
+import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.launch
+
+object ClockFloatingSheetBinder {
+    private const val SLIDER_ENABLED_ALPHA = 1f
+    private const val SLIDER_DISABLED_ALPHA = .3f
+    private const val ANIMATION_DURATION = 200L
+
+    private val _clockFloatingSheetHeights: MutableStateFlow<ClockFloatingSheetHeightsViewModel?> =
+        MutableStateFlow(null)
+    private val clockFloatingSheetHeights: Flow<ClockFloatingSheetHeightsViewModel> =
+        _clockFloatingSheetHeights.asStateFlow().filterNotNull()
+
+    fun bind(
+        view: View,
+        optionsViewModel: ThemePickerCustomizationOptionsViewModel,
+        colorUpdateViewModel: ColorUpdateViewModel,
+        lifecycleOwner: LifecycleOwner,
+    ) {
+        val viewModel = optionsViewModel.clockPickerViewModel
+
+        val appContext = view.context.applicationContext
+
+        val tabs = view.requireViewById<FloatingToolbar>(R.id.floating_toolbar)
+        val tabAdapter =
+            FloatingToolbarTabAdapter(
+                    colorUpdateViewModel = WeakReference(colorUpdateViewModel),
+                    shouldAnimateColor = { optionsViewModel.selectedOption.value == CLOCK },
+                )
+                .also { tabs.setAdapter(it) }
+
+        val floatingSheetContainer =
+            view.requireViewById<FrameLayout>(R.id.clock_floating_sheet_content_container)
+
+        // Clock style
+        val clockStyleContent = view.requireViewById<View>(R.id.clock_floating_sheet_style_content)
+        val clockStyleAdapter = createClockStyleOptionItemAdapter(lifecycleOwner)
+        val clockStyleList =
+            view.requireViewById<RecyclerView>(R.id.clock_style_list).apply {
+                initStyleList(appContext, clockStyleAdapter)
+            }
+
+        // Clock font editor
+        val clockFontContent =
+            view.requireViewById<ViewGroup>(R.id.clock_floating_sheet_font_content)
+        val clockFontToolbar = view.requireViewById<ViewGroup>(R.id.clock_font_toolbar)
+        clockFontToolbar.requireViewById<View>(R.id.clock_font_revert).setOnClickListener {
+            viewModel.cancelFontAxes()
+        }
+        clockFontToolbar.requireViewById<View>(R.id.clock_font_apply).setOnClickListener {
+            viewModel.confirmFontAxes()
+        }
+
+        // Clock color
+        val clockColorContent = view.requireViewById<View>(R.id.clock_floating_sheet_color_content)
+        val clockColorAdapter =
+            createClockColorOptionItemAdapter(view.resources.configuration.uiMode, lifecycleOwner)
+        val clockColorList =
+            view.requireViewById<RecyclerView>(R.id.clock_color_list).apply {
+                initColorList(appContext, clockColorAdapter)
+            }
+        val clockColorSlider: SeekBar = view.requireViewById(R.id.clock_color_slider)
+        clockColorSlider.setOnSeekBarChangeListener(
+            object : SeekBar.OnSeekBarChangeListener {
+                override fun onProgressChanged(p0: SeekBar?, progress: Int, fromUser: Boolean) {
+                    if (fromUser) {
+                        viewModel.onSliderProgressChanged(progress)
+                    }
+                }
+
+                override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit
+
+                override fun onStopTrackingTouch(seekBar: SeekBar?) = Unit
+            }
+        )
+
+        // Clock size switch
+        val clockSizeSwitch = view.requireViewById<Switch>(R.id.clock_style_clock_size_switch)
+
+        clockStyleContent.viewTreeObserver.addOnGlobalLayoutListener(
+            object : OnGlobalLayoutListener {
+                override fun onGlobalLayout() {
+                    if (clockStyleContent.height != 0) {
+                        _clockFloatingSheetHeights.value =
+                            _clockFloatingSheetHeights.value?.copy(
+                                clockStyleContentHeight = clockStyleContent.height
+                            )
+                                ?: ClockFloatingSheetHeightsViewModel(
+                                    clockStyleContentHeight = clockStyleContent.height
+                                )
+                        clockStyleContent.viewTreeObserver.removeOnGlobalLayoutListener(this)
+                    }
+                }
+            }
+        )
+
+        clockColorContent.viewTreeObserver.addOnGlobalLayoutListener(
+            object : OnGlobalLayoutListener {
+                override fun onGlobalLayout() {
+                    if (clockColorContent.height != 0) {
+                        _clockFloatingSheetHeights.value =
+                            _clockFloatingSheetHeights.value?.copy(
+                                clockColorContentHeight = clockColorContent.height
+                            )
+                                ?: ClockFloatingSheetHeightsViewModel(
+                                    clockColorContentHeight = clockColorContent.height
+                                )
+                        clockColorContent.viewTreeObserver.removeOnGlobalLayoutListener(this)
+                    }
+                }
+            }
+        )
+
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch { viewModel.tabs.collect { tabAdapter.submitList(it) } }
+
+                launch {
+                    combine(clockFloatingSheetHeights, viewModel.selectedTab, ::Pair).collect {
+                        (heights, selectedTab) ->
+                        val (clockStyleContentHeight, clockColorContentHeight) = heights
+                        clockStyleContentHeight ?: return@collect
+                        clockColorContentHeight ?: return@collect
+
+                        if (selectedTab == Tab.STYLE || selectedTab == Tab.COLOR) {
+                            val targetHeight =
+                                when (selectedTab) {
+                                    Tab.STYLE -> clockStyleContentHeight
+                                    Tab.COLOR -> clockColorContentHeight
+                                    else -> 0
+                                } +
+                                    view.resources.getDimensionPixelSize(
+                                        R.dimen.floating_sheet_content_vertical_padding
+                                    ) * 2
+
+                            ValueAnimator.ofInt(floatingSheetContainer.height, targetHeight)
+                                .apply {
+                                    addUpdateListener { valueAnimator ->
+                                        val value = valueAnimator.animatedValue as Int
+                                        floatingSheetContainer.layoutParams =
+                                            floatingSheetContainer.layoutParams.apply {
+                                                height = value
+                                            }
+                                    }
+                                    duration = ANIMATION_DURATION
+                                }
+                                .start()
+                        } else if (selectedTab == Tab.FONT) {
+                            floatingSheetContainer.layoutParams =
+                                LinearLayout.LayoutParams(
+                                    LinearLayout.LayoutParams.MATCH_PARENT,
+                                    LinearLayout.LayoutParams.WRAP_CONTENT,
+                                )
+                        }
+
+                        clockStyleContent.isVisible = selectedTab == Tab.STYLE
+                        clockColorContent.isVisible = selectedTab == Tab.COLOR
+                        clockFontContent.isVisible = selectedTab == Tab.FONT
+
+                        tabs.isVisible = selectedTab != Tab.FONT
+                        clockFontToolbar.isVisible = selectedTab == Tab.FONT
+                    }
+                }
+
+                launch {
+                    var boundClockId: ClockId? = null
+                    var boundEditorViews = mapOf<String, Pair<View, ClockFontAxis>>()
+                    combine(viewModel.previewingClock, viewModel.previewingFontAxisMap, ::Pair)
+                        .collect { pair ->
+                            val (clock, fontAxisMap) = pair
+
+                            if (boundClockId != clock.clockId) {
+                                boundEditorViews =
+                                    initClockFontEditor(clockFontContent, clock.fontAxes, viewModel)
+                                boundClockId = clock.clockId
+                            }
+
+                            for ((key, value) in fontAxisMap) {
+                                boundEditorViews[key]?.let { pair ->
+                                    val (view, axis) = pair
+                                    view.findViewById<Switch>(R.id.clock_axis_switch)?.apply {
+                                        isChecked = abs(value - axis.maxValue) < 0.01f
+                                    }
+                                    view.findViewById<SeekBar>(R.id.clock_axis_slider)?.apply {
+                                        setProgress(value.toInt(), false)
+                                    }
+                                }
+                            }
+                        }
+                }
+
+                launch {
+                    viewModel.clockStyleOptions.collect { styleOptions ->
+                        clockStyleAdapter.setItems(styleOptions) {
+                            var indexToFocus = styleOptions.indexOfFirst { it.isSelected.value }
+                            indexToFocus = if (indexToFocus < 0) 0 else indexToFocus
+                            (clockStyleList.layoutManager as LinearLayoutManager)
+                                .scrollToPositionWithOffset(indexToFocus, 0)
+                        }
+                    }
+                }
+
+                launch {
+                    viewModel.clockColorOptions.collect { colorOptions ->
+                        clockColorAdapter.setItems(colorOptions) {
+                            var indexToFocus = colorOptions.indexOfFirst { it.isSelected.value }
+                            indexToFocus = if (indexToFocus < 0) 0 else indexToFocus
+                            (clockColorList.layoutManager as LinearLayoutManager)
+                                .scrollToPositionWithOffset(indexToFocus, 0)
+                        }
+                    }
+                }
+
+                launch {
+                    viewModel.previewingSliderProgress.collect { progress ->
+                        clockColorSlider.setProgress(progress, true)
+                    }
+                }
+
+                launch {
+                    viewModel.isSliderEnabled.collect { isEnabled ->
+                        clockColorSlider.isEnabled = isEnabled
+                        clockColorSlider.alpha =
+                            if (isEnabled) SLIDER_ENABLED_ALPHA else SLIDER_DISABLED_ALPHA
+                    }
+                }
+
+                launch {
+                    viewModel.previewingClockSize.collect { size ->
+                        when (size) {
+                            ClockSize.DYNAMIC -> clockSizeSwitch.isChecked = true
+                            ClockSize.SMALL -> clockSizeSwitch.isChecked = false
+                        }
+                    }
+                }
+
+                launch {
+                    viewModel.onClockSizeSwitchCheckedChange.collect { onCheckedChange ->
+                        clockSizeSwitch.setOnCheckedChangeListener { _, _ ->
+                            onCheckedChange.invoke()
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private fun initClockFontEditor(
+        parent: ViewGroup,
+        fontAxes: List<ClockFontAxis>,
+        viewModel: ClockPickerViewModel,
+    ): Map<String, Pair<View, ClockFontAxis>> {
+        parent.removeAllViews()
+
+        val inflater = LayoutInflater.from(parent.context)
+        val axisMap = mutableMapOf<String, Pair<View, ClockFontAxis>>()
+        var nextSwitch: View? = null
+        for (axis in fontAxes) {
+            val view =
+                when (axis.type) {
+                    AxisType.Float -> {
+                        val id = R.layout.clock_font_axis_slider_row
+                        val row = inflater.inflate(id, parent, false)
+                        parent.addView(row)
+                        row
+                    }
+                    AxisType.Boolean ->
+                        nextSwitch?.also { nextSwitch = null }
+                            ?: run {
+                                val id = R.layout.clock_font_axis_switch_row
+                                val row = inflater.inflate(id, parent, false)
+                                parent.addView(row)
+
+                                nextSwitch = row.requireViewById(R.id.clock_switch_two)
+                                row.requireViewById(R.id.clock_switch_one)
+                            }
+                }
+
+            view.visibility = View.VISIBLE
+            axisMap[axis.key] = Pair(view, axis)
+            view.contentDescription = axis.description
+            view.requireViewById<TextView>(R.id.clock_axis_name).text = axis.name
+
+            view.findViewById<Switch>(R.id.clock_axis_switch)?.apply {
+                isChecked = abs(axis.currentValue - axis.maxValue) < 0.01f
+                setOnCheckedChangeListener { v, _ ->
+                    val value = if (v.isChecked) axis.maxValue else axis.minValue
+                    viewModel.updatePreviewFontAxis(axis.key, value)
+                }
+            }
+
+            view.findViewById<SeekBar>(R.id.clock_axis_slider)?.apply {
+                setMax(axis.maxValue.toInt())
+                setMin(axis.minValue.toInt())
+                setProgress(axis.currentValue.toInt(), false)
+
+                setOnSeekBarChangeListener(
+                    object : SeekBar.OnSeekBarChangeListener {
+                        override fun onProgressChanged(
+                            seekBar: SeekBar?,
+                            progress: Int,
+                            fromUser: Boolean,
+                        ) {
+                            if (fromUser) {
+                                viewModel.updatePreviewFontAxis(axis.key, progress.toFloat())
+                            }
+                        }
+
+                        override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+
+                        override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+                    }
+                )
+            }
+        }
+
+        return axisMap
+    }
+
+    private fun createClockStyleOptionItemAdapter(
+        lifecycleOwner: LifecycleOwner
+    ): OptionItemAdapter2<ClockStyleModel> =
+        OptionItemAdapter2(
+            layoutResourceId = R.layout.clock_style_option2,
+            lifecycleOwner = lifecycleOwner,
+            bindPayload = { view: View, styleModel: ClockStyleModel ->
+                view
+                    .findViewById<ImageView>(R.id.foreground)
+                    ?.setImageDrawable(styleModel.thumbnail)
+                val job =
+                    lifecycleOwner.lifecycleScope.launch {
+                        lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                            styleModel.showEditButton.collect {
+                                view.findViewById<ImageView>(R.id.edit_icon)?.isVisible = it
+                            }
+                        }
+                    }
+                return@OptionItemAdapter2 DisposableHandle { job.cancel() }
+            },
+        )
+
+    private fun RecyclerView.initStyleList(
+        context: Context,
+        adapter: OptionItemAdapter2<ClockStyleModel>,
+    ) {
+        this.adapter = adapter
+        layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+        addItemDecoration(
+            SingleRowListItemSpacing(
+                context.resources.getDimensionPixelSize(
+                    R.dimen.floating_sheet_content_horizontal_padding
+                ),
+                context.resources.getDimensionPixelSize(
+                    R.dimen.floating_sheet_list_item_horizontal_space
+                ),
+            )
+        )
+    }
+
+    private fun createClockColorOptionItemAdapter(
+        uiMode: Int,
+        lifecycleOwner: LifecycleOwner,
+    ): OptionItemAdapter<ColorOptionIconViewModel> =
+        OptionItemAdapter(
+            layoutResourceId = R.layout.color_option,
+            lifecycleOwner = lifecycleOwner,
+            bindIcon = { foregroundView: View, colorIcon: ColorOptionIconViewModel ->
+                val colorOptionIconView = foregroundView as? ColorOptionIconView
+                val night =
+                    uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
+                colorOptionIconView?.let { ColorOptionIconBinder.bind(it, colorIcon, night) }
+            },
+        )
+
+    private fun RecyclerView.initColorList(
+        context: Context,
+        adapter: OptionItemAdapter<ColorOptionIconViewModel>,
+    ) {
+        apply {
+            this.adapter = adapter
+            layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+            addItemDecoration(
+                SingleRowListItemSpacing(
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.floating_sheet_content_horizontal_padding
+                    ),
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.floating_sheet_list_item_horizontal_space
+                    ),
+                )
+            )
+        }
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/binder/ColorsFloatingSheetBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ColorsFloatingSheetBinder.kt
new file mode 100644
index 0000000..7ddcb01
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/binder/ColorsFloatingSheetBinder.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.binder
+
+import android.content.Context
+import android.content.res.Configuration.UI_MODE_NIGHT_MASK
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
+import android.view.View
+import android.widget.TextView
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder2
+import com.android.customization.picker.color.ui.view.ColorOptionIconView2
+import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
+import com.android.customization.picker.common.ui.view.SingleRowListItemSpacing
+import com.android.customization.picker.mode.ui.binder.DarkModeBinder
+import com.android.themepicker.R
+import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption.COLORS
+import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
+import com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
+import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter
+import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
+import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter2
+import java.lang.ref.WeakReference
+import kotlinx.coroutines.launch
+
+object ColorsFloatingSheetBinder {
+
+    fun bind(
+        view: View,
+        optionsViewModel: ThemePickerCustomizationOptionsViewModel,
+        colorUpdateViewModel: ColorUpdateViewModel,
+        lifecycleOwner: LifecycleOwner,
+    ) {
+        val viewModel = optionsViewModel.colorPickerViewModel2
+
+        val subhead = view.requireViewById<TextView>(R.id.color_type_tab_subhead)
+
+        val colorsAdapter =
+            createOptionItemAdapter(view.resources.configuration.uiMode, lifecycleOwner)
+        val colorsList =
+            view.requireViewById<RecyclerView>(R.id.colors_horizontal_list).also {
+                it.initColorsList(view.context.applicationContext, colorsAdapter)
+            }
+
+        val tabs = view.requireViewById<FloatingToolbar>(R.id.floating_toolbar)
+        val tabAdapter =
+            FloatingToolbarTabAdapter(
+                    colorUpdateViewModel = WeakReference(colorUpdateViewModel),
+                    shouldAnimateColor = { optionsViewModel.selectedOption.value == COLORS },
+                )
+                .also { tabs.setAdapter(it) }
+
+        DarkModeBinder.bind(
+            darkModeToggle = view.findViewById(R.id.dark_mode_toggle),
+            viewModel = optionsViewModel.darkModeViewModel,
+            lifecycleOwner = lifecycleOwner,
+        )
+
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch { viewModel.colorTypeTabs.collect { tabAdapter.submitList(it) } }
+
+                launch { viewModel.colorTypeTabSubheader.collect { subhead.text = it } }
+
+                launch {
+                    viewModel.colorOptions.collect { colorOptions ->
+                        colorsAdapter.setItems(colorOptions) {
+                            var indexToFocus = colorOptions.indexOfFirst { it.isSelected.value }
+                            indexToFocus = if (indexToFocus < 0) 0 else indexToFocus
+                            (colorsList.layoutManager as LinearLayoutManager)
+                                .scrollToPositionWithOffset(indexToFocus, 0)
+                        }
+                    }
+                }
+
+                launch {
+                    viewModel.previewingColorOption.collect { colorModel ->
+                        if (colorModel != null) {
+                            colorUpdateViewModel.previewColors(
+                                colorModel.colorOption.seedColor,
+                                colorModel.colorOption.style,
+                            )
+                        } else colorUpdateViewModel.resetPreview()
+                    }
+                }
+            }
+        }
+    }
+
+    private fun createOptionItemAdapter(
+        uiMode: Int,
+        lifecycleOwner: LifecycleOwner,
+    ): OptionItemAdapter2<ColorOptionIconViewModel> =
+        OptionItemAdapter2(
+            layoutResourceId = R.layout.color_option2,
+            lifecycleOwner = lifecycleOwner,
+            bindPayload = { itemView: View, colorIcon: ColorOptionIconViewModel ->
+                val colorOptionIconView =
+                    itemView.requireViewById<ColorOptionIconView2>(
+                        com.android.wallpaper.R.id.background
+                    )
+                val night = uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
+                ColorOptionIconBinder2.bind(colorOptionIconView, colorIcon, night)
+                // Return null since it does not need the lifecycleOwner to launch any job for later
+                // disposal when rebind.
+                return@OptionItemAdapter2 null
+            },
+        )
+
+    private fun RecyclerView.initColorsList(
+        context: Context,
+        adapter: OptionItemAdapter2<ColorOptionIconViewModel>,
+    ) {
+        apply {
+            this.adapter = adapter
+            layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+            addItemDecoration(
+                SingleRowListItemSpacing(
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.floating_sheet_content_horizontal_padding
+                    ),
+                    0,
+                )
+            )
+        }
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/binder/ShapeGridFloatingSheetBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ShapeGridFloatingSheetBinder.kt
new file mode 100644
index 0000000..5f292bd
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/binder/ShapeGridFloatingSheetBinder.kt
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.binder
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver.OnGlobalLayoutListener
+import android.widget.ImageView
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.customization.picker.common.ui.view.SingleRowListItemSpacing
+import com.android.customization.picker.grid.ui.binder.GridIconViewBinder
+import com.android.customization.picker.grid.ui.viewmodel.GridIconViewModel
+import com.android.customization.picker.grid.ui.viewmodel.ShapeIconViewModel
+import com.android.themepicker.R
+import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption.APP_SHAPE_GRID
+import com.android.wallpaper.customization.ui.viewmodel.ShapeGridFloatingSheetHeightsViewModel
+import com.android.wallpaper.customization.ui.viewmodel.ShapeGridPickerViewModel.Tab.GRID
+import com.android.wallpaper.customization.ui.viewmodel.ShapeGridPickerViewModel.Tab.SHAPE
+import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
+import com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
+import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter
+import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
+import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter
+import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder
+import java.lang.ref.WeakReference
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.launch
+
+object ShapeGridFloatingSheetBinder {
+    private const val ANIMATION_DURATION = 200L
+
+    private val _shapeGridFloatingSheetHeights:
+        MutableStateFlow<ShapeGridFloatingSheetHeightsViewModel?> =
+        MutableStateFlow(null)
+    private val shapeGridFloatingSheetHeights: Flow<ShapeGridFloatingSheetHeightsViewModel> =
+        _shapeGridFloatingSheetHeights.asStateFlow().filterNotNull().filter {
+            it.shapeContentHeight != null && it.gridContentHeight != null
+        }
+
+    fun bind(
+        view: View,
+        optionsViewModel: ThemePickerCustomizationOptionsViewModel,
+        colorUpdateViewModel: ColorUpdateViewModel,
+        lifecycleOwner: LifecycleOwner,
+        backgroundDispatcher: CoroutineDispatcher,
+    ) {
+        val floatingSheetContentVerticalPadding =
+            view.resources.getDimensionPixelSize(R.dimen.floating_sheet_content_vertical_padding)
+        val viewModel = optionsViewModel.shapeGridPickerViewModel
+
+        val tabs = view.requireViewById<FloatingToolbar>(R.id.floating_toolbar)
+        val tabAdapter =
+            FloatingToolbarTabAdapter(
+                    colorUpdateViewModel = WeakReference(colorUpdateViewModel),
+                    shouldAnimateColor = { optionsViewModel.selectedOption.value == APP_SHAPE_GRID },
+                )
+                .also { tabs.setAdapter(it) }
+
+        val floatingSheetContainer =
+            view.requireViewById<ViewGroup>(R.id.shape_grid_floating_sheet_content_container)
+
+        val shapeContent = view.requireViewById<View>(R.id.app_shape_container)
+        val shapeOptionListAdapter =
+            createShapeOptionItemAdapter(view.context, lifecycleOwner, backgroundDispatcher)
+        val shapeOptionList =
+            view.requireViewById<RecyclerView>(R.id.shape_options).also {
+                it.initShapeOptionList(view.context, shapeOptionListAdapter)
+            }
+
+        val gridContent = view.requireViewById<View>(R.id.app_grid_container)
+        val gridOptionListAdapter =
+            createGridOptionItemAdapter(view.context, lifecycleOwner, backgroundDispatcher)
+        val gridOptionList =
+            view.requireViewById<RecyclerView>(R.id.grid_options).also {
+                it.initGridOptionList(view.context, gridOptionListAdapter)
+            }
+
+        // Get the shape content height when it is ready
+        shapeContent.viewTreeObserver.addOnGlobalLayoutListener(
+            object : OnGlobalLayoutListener {
+                override fun onGlobalLayout() {
+                    if (shapeContent.height != 0) {
+                        _shapeGridFloatingSheetHeights.value =
+                            _shapeGridFloatingSheetHeights.value?.copy(
+                                shapeContentHeight = shapeContent.height
+                            )
+                                ?: ShapeGridFloatingSheetHeightsViewModel(
+                                    shapeContentHeight = shapeContent.height
+                                )
+                    }
+                    shapeContent.viewTreeObserver.removeOnGlobalLayoutListener(this)
+                }
+            }
+        )
+        // Get the grid content height when it is ready
+        gridContent.viewTreeObserver.addOnGlobalLayoutListener(
+            object : OnGlobalLayoutListener {
+                override fun onGlobalLayout() {
+                    if (gridContent.height != 0) {
+                        _shapeGridFloatingSheetHeights.value =
+                            _shapeGridFloatingSheetHeights.value?.copy(
+                                gridContentHeight = gridContent.height
+                            )
+                                ?: ShapeGridFloatingSheetHeightsViewModel(
+                                    gridContentHeight = shapeContent.height
+                                )
+                    }
+                    shapeContent.viewTreeObserver.removeOnGlobalLayoutListener(this)
+                }
+            }
+        )
+
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch { viewModel.tabs.collect { tabAdapter.submitList(it) } }
+
+                launch {
+                    combine(shapeGridFloatingSheetHeights, viewModel.selectedTab) {
+                            heights,
+                            selectedTab ->
+                            heights to selectedTab
+                        }
+                        .collect { (heights, selectedTab) ->
+                            val (shapeContentHeight, gridContentHeight) = heights
+                            shapeContentHeight ?: return@collect
+                            gridContentHeight ?: return@collect
+                            // Make sure the recycler view height is the same as its parent. It's
+                            // possible that the recycler view is shorter than expected.
+                            gridOptionList.layoutParams =
+                                gridOptionList.layoutParams.apply { height = gridContentHeight }
+                            val targetHeight =
+                                when (selectedTab) {
+                                    SHAPE -> shapeContentHeight
+                                    GRID -> gridContentHeight
+                                } + floatingSheetContentVerticalPadding * 2
+
+                            ValueAnimator.ofInt(floatingSheetContainer.height, targetHeight)
+                                .apply {
+                                    addUpdateListener { valueAnimator ->
+                                        val value = valueAnimator.animatedValue as Int
+                                        floatingSheetContainer.layoutParams =
+                                            floatingSheetContainer.layoutParams.apply {
+                                                height = value
+                                            }
+                                    }
+                                    duration = ANIMATION_DURATION
+                                }
+                                .start()
+
+                            shapeContent.isVisible = selectedTab == SHAPE
+                            gridContent.isVisible = selectedTab == GRID
+                        }
+                }
+
+                launch {
+                    viewModel.gridOptions.collect { options ->
+                        gridOptionListAdapter.setItems(options) {
+                            val indexToFocus =
+                                options.indexOfFirst { it.isSelected.value }.coerceAtLeast(0)
+                            (gridOptionList.layoutManager as LinearLayoutManager).scrollToPosition(
+                                indexToFocus
+                            )
+                        }
+                    }
+                }
+
+                launch {
+                    viewModel.shapeOptions.collect { options ->
+                        shapeOptionListAdapter.setItems(options) {
+                            val indexToFocus =
+                                options.indexOfFirst { it.isSelected.value }.coerceAtLeast(0)
+                            (shapeOptionList.layoutManager as LinearLayoutManager).scrollToPosition(
+                                indexToFocus
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private fun createShapeOptionItemAdapter(
+        context: Context,
+        lifecycleOwner: LifecycleOwner,
+        backgroundDispatcher: CoroutineDispatcher,
+    ): OptionItemAdapter<ShapeIconViewModel> =
+        OptionItemAdapter(
+            layoutResourceId = R.layout.shape_option,
+            lifecycleOwner = lifecycleOwner,
+            backgroundDispatcher = backgroundDispatcher,
+            foregroundTintSpec =
+                OptionItemBinder.TintSpec(
+                    selectedColor =
+                        context.getColor(com.android.wallpaper.R.color.system_on_surface),
+                    unselectedColor =
+                        context.getColor(com.android.wallpaper.R.color.system_on_surface),
+                ),
+            bindIcon = { foregroundView: View, shapeIcon: ShapeIconViewModel ->
+                val imageView = foregroundView as? ImageView
+                imageView?.let { ShapeIconViewBinder.bind(imageView, shapeIcon) }
+            },
+        )
+
+    private fun RecyclerView.initShapeOptionList(
+        context: Context,
+        adapter: OptionItemAdapter<ShapeIconViewModel>,
+    ) {
+        apply {
+            this.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
+            addItemDecoration(
+                SingleRowListItemSpacing(
+                    edgeItemSpacePx =
+                        context.resources.getDimensionPixelSize(
+                            R.dimen.floating_sheet_content_horizontal_padding
+                        ),
+                    itemHorizontalSpacePx =
+                        context.resources.getDimensionPixelSize(
+                            com.android.themepicker.R.dimen
+                                .floating_sheet_list_item_horizontal_space
+                        ),
+                )
+            )
+            this.adapter = adapter
+        }
+    }
+
+    private fun createGridOptionItemAdapter(
+        context: Context,
+        lifecycleOwner: LifecycleOwner,
+        backgroundDispatcher: CoroutineDispatcher,
+    ): OptionItemAdapter<GridIconViewModel> =
+        OptionItemAdapter(
+            layoutResourceId = R.layout.grid_option,
+            lifecycleOwner = lifecycleOwner,
+            backgroundDispatcher = backgroundDispatcher,
+            foregroundTintSpec =
+                OptionItemBinder.TintSpec(
+                    selectedColor =
+                        context.getColor(com.android.wallpaper.R.color.system_on_surface),
+                    unselectedColor =
+                        context.getColor(com.android.wallpaper.R.color.system_on_surface),
+                ),
+            bindIcon = { foregroundView: View, gridIcon: GridIconViewModel ->
+                val imageView = foregroundView as? ImageView
+                imageView?.let { GridIconViewBinder.bind(imageView, gridIcon) }
+            },
+        )
+
+    private fun RecyclerView.initGridOptionList(
+        context: Context,
+        adapter: OptionItemAdapter<GridIconViewModel>,
+    ) {
+        apply {
+            this.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
+            addItemDecoration(
+                SingleRowListItemSpacing(
+                    edgeItemSpacePx =
+                        context.resources.getDimensionPixelSize(
+                            R.dimen.floating_sheet_content_horizontal_padding
+                        ),
+                    itemHorizontalSpacePx =
+                        context.resources.getDimensionPixelSize(
+                            com.android.themepicker.R.dimen
+                                .floating_sheet_list_item_horizontal_space
+                        ),
+                )
+            )
+            this.adapter = adapter
+        }
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/binder/ShapeIconViewBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ShapeIconViewBinder.kt
new file mode 100644
index 0000000..550038d
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/binder/ShapeIconViewBinder.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.binder
+
+import android.widget.ImageView
+import com.android.customization.picker.grid.ui.viewmodel.ShapeIconViewModel
+import com.android.wallpaper.customization.ui.view.ShapeTileDrawable
+
+object ShapeIconViewBinder {
+    fun bind(view: ImageView, shapeIcon: ShapeIconViewModel) {
+        view.setImageDrawable(ShapeTileDrawable(shapeIcon.path))
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/binder/ShortcutFloatingSheetBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ShortcutFloatingSheetBinder.kt
new file mode 100644
index 0000000..838ef87
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/binder/ShortcutFloatingSheetBinder.kt
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.binder
+
+import android.app.Dialog
+import android.content.Context
+import android.view.View
+import android.widget.ImageView
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.customization.picker.common.ui.view.DoubleRowListItemSpacing
+import com.android.themepicker.R
+import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption.SHORTCUTS
+import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
+import com.android.wallpaper.picker.common.dialog.ui.viewbinder.DialogViewBinder
+import com.android.wallpaper.picker.common.dialog.ui.viewmodel.DialogViewModel
+import com.android.wallpaper.picker.common.icon.ui.viewbinder.IconViewBinder
+import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
+import com.android.wallpaper.picker.customization.ui.view.FloatingToolbar
+import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter
+import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
+import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter2
+import java.lang.ref.WeakReference
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.collectIndexed
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.launch
+
+@OptIn(ExperimentalCoroutinesApi::class)
+object ShortcutFloatingSheetBinder {
+
+    fun bind(
+        view: View,
+        optionsViewModel: ThemePickerCustomizationOptionsViewModel,
+        colorUpdateViewModel: ColorUpdateViewModel,
+        lifecycleOwner: LifecycleOwner,
+    ) {
+        val viewModel = optionsViewModel.keyguardQuickAffordancePickerViewModel2
+
+        val quickAffordanceAdapter = createOptionItemAdapter(lifecycleOwner)
+        val quickAffordanceList =
+            view.requireViewById<RecyclerView>(R.id.quick_affordance_horizontal_list).also {
+                it.initQuickAffordanceList(view.context.applicationContext, quickAffordanceAdapter)
+            }
+
+        val tabs = view.requireViewById<FloatingToolbar>(R.id.floating_toolbar)
+        val tabAdapter =
+            FloatingToolbarTabAdapter(
+                    colorUpdateViewModel = WeakReference(colorUpdateViewModel),
+                    shouldAnimateColor = { optionsViewModel.selectedOption.value == SHORTCUTS },
+                )
+                .also { tabs.setAdapter(it) }
+
+        var dialog: Dialog? = null
+
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch { viewModel.tabs.collect { tabAdapter.submitList(it) } }
+
+                launch {
+                    viewModel.quickAffordances.collect { affordances ->
+                        quickAffordanceAdapter.setItems(affordances)
+                    }
+                }
+
+                launch {
+                    viewModel.quickAffordances
+                        .flatMapLatest { affordances ->
+                            combine(affordances.map { affordance -> affordance.isSelected }) {
+                                selectedFlags ->
+                                selectedFlags.indexOfFirst { it }
+                            }
+                        }
+                        .collectIndexed { index, selectedPosition ->
+                            // Scroll the view to show the first selected affordance.
+                            if (selectedPosition != -1) {
+                                // We use "post" because we need to give the adapter item a pass to
+                                // update the view.
+                                quickAffordanceList.post {
+                                    if (index == 0) {
+                                        // don't animate on initial collection
+                                        quickAffordanceList.scrollToPosition(selectedPosition)
+                                    } else {
+                                        quickAffordanceList.smoothScrollToPosition(selectedPosition)
+                                    }
+                                }
+                            }
+                        }
+                }
+
+                launch {
+                    viewModel.dialog.distinctUntilChanged().collect { dialogRequest ->
+                        dialog?.dismiss()
+                        dialog =
+                            if (dialogRequest != null) {
+                                showDialog(
+                                    context = view.context,
+                                    request = dialogRequest,
+                                    onDismissed = viewModel::onDialogDismissed,
+                                )
+                            } else {
+                                null
+                            }
+                    }
+                }
+
+                launch {
+                    viewModel.activityStartRequests.collect { intent ->
+                        if (intent != null) {
+                            view.context.startActivity(intent)
+                            viewModel.onActivityStarted()
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private fun showDialog(
+        context: Context,
+        request: DialogViewModel,
+        onDismissed: () -> Unit,
+    ): Dialog {
+        return DialogViewBinder.show(
+            context = context,
+            viewModel = request,
+            onDismissed = onDismissed,
+        )
+    }
+
+    private fun createOptionItemAdapter(lifecycleOwner: LifecycleOwner): OptionItemAdapter2<Icon> =
+        OptionItemAdapter2(
+            layoutResourceId = R.layout.quick_affordance_list_item2,
+            lifecycleOwner = lifecycleOwner,
+            bindPayload = { itemView: View, gridIcon: Icon ->
+                val imageView =
+                    itemView.requireViewById<ImageView>(com.android.wallpaper.R.id.foreground)
+                IconViewBinder.bind(imageView, gridIcon)
+                // Return null since it does not need the lifecycleOwner to launch any job for later
+                // disposal when rebind.
+                return@OptionItemAdapter2 null
+            },
+        )
+
+    private fun RecyclerView.initQuickAffordanceList(
+        context: Context,
+        adapter: OptionItemAdapter2<Icon>,
+    ) {
+        apply {
+            this.adapter = adapter
+            layoutManager = GridLayoutManager(context, 2, GridLayoutManager.HORIZONTAL, false)
+            addItemDecoration(
+                DoubleRowListItemSpacing(
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.floating_sheet_content_horizontal_padding
+                    ),
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.floating_sheet_list_item_horizontal_space
+                    ),
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.floating_sheet_list_item_vertical_space
+                    ),
+                )
+            )
+        }
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
index 349c7c5..6bdd6ce 100644
--- a/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
+++ b/src/com/android/wallpaper/customization/ui/binder/ThemePickerCustomizationOptionBinder.kt
@@ -16,19 +16,42 @@
 
 package com.android.wallpaper.customization.ui.binder
 
+import android.content.Context
 import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.clock.ui.view.ClockConstraintLayoutHostView
+import com.android.customization.picker.clock.ui.view.ClockConstraintLayoutHostView.Companion.addClockViews
+import com.android.customization.picker.clock.ui.view.ClockViewFactory
+import com.android.customization.picker.grid.ui.binder.GridIconViewBinder
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
+import com.android.systemui.shared.Flags
+import com.android.themepicker.R
+import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption
 import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption
 import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
+import com.android.wallpaper.model.Screen
+import com.android.wallpaper.picker.common.icon.ui.viewbinder.IconViewBinder
+import com.android.wallpaper.picker.common.text.ui.viewbinder.TextViewBinder
 import com.android.wallpaper.picker.customization.ui.binder.CustomizationOptionsBinder
 import com.android.wallpaper.picker.customization.ui.binder.DefaultCustomizationOptionsBinder
 import com.android.wallpaper.picker.customization.ui.util.CustomizationOptionUtil.CustomizationOption
-import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationOptionsViewModel
+import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
+import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationPickerViewModel2
 import javax.inject.Inject
 import javax.inject.Singleton
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.launch
 
 @Singleton
@@ -41,41 +64,251 @@
         view: View,
         lockScreenCustomizationOptionEntries: List<Pair<CustomizationOption, View>>,
         homeScreenCustomizationOptionEntries: List<Pair<CustomizationOption, View>>,
-        viewModel: CustomizationOptionsViewModel,
-        lifecycleOwner: LifecycleOwner
+        customizationOptionFloatingSheetViewMap: Map<CustomizationOption, View>?,
+        viewModel: CustomizationPickerViewModel2,
+        colorUpdateViewModel: ColorUpdateViewModel,
+        lifecycleOwner: LifecycleOwner,
+        navigateToWallpaperCategoriesScreen: (screen: Screen) -> Unit,
     ) {
         defaultCustomizationOptionsBinder.bind(
             view,
             lockScreenCustomizationOptionEntries,
             homeScreenCustomizationOptionEntries,
+            customizationOptionFloatingSheetViewMap,
             viewModel,
-            lifecycleOwner
+            colorUpdateViewModel,
+            lifecycleOwner,
+            navigateToWallpaperCategoriesScreen,
         )
 
         val optionClock =
             lockScreenCustomizationOptionEntries
                 .find { it.first == ThemePickerLockCustomizationOption.CLOCK }
                 ?.second
+
         val optionShortcut =
             lockScreenCustomizationOptionEntries
                 .find { it.first == ThemePickerLockCustomizationOption.SHORTCUTS }
                 ?.second
-        viewModel as ThemePickerCustomizationOptionsViewModel
+        val optionShortcutDescription =
+            optionShortcut?.findViewById<TextView>(
+                R.id.option_entry_keyguard_quick_affordance_description
+            )
+        val optionShortcutIcon1 =
+            optionShortcut?.findViewById<ImageView>(
+                R.id.option_entry_keyguard_quick_affordance_icon_1
+            )
+        val optionShortcutIcon2 =
+            optionShortcut?.findViewById<ImageView>(
+                R.id.option_entry_keyguard_quick_affordance_icon_2
+            )
 
+        val optionColors =
+            homeScreenCustomizationOptionEntries
+                .find { it.first == ThemePickerHomeCustomizationOption.COLORS }
+                ?.second
+
+        val optionShapeGrid =
+            homeScreenCustomizationOptionEntries
+                .find { it.first == ThemePickerHomeCustomizationOption.APP_SHAPE_GRID }
+                ?.second
+        val optionShapeGridDescription =
+            optionShapeGrid?.findViewById<TextView>(R.id.option_entry_app_shape_grid_description)
+        val optionShapeGridIcon =
+            optionShapeGrid?.findViewById<ImageView>(R.id.option_entry_app_shape_grid_icon)
+
+        val optionsViewModel =
+            viewModel.customizationOptionsViewModel as ThemePickerCustomizationOptionsViewModel
         lifecycleOwner.lifecycleScope.launch {
             lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                 launch {
-                    viewModel.onCustomizeClockClicked.collect {
+                    optionsViewModel.onCustomizeClockClicked.collect {
                         optionClock?.setOnClickListener { _ -> it?.invoke() }
                     }
                 }
 
                 launch {
-                    viewModel.onCustomizeShortcutClicked.collect {
+                    optionsViewModel.onCustomizeShortcutClicked.collect {
                         optionShortcut?.setOnClickListener { _ -> it?.invoke() }
                     }
                 }
+
+                launch {
+                    optionsViewModel.keyguardQuickAffordancePickerViewModel2.summary.collect {
+                        summary ->
+                        optionShortcutDescription?.let {
+                            TextViewBinder.bind(view = it, viewModel = summary.description)
+                        }
+                        summary.icon1?.let { icon ->
+                            optionShortcutIcon1?.let {
+                                IconViewBinder.bind(view = it, viewModel = icon)
+                            }
+                        }
+                        optionShortcutIcon1?.isVisible = summary.icon1 != null
+
+                        summary.icon2?.let { icon ->
+                            optionShortcutIcon2?.let {
+                                IconViewBinder.bind(view = it, viewModel = icon)
+                            }
+                        }
+                        optionShortcutIcon2?.isVisible = summary.icon2 != null
+                    }
+                }
+
+                launch {
+                    optionsViewModel.onCustomizeColorsClicked.collect {
+                        optionColors?.setOnClickListener { _ -> it?.invoke() }
+                    }
+                }
+
+                launch {
+                    optionsViewModel.onCustomizeShapeGridClicked.collect {
+                        optionShapeGrid?.setOnClickListener { _ -> it?.invoke() }
+                    }
+                }
+
+                launch {
+                    optionsViewModel.shapeGridPickerViewModel.selectedGridOption.collect {
+                        gridOption ->
+                        optionShapeGridDescription?.let { TextViewBinder.bind(it, gridOption.text) }
+                        gridOption.payload?.let { gridIconViewModel ->
+                            optionShapeGridIcon?.let {
+                                GridIconViewBinder.bind(view = it, viewModel = gridIconViewModel)
+                            }
+                            // TODO(b/363018910): Use ColorUpdateBinder to update color
+                            optionShapeGridIcon?.setColorFilter(
+                                ContextCompat.getColor(
+                                    view.context,
+                                    com.android.wallpaper.R.color.system_on_surface_variant,
+                                )
+                            )
+                        }
+                    }
+                }
             }
         }
+
+        customizationOptionFloatingSheetViewMap
+            ?.get(ThemePickerLockCustomizationOption.CLOCK)
+            ?.let {
+                ClockFloatingSheetBinder.bind(
+                    it,
+                    optionsViewModel,
+                    colorUpdateViewModel,
+                    lifecycleOwner,
+                )
+            }
+
+        customizationOptionFloatingSheetViewMap
+            ?.get(ThemePickerLockCustomizationOption.SHORTCUTS)
+            ?.let {
+                ShortcutFloatingSheetBinder.bind(
+                    it,
+                    optionsViewModel,
+                    colorUpdateViewModel,
+                    lifecycleOwner,
+                )
+            }
+
+        customizationOptionFloatingSheetViewMap
+            ?.get(ThemePickerHomeCustomizationOption.COLORS)
+            ?.let {
+                ColorsFloatingSheetBinder.bind(
+                    it,
+                    optionsViewModel,
+                    colorUpdateViewModel,
+                    lifecycleOwner,
+                )
+            }
+
+        customizationOptionFloatingSheetViewMap
+            ?.get(ThemePickerHomeCustomizationOption.APP_SHAPE_GRID)
+            ?.let {
+                ShapeGridFloatingSheetBinder.bind(
+                    it,
+                    optionsViewModel,
+                    colorUpdateViewModel,
+                    lifecycleOwner,
+                    Dispatchers.IO,
+                )
+            }
     }
+
+    override fun bindClockPreview(
+        context: Context,
+        clockHostView: View,
+        viewModel: CustomizationPickerViewModel2,
+        colorUpdateViewModel: ColorUpdateViewModel,
+        lifecycleOwner: LifecycleOwner,
+        clockViewFactory: ClockViewFactory,
+    ) {
+        clockHostView as ClockConstraintLayoutHostView
+        val clockPickerViewModel =
+            (viewModel.customizationOptionsViewModel as ThemePickerCustomizationOptionsViewModel)
+                .clockPickerViewModel
+
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch {
+                    combine(
+                            clockPickerViewModel.previewingClock.filterNotNull(),
+                            clockPickerViewModel.previewingClockSize,
+                        ) { clock, size ->
+                            clock to size
+                        }
+                        .collect { (clock, size) ->
+                            clockHostView.removeAllViews()
+                            // For new customization picker, we should get views from clocklayout
+                            if (Flags.newCustomizationPickerUi()) {
+                                clockViewFactory.getController(clock.clockId).let { clockController
+                                    ->
+                                    addClockViews(clockController, clockHostView, size)
+                                    val cs = ConstraintSet()
+                                    clockController.largeClock.layout.applyPreviewConstraints(
+                                        context,
+                                        cs,
+                                    )
+                                    clockController.smallClock.layout.applyPreviewConstraints(
+                                        context,
+                                        cs,
+                                    )
+                                    cs.applyTo(clockHostView)
+                                }
+                            } else {
+                                val clockView =
+                                    when (size) {
+                                        ClockSize.DYNAMIC ->
+                                            clockViewFactory.getLargeView(clock.clockId)
+                                        ClockSize.SMALL ->
+                                            clockViewFactory.getSmallView(clock.clockId)
+                                    }
+                                // The clock view might still be attached to an existing parent.
+                                // Detach
+                                // before adding to another parent.
+                                (clockView.parent as? ViewGroup)?.removeView(clockView)
+                                clockHostView.addView(clockView)
+                            }
+                        }
+                }
+
+                launch {
+                    combine(
+                            clockPickerViewModel.previewingSeedColor,
+                            clockPickerViewModel.previewingClock,
+                            clockPickerViewModel.previewingFontAxisMap,
+                            colorUpdateViewModel.systemColorsUpdated,
+                            ::Quadruple,
+                        )
+                        .collect { quadruple ->
+                            val (color, clock, axisMap, _) = quadruple
+                            clockViewFactory.updateColor(clock.clockId, color)
+                            val axisList = axisMap.map { ClockFontAxisSetting(it.key, it.value) }
+                            clockViewFactory.updateFontAxes(clock.clockId, axisList)
+                        }
+                }
+            }
+        }
+    }
+
+    data class Quadruple<A, B, C, D>(val first: A, val second: B, val third: C, val fourth: D)
 }
diff --git a/src/com/android/wallpaper/customization/ui/binder/ThemePickerToolbarBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ThemePickerToolbarBinder.kt
new file mode 100644
index 0000000..357f131
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/binder/ThemePickerToolbarBinder.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.binder
+
+import android.animation.ValueAnimator
+import android.view.ViewTreeObserver.OnGlobalLayoutListener
+import android.widget.Button
+import android.widget.FrameLayout
+import android.widget.Toolbar
+import androidx.core.view.isInvisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
+import com.android.wallpaper.customization.ui.viewmodel.ToolbarHeightsViewModel
+import com.android.wallpaper.picker.customization.ui.binder.DefaultToolbarBinder
+import com.android.wallpaper.picker.customization.ui.binder.ToolbarBinder
+import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationOptionsViewModel
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.launch
+
+@Singleton
+class ThemePickerToolbarBinder
+@Inject
+constructor(private val defaultToolbarBinder: DefaultToolbarBinder) : ToolbarBinder {
+
+    private val _toolbarHeights: MutableStateFlow<ToolbarHeightsViewModel?> = MutableStateFlow(null)
+    private val toolbarHeights = _toolbarHeights.asStateFlow().filterNotNull()
+
+    override fun bind(
+        navButton: FrameLayout,
+        toolbar: Toolbar,
+        applyButton: Button,
+        viewModel: CustomizationOptionsViewModel,
+        lifecycleOwner: LifecycleOwner,
+        onNavBack: () -> Unit,
+    ) {
+        defaultToolbarBinder.bind(
+            navButton,
+            toolbar,
+            applyButton,
+            viewModel,
+            lifecycleOwner,
+            onNavBack,
+        )
+
+        if (viewModel !is ThemePickerCustomizationOptionsViewModel) {
+            throw IllegalArgumentException(
+                "viewModel $viewModel is not a ThemePickerCustomizationOptionsViewModel."
+            )
+        }
+
+        navButton.viewTreeObserver.addOnGlobalLayoutListener(
+            object : OnGlobalLayoutListener {
+                override fun onGlobalLayout() {
+                    if (navButton.height != 0) {
+                        _toolbarHeights.value =
+                            _toolbarHeights.value?.copy(navButtonHeight = navButton.height)
+                                ?: ToolbarHeightsViewModel(navButtonHeight = navButton.height)
+                    }
+                    navButton.viewTreeObserver.removeOnGlobalLayoutListener(this)
+                }
+            }
+        )
+
+        toolbar.viewTreeObserver.addOnGlobalLayoutListener(
+            object : OnGlobalLayoutListener {
+                override fun onGlobalLayout() {
+                    if (toolbar.height != 0) {
+                        _toolbarHeights.value =
+                            _toolbarHeights.value?.copy(toolbarHeight = toolbar.height)
+                                ?: ToolbarHeightsViewModel(toolbarHeight = toolbar.height)
+                    }
+                    navButton.viewTreeObserver.removeOnGlobalLayoutListener(this)
+                }
+            }
+        )
+
+        applyButton.viewTreeObserver.addOnGlobalLayoutListener(
+            object : OnGlobalLayoutListener {
+                override fun onGlobalLayout() {
+                    if (applyButton.height != 0) {
+                        _toolbarHeights.value =
+                            _toolbarHeights.value?.copy(applyButtonHeight = applyButton.height)
+                                ?: ToolbarHeightsViewModel(applyButtonHeight = applyButton.height)
+                    }
+                    applyButton.viewTreeObserver.removeOnGlobalLayoutListener(this)
+                }
+            }
+        )
+
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch {
+                    viewModel.onApplyButtonClicked.collect { onApplyButtonClicked ->
+                        applyButton.setOnClickListener { onApplyButtonClicked?.invoke(onNavBack) }
+                    }
+                }
+
+                launch { viewModel.isOnApplyVisible.collect { applyButton.isInvisible = !it } }
+
+                launch { viewModel.isOnApplyEnabled.collect { applyButton.isEnabled = it } }
+
+                launch {
+                    combine(toolbarHeights, viewModel.isToolbarCollapsed, ::Pair).collect {
+                        (toolbarHeights, isToolbarCollapsed) ->
+                        val (navButtonHeight, toolbarHeight, applyButtonHeight) = toolbarHeights
+                        navButtonHeight ?: return@collect
+                        toolbarHeight ?: return@collect
+                        applyButtonHeight ?: return@collect
+
+                        val navButtonToHeight = if (isToolbarCollapsed) 0 else navButtonHeight
+                        val toolbarToHeight = if (isToolbarCollapsed) 0 else toolbarHeight
+                        val applyButtonToHeight = if (isToolbarCollapsed) 0 else applyButtonHeight
+                        ValueAnimator.ofInt(navButton.height, navButtonToHeight)
+                            .apply {
+                                addUpdateListener { valueAnimator ->
+                                    val value = valueAnimator.animatedValue as Int
+                                    navButton.layoutParams =
+                                        navButton.layoutParams.apply { height = value }
+                                }
+                                duration = ANIMATION_DURATION
+                            }
+                            .start()
+
+                        ValueAnimator.ofInt(toolbar.height, toolbarToHeight)
+                            .apply {
+                                addUpdateListener { valueAnimator ->
+                                    val value = valueAnimator.animatedValue as Int
+                                    toolbar.layoutParams =
+                                        toolbar.layoutParams.apply { height = value }
+                                }
+                                duration = ANIMATION_DURATION
+                            }
+                            .start()
+
+                        ValueAnimator.ofInt(applyButton.height, applyButtonToHeight)
+                            .apply {
+                                addUpdateListener { valueAnimator ->
+                                    val value = valueAnimator.animatedValue as Int
+                                    applyButton.layoutParams =
+                                        applyButton.layoutParams.apply { height = value }
+                                }
+                                duration = ANIMATION_DURATION
+                            }
+                            .start()
+                    }
+                }
+            }
+        }
+    }
+
+    companion object {
+        private const val ANIMATION_DURATION = 200L
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/util/ThemePickerCustomizationOptionUtil.kt b/src/com/android/wallpaper/customization/ui/util/ThemePickerCustomizationOptionUtil.kt
index d670e68..6006327 100644
--- a/src/com/android/wallpaper/customization/ui/util/ThemePickerCustomizationOptionUtil.kt
+++ b/src/com/android/wallpaper/customization/ui/util/ThemePickerCustomizationOptionUtil.kt
@@ -18,8 +18,10 @@
 
 import android.view.LayoutInflater
 import android.view.View
+import android.view.ViewGroup
 import android.widget.FrameLayout
 import android.widget.LinearLayout
+import com.android.customization.picker.mode.shared.util.DarkModeLifecycleUtil
 import com.android.themepicker.R
 import com.android.wallpaper.model.Screen
 import com.android.wallpaper.model.Screen.HOME_SCREEN
@@ -35,6 +37,9 @@
 constructor(private val defaultCustomizationOptionUtil: DefaultCustomizationOptionUtil) :
     CustomizationOptionUtil {
 
+    // Instantiate DarkModeLifecycleUtil for it to observe lifecycle and update DarkModeRepository
+    @Inject lateinit var darkModeLifecycleUtil: DarkModeLifecycleUtil
+
     enum class ThemePickerLockCustomizationOption : CustomizationOptionUtil.CustomizationOption {
         CLOCK,
         SHORTCUTS,
@@ -44,24 +49,17 @@
 
     enum class ThemePickerHomeCustomizationOption : CustomizationOptionUtil.CustomizationOption {
         COLORS,
-        APP_GRID,
-        APP_SHAPE,
+        APP_SHAPE_GRID,
         THEMED_ICONS,
     }
 
-    private var viewMap: Map<CustomizationOptionUtil.CustomizationOption, View>? = null
-
     override fun getOptionEntries(
         screen: Screen,
         optionContainer: LinearLayout,
         layoutInflater: LayoutInflater,
     ): List<Pair<CustomizationOptionUtil.CustomizationOption, View>> {
         val defaultOptionEntries =
-            defaultCustomizationOptionUtil.getOptionEntries(
-                screen,
-                optionContainer,
-                layoutInflater,
-            )
+            defaultCustomizationOptionUtil.getOptionEntries(screen, optionContainer, layoutInflater)
         return when (screen) {
             LOCK_SCREEN ->
                 buildList {
@@ -79,7 +77,7 @@
                             layoutInflater.inflate(
                                 R.layout.customization_option_entry_keyguard_quick_affordance,
                                 optionContainer,
-                                false
+                                false,
                             )
                     )
                     add(
@@ -111,17 +109,9 @@
                             )
                     )
                     add(
-                        ThemePickerHomeCustomizationOption.APP_GRID to
+                        ThemePickerHomeCustomizationOption.APP_SHAPE_GRID to
                             layoutInflater.inflate(
-                                R.layout.customization_option_entry_app_grid,
-                                optionContainer,
-                                false,
-                            )
-                    )
-                    add(
-                        ThemePickerHomeCustomizationOption.APP_SHAPE to
-                            layoutInflater.inflate(
-                                R.layout.customization_option_entry_app_shape,
+                                R.layout.customization_option_entry_app_shape_grid,
                                 optionContainer,
                                 false,
                             )
@@ -138,49 +128,72 @@
         }
     }
 
-    override fun initBottomSheetContent(
+    override fun initFloatingSheet(
         bottomSheetContainer: FrameLayout,
-        layoutInflater: LayoutInflater
-    ) {
-        defaultCustomizationOptionUtil.initBottomSheetContent(bottomSheetContainer, layoutInflater)
-        viewMap = buildMap {
+        layoutInflater: LayoutInflater,
+    ): Map<CustomizationOptionUtil.CustomizationOption, View> {
+        val map =
+            defaultCustomizationOptionUtil.initFloatingSheet(bottomSheetContainer, layoutInflater)
+        return buildMap {
+            putAll(map)
             put(
                 ThemePickerLockCustomizationOption.CLOCK,
-                createCustomizationPickerBottomSheetView(
+                inflateFloatingSheet(
                         ThemePickerLockCustomizationOption.CLOCK,
                         bottomSheetContainer,
                         layoutInflater,
                     )
-                    .also { bottomSheetContainer.addView(it) }
+                    .also { bottomSheetContainer.addView(it) },
             )
             put(
                 ThemePickerLockCustomizationOption.SHORTCUTS,
-                createCustomizationPickerBottomSheetView(
+                inflateFloatingSheet(
                         ThemePickerLockCustomizationOption.SHORTCUTS,
                         bottomSheetContainer,
                         layoutInflater,
                     )
-                    .also { bottomSheetContainer.addView(it) }
+                    .also { bottomSheetContainer.addView(it) },
+            )
+            put(
+                ThemePickerHomeCustomizationOption.COLORS,
+                inflateFloatingSheet(
+                        ThemePickerHomeCustomizationOption.COLORS,
+                        bottomSheetContainer,
+                        layoutInflater,
+                    )
+                    .also { bottomSheetContainer.addView(it) },
+            )
+            put(
+                ThemePickerHomeCustomizationOption.APP_SHAPE_GRID,
+                inflateFloatingSheet(
+                        ThemePickerHomeCustomizationOption.APP_SHAPE_GRID,
+                        bottomSheetContainer,
+                        layoutInflater,
+                    )
+                    .also { bottomSheetContainer.addView(it) },
             )
         }
     }
 
-    override fun getBottomSheetContent(option: CustomizationOptionUtil.CustomizationOption): View? {
-        return defaultCustomizationOptionUtil.getBottomSheetContent(option) ?: viewMap?.get(option)
+    override fun createClockPreviewAndAddToParent(
+        parentView: ViewGroup,
+        layoutInflater: LayoutInflater,
+    ): View? {
+        val clockHostView = layoutInflater.inflate(R.layout.clock_host_view, parentView, false)
+        parentView.addView(clockHostView)
+        return clockHostView
     }
 
-    override fun onDestroy() {
-        viewMap = null
-    }
-
-    private fun createCustomizationPickerBottomSheetView(
-        option: ThemePickerLockCustomizationOption,
+    private fun inflateFloatingSheet(
+        option: CustomizationOptionUtil.CustomizationOption,
         bottomSheetContainer: FrameLayout,
         layoutInflater: LayoutInflater,
     ): View =
         when (option) {
-            ThemePickerLockCustomizationOption.CLOCK -> com.android.wallpaper.R.layout.bottom_sheet_clock
-            ThemePickerLockCustomizationOption.SHORTCUTS -> com.android.wallpaper.R.layout.bottom_sheet_shortcut
+            ThemePickerLockCustomizationOption.CLOCK -> R.layout.floating_sheet_clock
+            ThemePickerLockCustomizationOption.SHORTCUTS -> R.layout.floating_sheet_shortcut
+            ThemePickerHomeCustomizationOption.COLORS -> R.layout.floating_sheet_colors
+            ThemePickerHomeCustomizationOption.APP_SHAPE_GRID -> R.layout.floating_sheet_shape_grid
             else ->
                 throw IllegalStateException(
                     "Customization option $option does not have a bottom sheet view"
diff --git a/src/com/android/wallpaper/customization/ui/view/ShapeTileDrawable.kt b/src/com/android/wallpaper/customization/ui/view/ShapeTileDrawable.kt
new file mode 100644
index 0000000..3b492f4
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/view/ShapeTileDrawable.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.view
+
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import androidx.core.graphics.PathParser
+
+/**
+ * Drawable that draws a shape tile with a given path.
+ *
+ * @param path Path of the shape assuming drawing on a 100x100 canvas.
+ */
+class ShapeTileDrawable(path: String) : Drawable() {
+
+    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
+    private val path = PathParser.createPathFromPathData(path)
+    // The path scaled with regard to the update of drawable bounds
+    private val scaledPath = Path(this.path)
+    private val scaleMatrix = Matrix()
+
+    override fun onBoundsChange(bounds: Rect) {
+        super.onBoundsChange(bounds)
+        scaleMatrix.setScale(bounds.width() / PATH_SIZE, bounds.height() / PATH_SIZE)
+        path.transform(scaleMatrix, scaledPath)
+    }
+
+    override fun draw(canvas: Canvas) {
+        canvas.drawPath(scaledPath, paint)
+    }
+
+    override fun setAlpha(alpha: Int) {
+        paint.alpha = alpha
+    }
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {
+        paint.setColorFilter(colorFilter)
+    }
+
+    @Deprecated(
+        "getOpacity() is deprecated",
+        ReplaceWith("setAlpha(int)", "android.graphics.drawable.Drawable"),
+    )
+    override fun getOpacity(): Int {
+        return PixelFormat.TRANSLUCENT
+    }
+
+    companion object {
+        const val PATH_SIZE = 100f
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockFloatingSheetHeightsViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockFloatingSheetHeightsViewModel.kt
new file mode 100644
index 0000000..a39ee7d
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ClockFloatingSheetHeightsViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+data class ClockFloatingSheetHeightsViewModel(
+    val clockStyleContentHeight: Int? = null,
+    val clockColorContentHeight: Int? = null,
+)
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockOptionItemViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockOptionItemViewModel.kt
new file mode 100644
index 0000000..cd223a0
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ClockOptionItemViewModel.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.graphics.drawable.Drawable
+
+data class ClockOptionItemViewModel(
+    val clockId: String,
+    val isSelected: Boolean,
+    val contentDescription: String,
+    val thumbnail: Drawable,
+)
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt
new file mode 100644
index 0000000..da3e65c
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModel.kt
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.drawable.Drawable
+import androidx.core.graphics.ColorUtils
+import com.android.customization.model.color.ColorOptionImpl
+import com.android.customization.module.logging.ThemesUserEventLogger
+import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
+import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.customization.picker.clock.ui.viewmodel.ClockColorViewModel
+import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.color.shared.model.ColorOptionModel
+import com.android.customization.picker.color.shared.model.ColorType
+import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
+import com.android.themepicker.R
+import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
+import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
+import com.android.wallpaper.picker.customization.ui.viewmodel.FloatingToolbarTabViewModel
+import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.android.scopes.ViewModelScoped
+import kotlin.collections.map
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/** View model for the clock customization screen. */
+class ClockPickerViewModel
+@AssistedInject
+constructor(
+    @ApplicationContext context: Context,
+    resources: Resources,
+    private val clockPickerInteractor: ClockPickerInteractor,
+    colorPickerInteractor: ColorPickerInteractor,
+    private val logger: ThemesUserEventLogger,
+    @BackgroundDispatcher private val backgroundDispatcher: CoroutineDispatcher,
+    @Assisted private val viewModelScope: CoroutineScope,
+) {
+
+    enum class Tab {
+        STYLE,
+        COLOR,
+        FONT,
+    }
+
+    private val colorMap = ClockColorViewModel.getPresetColorMap(context.resources)
+
+    // Tabs
+    private val _selectedTab = MutableStateFlow(Tab.STYLE)
+    val selectedTab: StateFlow<Tab> = _selectedTab.asStateFlow()
+    val tabs: Flow<List<FloatingToolbarTabViewModel>> =
+        _selectedTab.asStateFlow().map {
+            listOf(
+                FloatingToolbarTabViewModel(
+                    Icon.Resource(
+                        res = R.drawable.ic_style_filled_24px,
+                        contentDescription = Text.Resource(R.string.clock_style),
+                    ),
+                    context.getString(R.string.clock_style),
+                    it == Tab.STYLE || it == Tab.FONT,
+                ) {
+                    _selectedTab.value = Tab.STYLE
+                },
+                FloatingToolbarTabViewModel(
+                    Icon.Resource(
+                        res = R.drawable.ic_palette_filled_24px,
+                        contentDescription = Text.Resource(R.string.clock_color),
+                    ),
+                    context.getString(R.string.clock_color),
+                    it == Tab.COLOR,
+                ) {
+                    _selectedTab.value = Tab.COLOR
+                },
+            )
+        }
+
+    // Clock style
+    private val overridingClock = MutableStateFlow<ClockMetadataModel?>(null)
+    private val isClockEdited =
+        combine(overridingClock, clockPickerInteractor.selectedClock) {
+            overridingClock,
+            selectedClock ->
+            overridingClock != null && overridingClock.clockId != selectedClock.clockId
+        }
+    val previewingClock =
+        combine(overridingClock, clockPickerInteractor.selectedClock) {
+            overridingClock,
+            selectedClock ->
+            overridingClock ?: selectedClock
+        }
+
+    data class ClockStyleModel(val thumbnail: Drawable, val showEditButton: StateFlow<Boolean>)
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    val clockStyleOptions: StateFlow<List<OptionItemViewModel<ClockStyleModel>>> =
+        clockPickerInteractor.allClocks
+            .mapLatest { allClocks ->
+                // Delay to avoid the case that the full list of clocks is not initiated.
+                delay(CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+                val allClockMap = allClocks.groupBy { it.fontAxes.isNotEmpty() }
+                buildList {
+                    allClockMap[true]?.map { add(it.toOption(resources)) }
+                    allClockMap[false]?.map { add(it.toOption(resources)) }
+                }
+            }
+            // makes sure that the operations above this statement are executed on I/O dispatcher
+            // while parallelism limits the number of threads this can run on which makes sure that
+            // the flows run sequentially
+            .flowOn(backgroundDispatcher.limitedParallelism(1))
+            .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
+
+    private suspend fun ClockMetadataModel.toOption(
+        resources: Resources
+    ): OptionItemViewModel<ClockStyleModel> {
+        val isSelectedFlow = previewingClock.map { it.clockId == clockId }.stateIn(viewModelScope)
+        val isEditable = fontAxes.isNotEmpty()
+        val showEditButton = isSelectedFlow.map { it && isEditable }.stateIn(viewModelScope)
+        val contentDescription =
+            resources.getString(R.string.select_clock_action_description, description)
+        return OptionItemViewModel<ClockStyleModel>(
+            key = MutableStateFlow(clockId) as StateFlow<String>,
+            payload = ClockStyleModel(thumbnail = thumbnail, showEditButton = showEditButton),
+            text = Text.Loaded(contentDescription),
+            isTextUserVisible = false,
+            isSelected = isSelectedFlow,
+            onClicked =
+                isSelectedFlow.map { isSelected ->
+                    if (isSelected && isEditable) {
+                        fun() {
+                            _selectedTab.value = Tab.FONT
+                        }
+                    } else {
+                        fun() {
+                            overridingClock.value = this
+                            overrideFontAxisMap.value = null
+                        }
+                    }
+                },
+        )
+    }
+
+    // Clock Font Axis Editor
+    private val overrideFontAxisMap = MutableStateFlow<Map<String, Float>?>(null)
+    private val isFontAxisMapEdited = overrideFontAxisMap.map { it != null }
+    private val selectedClockFontAxes =
+        previewingClock
+            .map { clock -> clock.fontAxes.associate { it.key to it.currentValue } }
+            .stateIn(viewModelScope, SharingStarted.Eagerly, null)
+    val previewingFontAxisMap =
+        combine(overrideFontAxisMap, selectedClockFontAxes.filterNotNull()) {
+                overrideAxes,
+                selectedFontAxes ->
+                selectedFontAxes.toMutableMap().let { mutableMap ->
+                    overrideAxes?.forEach { (key, value) -> mutableMap[key] = value }
+                    mutableMap.toMap()
+                }
+            }
+            .stateIn(viewModelScope, SharingStarted.Eagerly, emptyMap())
+
+    fun updatePreviewFontAxis(key: String, value: Float) {
+        val axisMap = (overrideFontAxisMap.value?.toMutableMap() ?: mutableMapOf())
+        axisMap[key] = value
+        overrideFontAxisMap.value = axisMap.toMap()
+    }
+
+    fun confirmFontAxes() {
+        _selectedTab.value = Tab.STYLE
+    }
+
+    fun cancelFontAxes() {
+        overrideFontAxisMap.value = null
+        _selectedTab.value = Tab.STYLE
+    }
+
+    // Clock size
+    private val overridingClockSize = MutableStateFlow<ClockSize?>(null)
+    private val isClockSizeEdited =
+        combine(overridingClockSize, clockPickerInteractor.selectedClockSize) {
+            overridingClockSize,
+            selectedClockSize ->
+            overridingClockSize != null && overridingClockSize != selectedClockSize
+        }
+    val previewingClockSize =
+        combine(overridingClockSize, clockPickerInteractor.selectedClockSize) {
+            overridingClockSize,
+            selectedClockSize ->
+            overridingClockSize ?: selectedClockSize
+        }
+    val onClockSizeSwitchCheckedChange: Flow<(() -> Unit)> =
+        previewingClockSize.map {
+            {
+                when (it) {
+                    ClockSize.DYNAMIC -> overridingClockSize.value = ClockSize.SMALL
+                    ClockSize.SMALL -> overridingClockSize.value = ClockSize.DYNAMIC
+                }
+            }
+        }
+
+    // Clock color
+    // 0 - 100
+    private val overridingClockColorId = MutableStateFlow<String?>(null)
+    private val isClockColorIdEdited =
+        combine(overridingClockColorId, clockPickerInteractor.selectedColorId) {
+            overridingClockColorId,
+            selectedColorId ->
+            overridingClockColorId != null && (overridingClockColorId != selectedColorId)
+        }
+    private val previewingClockColorId =
+        combine(overridingClockColorId, clockPickerInteractor.selectedColorId) {
+            overridingClockColorId,
+            selectedColorId ->
+            overridingClockColorId ?: selectedColorId ?: DEFAULT_CLOCK_COLOR_ID
+        }
+
+    private val overridingSliderProgress = MutableStateFlow<Int?>(null)
+    private val isSliderProgressEdited =
+        combine(overridingSliderProgress, clockPickerInteractor.colorToneProgress) {
+            overridingSliderProgress,
+            colorToneProgress ->
+            overridingSliderProgress != null && (overridingSliderProgress != colorToneProgress)
+        }
+    val previewingSliderProgress: Flow<Int> =
+        combine(overridingSliderProgress, clockPickerInteractor.colorToneProgress) {
+            overridingSliderProgress,
+            colorToneProgress ->
+            overridingSliderProgress ?: colorToneProgress
+        }
+    val isSliderEnabled: Flow<Boolean> =
+        combine(previewingClock, previewingClockColorId) { clock, clockColorId ->
+                clock.isReactiveToTone && clockColorId != DEFAULT_CLOCK_COLOR_ID
+            }
+            .distinctUntilChanged()
+
+    fun onSliderProgressChanged(progress: Int) {
+        overridingSliderProgress.value = progress
+    }
+
+    val previewingSeedColor: Flow<Int?> =
+        combine(previewingClockColorId, previewingSliderProgress) { clockColorId, sliderProgress ->
+            val clockColorViewModel =
+                if (clockColorId == DEFAULT_CLOCK_COLOR_ID) null else colorMap[clockColorId]
+            if (clockColorViewModel == null) {
+                null
+            } else {
+                blendColorWithTone(
+                    color = clockColorViewModel.color,
+                    colorTone = clockColorViewModel.getColorTone(sliderProgress),
+                )
+            }
+        }
+
+    val clockColorOptions: Flow<List<OptionItemViewModel<ColorOptionIconViewModel>>> =
+        colorPickerInteractor.colorOptions.map { colorOptions ->
+            // Use mapLatest and delay(100) here to prevent too many selectedClockColor update
+            // events from ClockRegistry upstream, caused by sliding the saturation level bar.
+            delay(COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS)
+            buildList {
+                val defaultThemeColorOptionViewModel =
+                    (colorOptions[ColorType.WALLPAPER_COLOR]?.find { it.isSelected })
+                        ?.toOptionItemViewModel(context)
+                        ?: (colorOptions[ColorType.PRESET_COLOR]?.find { it.isSelected })
+                            ?.toOptionItemViewModel(context)
+                if (defaultThemeColorOptionViewModel != null) {
+                    add(defaultThemeColorOptionViewModel)
+                }
+
+                colorMap.values.forEachIndexed { index, colorModel ->
+                    val isSelectedFlow =
+                        previewingClockColorId
+                            .map { colorMap.keys.indexOf(it) == index }
+                            .stateIn(viewModelScope)
+                    add(
+                        OptionItemViewModel<ColorOptionIconViewModel>(
+                            key = MutableStateFlow(colorModel.colorId) as StateFlow<String>,
+                            payload =
+                                ColorOptionIconViewModel(
+                                    lightThemeColor0 = colorModel.color,
+                                    lightThemeColor1 = colorModel.color,
+                                    lightThemeColor2 = colorModel.color,
+                                    lightThemeColor3 = colorModel.color,
+                                    darkThemeColor0 = colorModel.color,
+                                    darkThemeColor1 = colorModel.color,
+                                    darkThemeColor2 = colorModel.color,
+                                    darkThemeColor3 = colorModel.color,
+                                ),
+                            text =
+                                Text.Loaded(
+                                    context.getString(
+                                        R.string.content_description_color_option,
+                                        index,
+                                    )
+                                ),
+                            isTextUserVisible = false,
+                            isSelected = isSelectedFlow,
+                            onClicked =
+                                isSelectedFlow.map { isSelected ->
+                                    if (isSelected) {
+                                        null
+                                    } else {
+                                        {
+                                            overridingClockColorId.value = colorModel.colorId
+                                            overridingSliderProgress.value =
+                                                ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS
+                                        }
+                                    }
+                                },
+                        )
+                    )
+                }
+            }
+        }
+
+    private suspend fun ColorOptionModel.toOptionItemViewModel(
+        context: Context
+    ): OptionItemViewModel<ColorOptionIconViewModel> {
+        val lightThemeColors =
+            (colorOption as ColorOptionImpl)
+                .previewInfo
+                .resolveColors(
+                    /** darkTheme= */
+                    false
+                )
+        val darkThemeColors =
+            colorOption.previewInfo.resolveColors(
+                /** darkTheme= */
+                true
+            )
+        val isSelectedFlow =
+            previewingClockColorId.map { it == DEFAULT_CLOCK_COLOR_ID }.stateIn(viewModelScope)
+        return OptionItemViewModel<ColorOptionIconViewModel>(
+            key = MutableStateFlow(key) as StateFlow<String>,
+            payload =
+                ColorOptionIconViewModel(
+                    lightThemeColor0 = lightThemeColors[0],
+                    lightThemeColor1 = lightThemeColors[1],
+                    lightThemeColor2 = lightThemeColors[2],
+                    lightThemeColor3 = lightThemeColors[3],
+                    darkThemeColor0 = darkThemeColors[0],
+                    darkThemeColor1 = darkThemeColors[1],
+                    darkThemeColor2 = darkThemeColors[2],
+                    darkThemeColor3 = darkThemeColors[3],
+                ),
+            text = Text.Loaded(context.getString(R.string.default_theme_title)),
+            isTextUserVisible = true,
+            isSelected = isSelectedFlow,
+            onClicked =
+                isSelectedFlow.map { isSelected ->
+                    if (isSelected) {
+                        null
+                    } else {
+                        {
+                            overridingClockColorId.value = DEFAULT_CLOCK_COLOR_ID
+                            overridingSliderProgress.value =
+                                ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS
+                        }
+                    }
+                },
+        )
+    }
+
+    private val isEdited =
+        combine(
+            isClockEdited,
+            isClockSizeEdited,
+            isClockColorIdEdited,
+            isSliderProgressEdited,
+            isFontAxisMapEdited,
+        ) {
+            isClockEdited,
+            isClockSizeEdited,
+            isClockColorEdited,
+            isSliderProgressEdited,
+            isFontAxisMapEdited ->
+            isClockEdited ||
+                isClockSizeEdited ||
+                isClockColorEdited ||
+                isSliderProgressEdited ||
+                isFontAxisMapEdited
+        }
+
+    val onApply: Flow<(suspend () -> Unit)?> =
+        combine(
+            isEdited,
+            previewingClock,
+            previewingClockSize,
+            previewingClockColorId,
+            previewingSliderProgress,
+            previewingFontAxisMap,
+        ) { array ->
+            val isEdited = array[0] as Boolean
+            val clock = array[1] as ClockMetadataModel
+            val size = array[2] as ClockSize
+            val previewingColorId = array[3] as String
+            val previewProgress = array[4] as Int
+            val axisMap = array[5] as Map<String, Float>
+            if (isEdited) {
+                {
+                    clockPickerInteractor.applyClock(
+                        clockId = clock.clockId,
+                        size = size,
+                        selectedColorId = previewingColorId,
+                        colorToneProgress = previewProgress,
+                        seedColor =
+                            colorMap[previewingColorId]?.let {
+                                blendColorWithTone(
+                                    color = it.color,
+                                    colorTone = it.getColorTone(previewProgress),
+                                )
+                            },
+                        axisSettings = axisMap.map { ClockFontAxisSetting(it.key, it.value) },
+                    )
+                }
+            } else {
+                null
+            }
+        }
+
+    fun resetPreview() {
+        overridingClock.value = null
+        overridingClockSize.value = null
+        overridingClockColorId.value = null
+        overridingSliderProgress.value = null
+        overrideFontAxisMap.value = null
+        _selectedTab.value = Tab.STYLE
+    }
+
+    companion object {
+        private const val DEFAULT_CLOCK_COLOR_ID = "DEFAULT"
+        private val helperColorLab: DoubleArray by lazy { DoubleArray(3) }
+
+        fun blendColorWithTone(color: Int, colorTone: Double): Int {
+            ColorUtils.colorToLAB(color, helperColorLab)
+            return ColorUtils.LABToColor(colorTone, helperColorLab[1], helperColorLab[2])
+        }
+
+        const val COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS: Long = 100
+        const val CLOCKS_EVENT_UPDATE_DELAY_MILLIS: Long = 100
+    }
+
+    @ViewModelScoped
+    @AssistedFactory
+    interface Factory {
+        fun create(viewModelScope: CoroutineScope): ClockPickerViewModel
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ClockSizeOptionViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ClockSizeOptionViewModel.kt
new file mode 100644
index 0000000..de2c54a
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ClockSizeOptionViewModel.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+import com.android.customization.picker.clock.shared.ClockSize
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+data class ClockSizeOptionViewModel(
+    val size: ClockSize,
+    val isSelected: StateFlow<Boolean>,
+    val onClicked: Flow<(() -> Unit)?>,
+)
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ColorPickerViewModel2.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ColorPickerViewModel2.kt
new file mode 100644
index 0000000..26e7867
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ColorPickerViewModel2.kt
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.content.Context
+import com.android.customization.model.color.ColorOptionImpl
+import com.android.customization.module.logging.ThemesUserEventLogger
+import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.color.shared.model.ColorOptionModel
+import com.android.customization.picker.color.shared.model.ColorType
+import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
+import com.android.themepicker.R
+import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
+import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
+import com.android.wallpaper.picker.customization.ui.viewmodel.FloatingToolbarTabViewModel
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.android.scopes.ViewModelScoped
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/** Models UI state for a color picker experience. */
+class ColorPickerViewModel2
+@AssistedInject
+constructor(
+    @ApplicationContext context: Context,
+    private val interactor: ColorPickerInteractor,
+    private val logger: ThemesUserEventLogger,
+    @Assisted private val viewModelScope: CoroutineScope,
+) {
+
+    private val overridingColorOption = MutableStateFlow<ColorOptionModel?>(null)
+    val previewingColorOption = overridingColorOption.asStateFlow()
+
+    private val selectedColorTypeTabId = MutableStateFlow<ColorType?>(null)
+
+    /** View-models for each color tab. */
+    val colorTypeTabs: Flow<List<FloatingToolbarTabViewModel>> =
+        combine(interactor.colorOptions, selectedColorTypeTabId) {
+            colorOptions,
+            selectedColorTypeIdOrNull ->
+            colorOptions.keys.mapIndexed { index, colorType ->
+                val isSelected =
+                    (selectedColorTypeIdOrNull == null && index == 0) ||
+                        selectedColorTypeIdOrNull == colorType
+
+                val name =
+                    when (colorType) {
+                        ColorType.WALLPAPER_COLOR ->
+                            context.resources.getString(R.string.wallpaper_color_tab)
+                        ColorType.PRESET_COLOR ->
+                            context.resources.getString(R.string.preset_color_tab_2)
+                    }
+
+                FloatingToolbarTabViewModel(
+                    Icon.Resource(
+                        res =
+                            when (colorType) {
+                                ColorType.WALLPAPER_COLOR ->
+                                    com.android.wallpaper.R.drawable.ic_baseline_wallpaper_24
+                                ColorType.PRESET_COLOR -> R.drawable.ic_colors
+                            },
+                        contentDescription = Text.Loaded(name),
+                    ),
+                    name,
+                    isSelected,
+                ) {
+                    if (!isSelected) {
+                        this.selectedColorTypeTabId.value = colorType
+                    }
+                }
+            }
+        }
+
+    /** View-models for each color tab subheader */
+    val colorTypeTabSubheader: Flow<String> =
+        selectedColorTypeTabId.map { selectedColorTypeIdOrNull ->
+            when (selectedColorTypeIdOrNull ?: ColorType.WALLPAPER_COLOR) {
+                ColorType.WALLPAPER_COLOR ->
+                    context.resources.getString(R.string.wallpaper_color_subheader)
+                ColorType.PRESET_COLOR ->
+                    context.resources.getString(R.string.preset_color_subheader)
+            }
+        }
+
+    /** The list of all color options mapped by their color type */
+    private val allColorOptions:
+        Flow<Map<ColorType, List<OptionItemViewModel<ColorOptionIconViewModel>>>> =
+        interactor.colorOptions.map { colorOptions ->
+            colorOptions
+                .map { colorOptionEntry ->
+                    colorOptionEntry.key to
+                        colorOptionEntry.value.map { colorOptionModel ->
+                            val colorOption: ColorOptionImpl =
+                                colorOptionModel.colorOption as ColorOptionImpl
+                            val lightThemeColors =
+                                colorOption.previewInfo.resolveColors(/* darkTheme= */ false)
+                            val darkThemeColors =
+                                colorOption.previewInfo.resolveColors(/* darkTheme= */ true)
+                            val isSelectedFlow: StateFlow<Boolean> =
+                                previewingColorOption
+                                    .map {
+                                        it?.colorOption?.isEquivalent(colorOptionModel.colorOption)
+                                            ?: colorOptionModel.isSelected
+                                    }
+                                    .stateIn(viewModelScope)
+                            OptionItemViewModel<ColorOptionIconViewModel>(
+                                key = MutableStateFlow(colorOptionModel.key) as StateFlow<String>,
+                                payload =
+                                    ColorOptionIconViewModel(
+                                        lightThemeColor0 = lightThemeColors[0],
+                                        lightThemeColor1 = lightThemeColors[1],
+                                        lightThemeColor2 = lightThemeColors[2],
+                                        lightThemeColor3 = lightThemeColors[3],
+                                        darkThemeColor0 = darkThemeColors[0],
+                                        darkThemeColor1 = darkThemeColors[1],
+                                        darkThemeColor2 = darkThemeColors[2],
+                                        darkThemeColor3 = darkThemeColors[3],
+                                    ),
+                                text =
+                                    Text.Loaded(
+                                        colorOption.getContentDescription(context).toString()
+                                    ),
+                                isTextUserVisible = false,
+                                isSelected = isSelectedFlow,
+                                onClicked =
+                                    isSelectedFlow.map { isSelected ->
+                                        if (isSelected) {
+                                            null
+                                        } else {
+                                            {
+                                                viewModelScope.launch {
+                                                    overridingColorOption.value = colorOptionModel
+                                                }
+                                            }
+                                        }
+                                    },
+                            )
+                        }
+                }
+                .toMap()
+        }
+
+    val onApply: Flow<(suspend () -> Unit)?> =
+        previewingColorOption.map { previewingColorOption ->
+            previewingColorOption?.let {
+                if (it.isSelected) {
+                    null
+                } else {
+                    {
+                        interactor.select(it)
+                        logger.logThemeColorApplied(
+                            previewingColorOption.colorOption.sourceForLogging,
+                            previewingColorOption.colorOption.styleForLogging,
+                            previewingColorOption.colorOption.seedColor,
+                        )
+                    }
+                }
+            }
+        }
+
+    fun resetPreview() {
+        overridingColorOption.value = null
+    }
+
+    /** The list of all available color options for the selected Color Type. */
+    val colorOptions: Flow<List<OptionItemViewModel<ColorOptionIconViewModel>>> =
+        combine(allColorOptions, selectedColorTypeTabId) {
+            allColorOptions: Map<ColorType, List<OptionItemViewModel<ColorOptionIconViewModel>>>,
+            selectedColorTypeIdOrNull ->
+            val selectedColorTypeId = selectedColorTypeIdOrNull ?: ColorType.WALLPAPER_COLOR
+            allColorOptions[selectedColorTypeId]!!
+        }
+
+    @ViewModelScoped
+    @AssistedFactory
+    interface Factory {
+        fun create(viewModelScope: CoroutineScope): ColorPickerViewModel2
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/KeyguardQuickAffordancePickerViewModel2.kt b/src/com/android/wallpaper/customization/ui/viewmodel/KeyguardQuickAffordancePickerViewModel2.kt
new file mode 100644
index 0000000..fd94b78
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/KeyguardQuickAffordancePickerViewModel2.kt
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import androidx.annotation.DrawableRes
+import com.android.customization.module.logging.ThemesUserEventLogger
+import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
+import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordanceSlotViewModel
+import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordanceSummaryViewModel
+import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END
+import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.KEYGUARD_QUICK_AFFORDANCE_ID_NONE
+import com.android.themepicker.R
+import com.android.wallpaper.picker.common.button.ui.viewmodel.ButtonStyle
+import com.android.wallpaper.picker.common.button.ui.viewmodel.ButtonViewModel
+import com.android.wallpaper.picker.common.dialog.ui.viewmodel.DialogViewModel
+import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
+import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
+import com.android.wallpaper.picker.customization.ui.viewmodel.FloatingToolbarTabViewModel
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.android.scopes.ViewModelScoped
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
+
+class KeyguardQuickAffordancePickerViewModel2
+@AssistedInject
+constructor(
+    @ApplicationContext private val applicationContext: Context,
+    private val quickAffordanceInteractor: KeyguardQuickAffordancePickerInteractor,
+    private val logger: ThemesUserEventLogger,
+    @Assisted private val viewModelScope: CoroutineScope,
+) {
+    /** A locally-selected slot, if the user ever switched from the original one. */
+    private val _selectedSlotId = MutableStateFlow<String?>(null)
+    /** The ID of the selected slot. */
+    val selectedSlotId: StateFlow<String> =
+        combine(quickAffordanceInteractor.slots, _selectedSlotId) { slots, selectedSlotIdOrNull ->
+                if (selectedSlotIdOrNull != null) {
+                    slots.first { slot -> slot.id == selectedSlotIdOrNull }
+                } else {
+                    // If we haven't yet selected a new slot locally, default to the first slot.
+                    slots[0]
+                }
+            }
+            .map { selectedSlot -> selectedSlot.id }
+            .stateIn(
+                scope = viewModelScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = "",
+            )
+    private val _previewingQuickAffordances = MutableStateFlow<Map<String, String>>(emptyMap())
+    val previewingQuickAffordances: Flow<Map<String, String>> =
+        _previewingQuickAffordances.asStateFlow()
+
+    fun resetPreview() {
+        _previewingQuickAffordances.tryEmit(emptyMap())
+        _selectedSlotId.tryEmit(SLOT_ID_BOTTOM_START)
+    }
+
+    /** View-models for each slot, keyed by slot ID. */
+    private val slots: StateFlow<Map<String, KeyguardQuickAffordanceSlotViewModel>> =
+        combine(
+                quickAffordanceInteractor.slots,
+                quickAffordanceInteractor.affordances,
+                quickAffordanceInteractor.selections,
+                previewingQuickAffordances,
+                selectedSlotId,
+            ) { slots, affordances, selections, selectedQuickAffordances, selectedSlotId ->
+                slots.associate { slot ->
+                    val selectedAffordanceIds =
+                        selectedQuickAffordances[slot.id]?.let { setOf(it) }
+                            ?: selections
+                                .filter { selection -> selection.slotId == slot.id }
+                                .map { selection -> selection.affordanceId }
+                                .toSet()
+                    val selectedAffordances =
+                        affordances.filter { affordance ->
+                            selectedAffordanceIds.contains(affordance.id)
+                        }
+
+                    val isSelected = selectedSlotId == slot.id
+                    slot.id to
+                        KeyguardQuickAffordanceSlotViewModel(
+                            name = getSlotName(slot.id),
+                            isSelected = isSelected,
+                            selectedQuickAffordances =
+                                selectedAffordances.map { affordanceModel ->
+                                    OptionItemViewModel<Icon>(
+                                        key =
+                                            MutableStateFlow("${slot.id}::${affordanceModel.id}")
+                                                as StateFlow<String>,
+                                        payload =
+                                            Icon.Loaded(
+                                                drawable =
+                                                    getAffordanceIcon(
+                                                        affordanceModel.iconResourceId
+                                                    ),
+                                                contentDescription =
+                                                    Text.Loaded(getSlotContentDescription(slot.id)),
+                                            ),
+                                        text = Text.Loaded(affordanceModel.name),
+                                        isSelected = MutableStateFlow(true) as StateFlow<Boolean>,
+                                        onClicked = flowOf(null),
+                                        onLongClicked = null,
+                                        isEnabled = true,
+                                    )
+                                },
+                            maxSelectedQuickAffordances = slot.maxSelectedQuickAffordances,
+                            onClicked =
+                                if (isSelected) {
+                                    null
+                                } else {
+                                    { _selectedSlotId.tryEmit(slot.id) }
+                                },
+                        )
+                }
+            }
+            .stateIn(
+                scope = viewModelScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = emptyMap(),
+            )
+
+    val tabs: Flow<List<FloatingToolbarTabViewModel>> =
+        slots.map { slotById ->
+            slotById.values.map {
+                FloatingToolbarTabViewModel(it.getIcon(), it.name, it.isSelected, it.onClicked)
+            }
+        }
+
+    /**
+     * The set of IDs of the currently-selected affordances. These change with user selection of new
+     * or different affordances in the currently-selected slot or when slot selection changes.
+     */
+    private val selectedAffordanceIds: Flow<Set<String>> =
+        combine(quickAffordanceInteractor.selections, selectedSlotId) { selections, selectedSlotId
+                ->
+                selections
+                    .filter { selection -> selection.slotId == selectedSlotId }
+                    .map { selection -> selection.affordanceId }
+                    .toSet()
+            }
+            .shareIn(scope = viewModelScope, started = SharingStarted.WhileSubscribed(), replay = 1)
+
+    /** The list of all available quick affordances for the selected slot. */
+    val quickAffordances: Flow<List<OptionItemViewModel<Icon>>> =
+        quickAffordanceInteractor.affordances.map { affordances ->
+            val isNoneSelected =
+                combine(selectedSlotId, previewingQuickAffordances, selectedAffordanceIds) {
+                        selectedSlotId,
+                        selectedQuickAffordances,
+                        selectedAffordanceIds ->
+                        selectedQuickAffordances[selectedSlotId]?.let {
+                            it == KEYGUARD_QUICK_AFFORDANCE_ID_NONE
+                        } ?: selectedAffordanceIds.isEmpty()
+                    }
+                    .stateIn(viewModelScope)
+            listOf(
+                none(
+                    slotId = selectedSlotId,
+                    isSelected = isNoneSelected,
+                    onSelected =
+                        combine(isNoneSelected, selectedSlotId) { isSelected, selectedSlotId ->
+                            if (!isSelected) {
+                                {
+                                    val newMap =
+                                        _previewingQuickAffordances.value.toMutableMap().apply {
+                                            put(selectedSlotId, KEYGUARD_QUICK_AFFORDANCE_ID_NONE)
+                                        }
+                                    _previewingQuickAffordances.tryEmit(newMap)
+                                }
+                            } else {
+                                null
+                            }
+                        },
+                )
+            ) +
+                affordances.map { affordance ->
+                    val affordanceIcon = getAffordanceIcon(affordance.iconResourceId)
+                    val isSelectedFlow: StateFlow<Boolean> =
+                        combine(
+                                selectedSlotId,
+                                previewingQuickAffordances,
+                                selectedAffordanceIds,
+                            ) { selectedSlotId, selectedQuickAffordances, selectedAffordanceIds ->
+                                selectedQuickAffordances[selectedSlotId]?.let {
+                                    it == affordance.id
+                                } ?: selectedAffordanceIds.contains(affordance.id)
+                            }
+                            .stateIn(viewModelScope)
+                    OptionItemViewModel<Icon>(
+                        key =
+                            selectedSlotId
+                                .map { slotId -> "$slotId::${affordance.id}" }
+                                .stateIn(viewModelScope),
+                        payload = Icon.Loaded(drawable = affordanceIcon, contentDescription = null),
+                        text = Text.Loaded(affordance.name),
+                        isSelected = isSelectedFlow,
+                        onClicked =
+                            if (affordance.isEnabled) {
+                                combine(isSelectedFlow, selectedSlotId) { isSelected, selectedSlotId
+                                    ->
+                                    if (!isSelected) {
+                                        {
+                                            val newMap =
+                                                _previewingQuickAffordances.value
+                                                    .toMutableMap()
+                                                    .apply { put(selectedSlotId, affordance.id) }
+                                            _previewingQuickAffordances.tryEmit(newMap)
+                                        }
+                                    } else {
+                                        null
+                                    }
+                                }
+                            } else {
+                                flowOf {
+                                    showEnablementDialog(
+                                        icon = affordanceIcon,
+                                        name = affordance.name,
+                                        explanation = affordance.enablementExplanation,
+                                        actionText = affordance.enablementActionText,
+                                        actionIntent = affordance.enablementActionIntent,
+                                    )
+                                }
+                            },
+                        onLongClicked =
+                            if (affordance.configureIntent != null) {
+                                { requestActivityStart(affordance.configureIntent) }
+                            } else {
+                                null
+                            },
+                        isEnabled = affordance.isEnabled,
+                    )
+                }
+        }
+
+    val onApply: Flow<(suspend () -> Unit)?> =
+        previewingQuickAffordances.map {
+            if (it.isEmpty()) {
+                null
+            } else {
+                {
+                    it.forEach { entry ->
+                        val slotId = entry.key
+                        val affordanceId = entry.value
+                        if (slotId == KEYGUARD_QUICK_AFFORDANCE_ID_NONE) {
+                            quickAffordanceInteractor.unselectAllFromSlot(slotId)
+                        } else {
+                            quickAffordanceInteractor.select(
+                                slotId = slotId,
+                                affordanceId = affordanceId,
+                            )
+                        }
+                        logger.logShortcutApplied(shortcut = affordanceId, shortcutSlotId = slotId)
+                    }
+                }
+            }
+        }
+
+    private val _dialog = MutableStateFlow<DialogViewModel?>(null)
+    /**
+     * The current dialog to show. If `null`, no dialog should be shown.
+     *
+     * When the dialog is dismissed, [onDialogDismissed] must be called.
+     */
+    val dialog: Flow<DialogViewModel?> = _dialog.asStateFlow()
+
+    private val _activityStartRequests = MutableStateFlow<Intent?>(null)
+    /**
+     * Requests to start an activity with the given [Intent].
+     *
+     * Important: once the activity is started, the [Intent] should be consumed by calling
+     * [onActivityStarted].
+     */
+    val activityStartRequests: StateFlow<Intent?> = _activityStartRequests.asStateFlow()
+
+    /** Notifies that the dialog has been dismissed in the UI. */
+    fun onDialogDismissed() {
+        _dialog.value = null
+    }
+
+    /**
+     * Notifies that an activity request from [activityStartRequests] has been fulfilled (e.g. the
+     * activity was started and the view-model can forget needing to start this activity).
+     */
+    fun onActivityStarted() {
+        _activityStartRequests.value = null
+    }
+
+    private fun requestActivityStart(intent: Intent) {
+        _activityStartRequests.value = intent
+    }
+
+    private fun showEnablementDialog(
+        icon: Drawable,
+        name: String,
+        explanation: String,
+        actionText: String?,
+        actionIntent: Intent?,
+    ) {
+        _dialog.value =
+            DialogViewModel(
+                icon = Icon.Loaded(drawable = icon, contentDescription = null),
+                headline = Text.Resource(R.string.keyguard_affordance_enablement_dialog_headline),
+                message = Text.Loaded(explanation),
+                buttons =
+                    buildList {
+                        add(
+                            ButtonViewModel(
+                                text =
+                                    Text.Resource(
+                                        if (actionText != null) {
+                                            // This is not the only button on the dialog.
+                                            R.string.cancel
+                                        } else {
+                                            // This is the only button on the dialog.
+                                            R.string
+                                                .keyguard_affordance_enablement_dialog_dismiss_button
+                                        }
+                                    ),
+                                style = ButtonStyle.Secondary,
+                            )
+                        )
+
+                        if (actionText != null) {
+                            add(
+                                ButtonViewModel(
+                                    text = Text.Loaded(actionText),
+                                    style = ButtonStyle.Primary,
+                                    onClicked = {
+                                        actionIntent?.let { intent -> requestActivityStart(intent) }
+                                    },
+                                )
+                            )
+                        }
+                    },
+            )
+    }
+
+    /** Returns a view-model for the special "None" option. */
+    @SuppressLint("UseCompatLoadingForDrawables")
+    private suspend fun none(
+        slotId: StateFlow<String>,
+        isSelected: StateFlow<Boolean>,
+        onSelected: Flow<(() -> Unit)?>,
+    ): OptionItemViewModel<Icon> {
+        return OptionItemViewModel<Icon>(
+            key = slotId.map { "$it::none" }.stateIn(viewModelScope),
+            payload = Icon.Resource(res = R.drawable.link_off, contentDescription = null),
+            text = Text.Resource(res = R.string.keyguard_affordance_none),
+            isSelected = isSelected,
+            onClicked = onSelected,
+            onLongClicked = null,
+            isEnabled = true,
+        )
+    }
+
+    private fun getSlotName(slotId: String): String {
+        return applicationContext.getString(
+            when (slotId) {
+                SLOT_ID_BOTTOM_START -> R.string.keyguard_slot_name_bottom_start
+                SLOT_ID_BOTTOM_END -> R.string.keyguard_slot_name_bottom_end
+                else -> error("No name for slot with ID of \"$slotId\"!")
+            }
+        )
+    }
+
+    private fun getSlotContentDescription(slotId: String): String {
+        return applicationContext.getString(
+            when (slotId) {
+                SLOT_ID_BOTTOM_START -> R.string.keyguard_slot_name_bottom_start
+                SLOT_ID_BOTTOM_END -> R.string.keyguard_slot_name_bottom_end
+                else -> error("No accessibility label for slot with ID \"$slotId\"!")
+            }
+        )
+    }
+
+    private suspend fun getAffordanceIcon(@DrawableRes iconResourceId: Int): Drawable {
+        return quickAffordanceInteractor.getAffordanceIcon(iconResourceId)
+    }
+
+    val summary: Flow<KeyguardQuickAffordanceSummaryViewModel> =
+        slots.map { slots ->
+            val icon2 =
+                (slots[SLOT_ID_BOTTOM_END]?.selectedQuickAffordances?.firstOrNull())?.payload
+            val icon1 =
+                (slots[SLOT_ID_BOTTOM_START]?.selectedQuickAffordances?.firstOrNull())?.payload
+
+            KeyguardQuickAffordanceSummaryViewModel(
+                description = toDescriptionText(applicationContext, slots),
+                icon1 =
+                    icon1
+                        ?: if (icon2 == null) {
+                            Icon.Resource(res = R.drawable.link_off, contentDescription = null)
+                        } else {
+                            null
+                        },
+                icon2 = icon2,
+            )
+        }
+
+    private fun toDescriptionText(
+        context: Context,
+        slots: Map<String, KeyguardQuickAffordanceSlotViewModel>,
+    ): Text {
+        val bottomStartAffordanceName =
+            slots[SLOT_ID_BOTTOM_START]?.selectedQuickAffordances?.firstOrNull()?.text
+        val bottomEndAffordanceName =
+            slots[SLOT_ID_BOTTOM_END]?.selectedQuickAffordances?.firstOrNull()?.text
+
+        return when {
+            bottomStartAffordanceName != null && bottomEndAffordanceName != null -> {
+                Text.Loaded(
+                    context.getString(
+                        R.string.keyguard_quick_affordance_two_selected_template,
+                        bottomStartAffordanceName.asString(context),
+                        bottomEndAffordanceName.asString(context),
+                    )
+                )
+            }
+            bottomStartAffordanceName != null -> bottomStartAffordanceName
+            bottomEndAffordanceName != null -> bottomEndAffordanceName
+            else -> Text.Resource(R.string.keyguard_quick_affordance_none_selected)
+        }
+    }
+
+    companion object {
+        private fun KeyguardQuickAffordanceSlotViewModel.getIcon(): Icon =
+            selectedQuickAffordances.firstOrNull()?.payload
+                ?: Icon.Resource(res = R.drawable.link_off, contentDescription = null)
+    }
+
+    @ViewModelScoped
+    @AssistedFactory
+    interface Factory {
+        fun create(viewModelScope: CoroutineScope): KeyguardQuickAffordancePickerViewModel2
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridFloatingSheetHeightsViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridFloatingSheetHeightsViewModel.kt
new file mode 100644
index 0000000..237ab36
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridFloatingSheetHeightsViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+data class ShapeGridFloatingSheetHeightsViewModel(
+    val shapeContentHeight: Int? = null,
+    val gridContentHeight: Int? = null,
+)
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModel.kt
new file mode 100644
index 0000000..7f3c4cb
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModel.kt
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.content.Context
+import android.content.res.Resources
+import com.android.customization.model.ResourceConstants
+import com.android.customization.model.grid.GridOptionModel
+import com.android.customization.model.grid.ShapeOptionModel
+import com.android.customization.picker.grid.domain.interactor.ShapeGridInteractor
+import com.android.customization.picker.grid.ui.viewmodel.GridIconViewModel
+import com.android.customization.picker.grid.ui.viewmodel.ShapeIconViewModel
+import com.android.themepicker.R
+import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
+import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
+import com.android.wallpaper.picker.customization.ui.viewmodel.FloatingToolbarTabViewModel
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.android.scopes.ViewModelScoped
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
+
+class ShapeGridPickerViewModel
+@AssistedInject
+constructor(
+    @ApplicationContext private val context: Context,
+    interactor: ShapeGridInteractor,
+    @Assisted private val viewModelScope: CoroutineScope,
+) {
+
+    enum class Tab {
+        SHAPE,
+        GRID,
+    }
+
+    //// Tabs
+    private val _selectedTab = MutableStateFlow(Tab.SHAPE)
+    val selectedTab: StateFlow<Tab> = _selectedTab.asStateFlow()
+    val tabs: Flow<List<FloatingToolbarTabViewModel>> =
+        _selectedTab.map {
+            listOf(
+                FloatingToolbarTabViewModel(
+                    Icon.Resource(
+                        res = R.drawable.ic_category_filled_24px,
+                        contentDescription = Text.Resource(R.string.preview_name_shape),
+                    ),
+                    context.getString(R.string.preview_name_shape),
+                    it == Tab.SHAPE,
+                ) {
+                    _selectedTab.value = Tab.SHAPE
+                },
+                FloatingToolbarTabViewModel(
+                    Icon.Resource(
+                        res = R.drawable.ic_apps_filled_24px,
+                        contentDescription = Text.Resource(R.string.grid_layout),
+                    ),
+                    context.getString(R.string.grid_layout),
+                    it == Tab.GRID,
+                ) {
+                    _selectedTab.value = Tab.GRID
+                },
+            )
+        }
+
+    //// Shape
+
+    // The currently-set system shape option
+    val selectedShapeKey =
+        interactor.selectedShapeOption
+            .filterNotNull()
+            .map { it.key }
+            .shareIn(scope = viewModelScope, started = SharingStarted.Lazily, replay = 1)
+    private val overridingShapeKey = MutableStateFlow<String?>(null)
+    // If the overriding key is null, use the currently-set system shape option
+    val previewingShapeKey =
+        combine(overridingShapeKey, selectedShapeKey) { overridingShapeOptionKey, selectedShapeKey
+            ->
+            overridingShapeOptionKey ?: selectedShapeKey
+        }
+
+    val shapeOptions: Flow<List<OptionItemViewModel<ShapeIconViewModel>>> =
+        interactor.shapeOptions
+            .filterNotNull()
+            .map { shapeOptions -> shapeOptions.map { toShapeOptionItemViewModel(it) } }
+            .shareIn(scope = viewModelScope, started = SharingStarted.Lazily, replay = 1)
+
+    //// Grid
+
+    // The currently-set system grid option
+    val selectedGridOption =
+        interactor.selectedGridOption
+            .filterNotNull()
+            .map { toGridOptionItemViewModel(it) }
+            .shareIn(scope = viewModelScope, started = SharingStarted.Lazily, replay = 1)
+    private val overridingGridKey = MutableStateFlow<String?>(null)
+    // If the overriding key is null, use the currently-set system grid option
+    val previewingGridKey =
+        combine(overridingGridKey, selectedGridOption) { overridingGridOptionKey, selectedGridOption
+            ->
+            overridingGridOptionKey ?: selectedGridOption.key.value
+        }
+
+    val gridOptions: Flow<List<OptionItemViewModel<GridIconViewModel>>> =
+        interactor.gridOptions
+            .filterNotNull()
+            .map { gridOptions -> gridOptions.map { toGridOptionItemViewModel(it) } }
+            .shareIn(scope = viewModelScope, started = SharingStarted.Lazily, replay = 1)
+
+    val onApply: Flow<(suspend () -> Unit)?> =
+        combine(previewingGridKey, selectedGridOption, previewingShapeKey, selectedShapeKey) {
+            previewingGridOptionKey,
+            selectedGridOption,
+            previewingShapeKey,
+            selectedShapeKey ->
+            if (
+                previewingGridOptionKey == selectedGridOption.key.value &&
+                    previewingShapeKey == selectedShapeKey
+            ) {
+                null
+            } else {
+                { interactor.applySelectedOption(previewingShapeKey, previewingGridOptionKey) }
+            }
+        }
+
+    fun resetPreview() {
+        overridingShapeKey.value = null
+        overridingGridKey.value = null
+        _selectedTab.value = Tab.SHAPE
+    }
+
+    private fun toShapeOptionItemViewModel(
+        option: ShapeOptionModel
+    ): OptionItemViewModel<ShapeIconViewModel> {
+        val isSelected =
+            previewingShapeKey
+                .map { it == option.key }
+                .stateIn(
+                    scope = viewModelScope,
+                    started = SharingStarted.Lazily,
+                    initialValue = false,
+                )
+
+        return OptionItemViewModel(
+            key = MutableStateFlow(option.key),
+            payload = ShapeIconViewModel(option.key, option.path),
+            text = Text.Loaded(option.title),
+            isSelected = isSelected,
+            onClicked =
+                isSelected.map {
+                    if (!it) {
+                        { overridingShapeKey.value = option.key }
+                    } else {
+                        null
+                    }
+                },
+        )
+    }
+
+    private fun toGridOptionItemViewModel(
+        option: GridOptionModel
+    ): OptionItemViewModel<GridIconViewModel> {
+        val iconShapePath =
+            context.resources.getString(
+                Resources.getSystem()
+                    .getIdentifier(
+                        ResourceConstants.CONFIG_ICON_MASK,
+                        "string",
+                        ResourceConstants.ANDROID_PACKAGE,
+                    )
+            )
+        val isSelected =
+            previewingGridKey
+                .map { it == option.key }
+                .stateIn(
+                    scope = viewModelScope,
+                    started = SharingStarted.Lazily,
+                    initialValue = false,
+                )
+
+        return OptionItemViewModel(
+            key = MutableStateFlow(option.key),
+            payload =
+                GridIconViewModel(columns = option.cols, rows = option.rows, path = iconShapePath),
+            text = Text.Loaded(option.title),
+            isSelected = isSelected,
+            onClicked =
+                isSelected.map {
+                    if (!it) {
+                        { overridingGridKey.value = option.key }
+                    } else {
+                        null
+                    }
+                },
+        )
+    }
+
+    @ViewModelScoped
+    @AssistedFactory
+    interface Factory {
+        fun create(viewModelScope: CoroutineScope): ShapeGridPickerViewModel
+    }
+}
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ThemePickerCustomizationOptionsViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ThemePickerCustomizationOptionsViewModel.kt
index cc909b5..54ae132 100644
--- a/src/com/android/wallpaper/customization/ui/viewmodel/ThemePickerCustomizationOptionsViewModel.kt
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ThemePickerCustomizationOptionsViewModel.kt
@@ -16,24 +16,66 @@
 
 package com.android.wallpaper.customization.ui.viewmodel
 
+import com.android.customization.picker.mode.ui.viewmodel.DarkModeViewModel
 import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil
 import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationOptionsViewModel
+import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationOptionsViewModelFactory
 import com.android.wallpaper.picker.customization.ui.viewmodel.DefaultCustomizationOptionsViewModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
 import dagger.hilt.android.scopes.ViewModelScoped
-import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
 
-@ViewModelScoped
 class ThemePickerCustomizationOptionsViewModel
-@Inject
+@AssistedInject
 constructor(
-    private val defaultCustomizationOptionsViewModel: DefaultCustomizationOptionsViewModel
+    defaultCustomizationOptionsViewModelFactory: DefaultCustomizationOptionsViewModel.Factory,
+    keyguardQuickAffordancePickerViewModel2Factory: KeyguardQuickAffordancePickerViewModel2.Factory,
+    colorPickerViewModel2Factory: ColorPickerViewModel2.Factory,
+    clockPickerViewModelFactory: ClockPickerViewModel.Factory,
+    shapeGridPickerViewModelFactory: ShapeGridPickerViewModel.Factory,
+    val darkModeViewModel: DarkModeViewModel,
+    @Assisted private val viewModelScope: CoroutineScope,
 ) : CustomizationOptionsViewModel {
 
+    private val defaultCustomizationOptionsViewModel =
+        defaultCustomizationOptionsViewModelFactory.create(viewModelScope)
+
+    val clockPickerViewModel = clockPickerViewModelFactory.create(viewModelScope = viewModelScope)
+    val keyguardQuickAffordancePickerViewModel2 =
+        keyguardQuickAffordancePickerViewModel2Factory.create(viewModelScope = viewModelScope)
+    val colorPickerViewModel2 = colorPickerViewModel2Factory.create(viewModelScope = viewModelScope)
+    val shapeGridPickerViewModel =
+        shapeGridPickerViewModelFactory.create(viewModelScope = viewModelScope)
+
     override val selectedOption = defaultCustomizationOptionsViewModel.selectedOption
 
-    override fun deselectOption(): Boolean = defaultCustomizationOptionsViewModel.deselectOption()
+    override fun handleBackPressed(): Boolean {
+        val isBackPressedHandled = defaultCustomizationOptionsViewModel.handleBackPressed()
+
+        if (isBackPressedHandled) {
+            // If isBackPressedHandled is handled by DefaultCustomizationOptionsViewModel, it means
+            // we navigate back to the main screen from a secondary screen. Reset preview.
+            keyguardQuickAffordancePickerViewModel2.resetPreview()
+            shapeGridPickerViewModel.resetPreview()
+            clockPickerViewModel.resetPreview()
+            colorPickerViewModel2.resetPreview()
+            darkModeViewModel.resetPreview()
+        }
+
+        return isBackPressedHandled
+    }
 
     val onCustomizeClockClicked: Flow<(() -> Unit)?> =
         selectedOption.map {
@@ -61,4 +103,88 @@
                 null
             }
         }
+
+    val onCustomizeColorsClicked: Flow<(() -> Unit)?> =
+        selectedOption.map {
+            if (it == null) {
+                {
+                    defaultCustomizationOptionsViewModel.selectOption(
+                        ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption.COLORS
+                    )
+                }
+            } else {
+                null
+            }
+        }
+
+    val onCustomizeShapeGridClicked: Flow<(() -> Unit)?> =
+        selectedOption.map {
+            if (it == null) {
+                {
+                    defaultCustomizationOptionsViewModel.selectOption(
+                        ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption
+                            .APP_SHAPE_GRID
+                    )
+                }
+            } else {
+                null
+            }
+        }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    val onApplyButtonClicked: Flow<((onComplete: () -> Unit) -> Unit)?> =
+        selectedOption
+            .flatMapLatest {
+                when (it) {
+                    ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption.CLOCK ->
+                        clockPickerViewModel.onApply
+                    ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption
+                        .SHORTCUTS -> keyguardQuickAffordancePickerViewModel2.onApply
+                    ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption
+                        .APP_SHAPE_GRID -> shapeGridPickerViewModel.onApply
+                    ThemePickerCustomizationOptionUtil.ThemePickerHomeCustomizationOption.COLORS ->
+                        combine(colorPickerViewModel2.onApply, darkModeViewModel.onApply) {
+                            colorOnApply,
+                            darkModeOnApply ->
+                            {
+                                colorOnApply?.invoke()
+                                darkModeOnApply?.invoke()
+                            }
+                        }
+                    else -> flow { emit(null) }
+                }
+            }
+            .map { onApply ->
+                if (onApply != null) {
+                    fun(onComplete: () -> Unit) {
+                        viewModelScope.launch {
+                            onApply()
+                            onComplete()
+                        }
+                    }
+                } else {
+                    null
+                }
+            }
+            .stateIn(viewModelScope, SharingStarted.Eagerly, null)
+
+    val isOnApplyEnabled: Flow<Boolean> = onApplyButtonClicked.map { it != null }
+
+    val isOnApplyVisible: Flow<Boolean> = selectedOption.map { it != null }
+
+    val isToolbarCollapsed: Flow<Boolean> =
+        combine(selectedOption, clockPickerViewModel.selectedTab) { selectedOption, selectedTab ->
+                selectedOption ==
+                    ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption.CLOCK &&
+                    selectedTab == ClockPickerViewModel.Tab.FONT
+            }
+            .distinctUntilChanged()
+
+    @ViewModelScoped
+    @AssistedFactory
+    interface Factory : CustomizationOptionsViewModelFactory {
+        override fun create(
+            viewModelScope: CoroutineScope
+        ): ThemePickerCustomizationOptionsViewModel
+    }
 }
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ToolbarHeightsViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ToolbarHeightsViewModel.kt
new file mode 100644
index 0000000..0d859da
--- /dev/null
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ToolbarHeightsViewModel.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+data class ToolbarHeightsViewModel(
+    val navButtonHeight: Int? = null,
+    val toolbarHeight: Int? = null,
+    val applyButtonHeight: Int? = null,
+)
diff --git a/src/com/android/wallpaper/picker/common/preview/ui/binder/ThemePickerWorkspaceCallbackBinder.kt b/src/com/android/wallpaper/picker/common/preview/ui/binder/ThemePickerWorkspaceCallbackBinder.kt
new file mode 100644
index 0000000..6952d91
--- /dev/null
+++ b/src/com/android/wallpaper/picker/common/preview/ui/binder/ThemePickerWorkspaceCallbackBinder.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.picker.common.preview.ui.binder
+
+import android.os.Bundle
+import android.os.Message
+import androidx.core.os.bundleOf
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.customization.model.grid.DefaultShapeGridManager.Companion.COL_GRID_NAME
+import com.android.customization.model.grid.DefaultShapeGridManager.Companion.COL_SHAPE_KEY
+import com.android.customization.picker.color.data.util.MaterialColorsGenerator
+import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END
+import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.KEY_QUICK_AFFORDANCE_ID
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.KEY_SLOT_ID
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.MESSAGE_ID_DEFAULT_PREVIEW
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.MESSAGE_ID_PREVIEW_QUICK_AFFORDANCE_SELECTED
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.MESSAGE_ID_SLOT_SELECTED
+import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.MESSAGE_ID_START_CUSTOMIZING_QUICK_AFFORDANCES
+import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil.ThemePickerLockCustomizationOption
+import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
+import com.android.wallpaper.model.Screen
+import com.android.wallpaper.picker.common.preview.ui.binder.WorkspaceCallbackBinder.Companion.sendMessage
+import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
+import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationOptionsViewModel
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.launch
+
+@Singleton
+class ThemePickerWorkspaceCallbackBinder
+@Inject
+constructor(
+    private val defaultWorkspaceCallbackBinder: DefaultWorkspaceCallbackBinder,
+    private val materialColorsGenerator: MaterialColorsGenerator,
+) : WorkspaceCallbackBinder {
+
+    override fun bind(
+        workspaceCallback: Message,
+        viewModel: CustomizationOptionsViewModel,
+        colorUpdateViewModel: ColorUpdateViewModel,
+        screen: Screen,
+        lifecycleOwner: LifecycleOwner,
+    ) {
+        defaultWorkspaceCallbackBinder.bind(
+            workspaceCallback = workspaceCallback,
+            viewModel = viewModel,
+            colorUpdateViewModel = colorUpdateViewModel,
+            screen = screen,
+            lifecycleOwner = lifecycleOwner,
+        )
+
+        if (viewModel !is ThemePickerCustomizationOptionsViewModel) {
+            throw IllegalArgumentException(
+                "viewModel $viewModel is not a ThemePickerCustomizationOptionsViewModel."
+            )
+        }
+
+        when (screen) {
+            Screen.LOCK_SCREEN ->
+                lifecycleOwner.lifecycleScope.launch {
+                    lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                        launch {
+                            viewModel.selectedOption.collect {
+                                when (it) {
+                                    ThemePickerLockCustomizationOption.SHORTCUTS ->
+                                        workspaceCallback.sendMessage(
+                                            MESSAGE_ID_START_CUSTOMIZING_QUICK_AFFORDANCES,
+                                            Bundle().apply {
+                                                putString(
+                                                    KEY_INITIALLY_SELECTED_SLOT_ID,
+                                                    SLOT_ID_BOTTOM_START,
+                                                )
+                                            },
+                                        )
+                                    else ->
+                                        workspaceCallback.sendMessage(
+                                            MESSAGE_ID_DEFAULT_PREVIEW,
+                                            Bundle.EMPTY,
+                                        )
+                                }
+                            }
+                        }
+
+                        launch {
+                            viewModel.keyguardQuickAffordancePickerViewModel2.selectedSlotId
+                                .collect {
+                                    workspaceCallback.sendMessage(
+                                        MESSAGE_ID_SLOT_SELECTED,
+                                        Bundle().apply { putString(KEY_SLOT_ID, it) },
+                                    )
+                                }
+                        }
+
+                        launch {
+                            viewModel.keyguardQuickAffordancePickerViewModel2
+                                .previewingQuickAffordances
+                                .collect {
+                                    it[SLOT_ID_BOTTOM_START]?.let {
+                                        workspaceCallback.sendMessage(
+                                            MESSAGE_ID_PREVIEW_QUICK_AFFORDANCE_SELECTED,
+                                            Bundle().apply {
+                                                putString(KEY_SLOT_ID, SLOT_ID_BOTTOM_START)
+                                                putString(KEY_QUICK_AFFORDANCE_ID, it)
+                                            },
+                                        )
+                                    }
+                                    it[SLOT_ID_BOTTOM_END]?.let {
+                                        workspaceCallback.sendMessage(
+                                            MESSAGE_ID_PREVIEW_QUICK_AFFORDANCE_SELECTED,
+                                            Bundle().apply {
+                                                putString(KEY_SLOT_ID, SLOT_ID_BOTTOM_END)
+                                                putString(KEY_QUICK_AFFORDANCE_ID, it)
+                                            },
+                                        )
+                                    }
+                                }
+                        }
+                    }
+                }
+            Screen.HOME_SCREEN ->
+                lifecycleOwner.lifecycleScope.launch {
+                    lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                        launch {
+                            viewModel.shapeGridPickerViewModel.previewingShapeKey.collect {
+                                workspaceCallback.sendMessage(
+                                    MESSAGE_ID_UPDATE_SHAPE,
+                                    bundleOf(COL_SHAPE_KEY to it),
+                                )
+                            }
+                        }
+
+                        launch {
+                            viewModel.shapeGridPickerViewModel.previewingGridKey.collect {
+                                workspaceCallback.sendMessage(
+                                    MESSAGE_ID_UPDATE_GRID,
+                                    bundleOf(COL_GRID_NAME to it),
+                                )
+                            }
+                        }
+
+                        launch {
+                            combine(
+                                    viewModel.colorPickerViewModel2.previewingColorOption,
+                                    viewModel.darkModeViewModel.overridingIsDarkMode,
+                                    colorUpdateViewModel.systemColorsUpdated,
+                                    ::Triple,
+                                )
+                                .collect { (colorModel, darkMode, _) ->
+                                    val bundle =
+                                        Bundle().apply {
+                                            if (colorModel != null) {
+                                                val (ids, colors) =
+                                                    materialColorsGenerator.generate(
+                                                        colorModel.colorOption.seedColor,
+                                                        colorModel.colorOption.style,
+                                                    )
+                                                putIntArray(KEY_COLOR_RESOURCE_IDS, ids)
+                                                putIntArray(KEY_COLOR_VALUES, colors)
+                                            }
+
+                                            if (darkMode != null) {
+                                                putBoolean(KEY_DARK_MODE, darkMode)
+                                            }
+                                        }
+                                    workspaceCallback.sendMessage(MESSAGE_ID_UPDATE_COLOR, bundle)
+                                }
+                        }
+                    }
+                }
+        }
+    }
+
+    companion object {
+        const val MESSAGE_ID_UPDATE_SHAPE = 2586
+        const val MESSAGE_ID_UPDATE_GRID = 7414
+
+        const val MESSAGE_ID_UPDATE_COLOR = 856
+        const val KEY_COLOR_RESOURCE_IDS: String = "color_resource_ids"
+        const val KEY_COLOR_VALUES: String = "color_values"
+        const val KEY_DARK_MODE: String = "use_dark_mode"
+    }
+}
diff --git a/src_override/com/android/wallpaper/picker/di/modules/EffectsModule.kt b/src/com/android/wallpaper/picker/di/modules/ThemePickerSharedAppModule.kt
similarity index 63%
rename from src_override/com/android/wallpaper/picker/di/modules/EffectsModule.kt
rename to src/com/android/wallpaper/picker/di/modules/ThemePickerSharedAppModule.kt
index 4fc0fbb..98c881f 100644
--- a/src_override/com/android/wallpaper/picker/di/modules/EffectsModule.kt
+++ b/src/com/android/wallpaper/picker/di/modules/ThemePickerSharedAppModule.kt
@@ -13,22 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.wallpaper.picker.di.modules
 
-import com.android.wallpaper.effects.DefaultEffectsController
-import com.android.wallpaper.effects.EffectsController
+import com.android.customization.model.grid.DefaultShapeGridManager
+import com.android.customization.model.grid.ShapeGridManager
+import com.android.customization.picker.mode.shared.util.DarkModeUtil
+import com.android.customization.picker.mode.shared.util.DarkModeUtilImpl
 import dagger.Binds
 import dagger.Module
 import dagger.hilt.InstallIn
 import dagger.hilt.components.SingletonComponent
 import javax.inject.Singleton
 
-/** This class provides the singleton scoped effects controller for wallpaper picker. */
-@InstallIn(SingletonComponent::class)
 @Module
-abstract class EffectsModule {
+@InstallIn(SingletonComponent::class)
+abstract class ThemePickerSharedAppModule {
 
     @Binds
     @Singleton
-    abstract fun bindEffectsController(impl: DefaultEffectsController): EffectsController
+    abstract fun bindGridOptionsManager2(impl: DefaultShapeGridManager): ShapeGridManager
+
+    @Binds @Singleton abstract fun bindDarkModeUtil(impl: DarkModeUtilImpl): DarkModeUtil
 }
diff --git a/src_override/com/android/wallpaper/modules/ThemePickerActivityModule.kt b/src_override/com/android/wallpaper/modules/ThemePickerActivityModule.kt
index 90a0e3b..31213e5 100644
--- a/src_override/com/android/wallpaper/modules/ThemePickerActivityModule.kt
+++ b/src_override/com/android/wallpaper/modules/ThemePickerActivityModule.kt
@@ -16,6 +16,8 @@
 
 package com.android.wallpaper.modules
 
+import com.android.customization.picker.clock.ui.view.ClockViewFactory
+import com.android.customization.picker.clock.ui.view.ThemePickerClockViewFactory
 import com.android.wallpaper.customization.ui.util.ThemePickerCustomizationOptionUtil
 import com.android.wallpaper.picker.customization.ui.util.CustomizationOptionUtil
 import dagger.Binds
@@ -30,6 +32,10 @@
 
     @Binds
     @ActivityScoped
+    abstract fun bindClockViewFactory(impl: ThemePickerClockViewFactory): ClockViewFactory
+
+    @Binds
+    @ActivityScoped
     abstract fun bindCustomizationOptionUtil(
         impl: ThemePickerCustomizationOptionUtil
     ): CustomizationOptionUtil
diff --git a/src_override/com/android/wallpaper/modules/ThemePickerActivityRetainedModule.kt b/src_override/com/android/wallpaper/modules/ThemePickerActivityRetainedModule.kt
new file mode 100644
index 0000000..9462c6a
--- /dev/null
+++ b/src_override/com/android/wallpaper/modules/ThemePickerActivityRetainedModule.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.modules
+
+import com.android.wallpaper.picker.preview.data.util.DefaultLiveWallpaperDownloader
+import com.android.wallpaper.picker.preview.data.util.LiveWallpaperDownloader
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityRetainedComponent
+import dagger.hilt.android.scopes.ActivityRetainedScoped
+
+@Module
+@InstallIn(ActivityRetainedComponent::class)
+abstract class ThemePickerActivityRetainedModule {
+
+    @Binds
+    @ActivityRetainedScoped
+    abstract fun bindLiveWallpaperDownloader(
+        impl: DefaultLiveWallpaperDownloader
+    ): LiveWallpaperDownloader
+}
diff --git a/src_override/com/android/wallpaper/modules/ThemePickerAppModule.kt b/src_override/com/android/wallpaper/modules/ThemePickerAppModule.kt
index ab1541c..1c4ecc9 100644
--- a/src_override/com/android/wallpaper/modules/ThemePickerAppModule.kt
+++ b/src_override/com/android/wallpaper/modules/ThemePickerAppModule.kt
@@ -23,14 +23,44 @@
 import com.android.customization.module.ThemePickerInjector
 import com.android.customization.module.logging.ThemesUserEventLogger
 import com.android.customization.module.logging.ThemesUserEventLoggerImpl
+import com.android.customization.picker.clock.data.repository.ClockPickerRepository
+import com.android.customization.picker.clock.data.repository.ClockPickerRepositoryImpl
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
+import com.android.customization.picker.color.data.repository.ColorPickerRepository
+import com.android.customization.picker.color.data.repository.ColorPickerRepositoryImpl
+import com.android.systemui.shared.clocks.ClockRegistry
+import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
+import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
+import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
+import com.android.systemui.shared.settings.data.repository.SecureSettingsRepositoryImpl
+import com.android.systemui.shared.settings.data.repository.SystemSettingsRepository
+import com.android.systemui.shared.settings.data.repository.SystemSettingsRepositoryImpl
 import com.android.wallpaper.customization.ui.binder.ThemePickerCustomizationOptionsBinder
+import com.android.wallpaper.customization.ui.binder.ThemePickerToolbarBinder
+import com.android.wallpaper.effects.DefaultEffectsController
+import com.android.wallpaper.effects.EffectsController
 import com.android.wallpaper.module.DefaultPartnerProvider
 import com.android.wallpaper.module.PartnerProvider
 import com.android.wallpaper.module.WallpaperPreferences
 import com.android.wallpaper.module.logging.UserEventLogger
+import com.android.wallpaper.picker.category.domain.interactor.CategoriesLoadingStatusInteractor
+import com.android.wallpaper.picker.category.domain.interactor.CategoryInteractor
+import com.android.wallpaper.picker.category.domain.interactor.CreativeCategoryInteractor
+import com.android.wallpaper.picker.category.domain.interactor.ThirdPartyCategoryInteractor
+import com.android.wallpaper.picker.category.domain.interactor.implementations.CategoryInteractorImpl
+import com.android.wallpaper.picker.category.domain.interactor.implementations.CreativeCategoryInteractorImpl
+import com.android.wallpaper.picker.category.domain.interactor.implementations.DefaultCategoriesLoadingStatusInteractor
+import com.android.wallpaper.picker.category.domain.interactor.implementations.ThirdPartyCategoryInteractorImpl
+import com.android.wallpaper.picker.category.ui.view.providers.IndividualPickerFactory
+import com.android.wallpaper.picker.category.ui.view.providers.implementation.DefaultIndividualPickerFactory
+import com.android.wallpaper.picker.category.wrapper.DefaultWallpaperCategoryWrapper
+import com.android.wallpaper.picker.category.wrapper.WallpaperCategoryWrapper
+import com.android.wallpaper.picker.common.preview.ui.binder.ThemePickerWorkspaceCallbackBinder
+import com.android.wallpaper.picker.common.preview.ui.binder.WorkspaceCallbackBinder
 import com.android.wallpaper.picker.customization.ui.binder.CustomizationOptionsBinder
-import com.android.wallpaper.picker.preview.data.util.DefaultLiveWallpaperDownloader
-import com.android.wallpaper.picker.preview.data.util.LiveWallpaperDownloader
+import com.android.wallpaper.picker.customization.ui.binder.ToolbarBinder
+import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
+import com.android.wallpaper.picker.di.modules.MainDispatcher
 import com.android.wallpaper.picker.preview.ui.util.DefaultImageEffectDialogUtil
 import com.android.wallpaper.picker.preview.ui.util.ImageEffectDialogUtil
 import com.android.wallpaper.util.converter.DefaultWallpaperModelFactory
@@ -42,15 +72,72 @@
 import dagger.hilt.android.qualifiers.ApplicationContext
 import dagger.hilt.components.SingletonComponent
 import javax.inject.Singleton
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 
 @Module
 @InstallIn(SingletonComponent::class)
 abstract class ThemePickerAppModule {
-    @Binds @Singleton abstract fun bindInjector(impl: ThemePickerInjector): CustomizationInjector
 
     @Binds
     @Singleton
-    abstract fun bindUserEventLogger(impl: ThemesUserEventLoggerImpl): UserEventLogger
+    abstract fun bindClockPickerRepository(impl: ClockPickerRepositoryImpl): ClockPickerRepository
+
+    @Binds
+    @Singleton
+    abstract fun bindColorPickerRepository(impl: ColorPickerRepositoryImpl): ColorPickerRepository
+
+    @Binds
+    @Singleton
+    abstract fun bindCreativeCategoryInteractor(
+        impl: CreativeCategoryInteractorImpl
+    ): CreativeCategoryInteractor
+
+    @Binds
+    @Singleton
+    abstract fun bindWallpaperCategoryWrapper(
+        impl: DefaultWallpaperCategoryWrapper
+    ): WallpaperCategoryWrapper
+
+    @Binds
+    @Singleton
+    abstract fun bindCustomizationInjector(impl: ThemePickerInjector): CustomizationInjector
+
+    @Binds
+    @Singleton
+    abstract fun bindCustomizationOptionsBinder(
+        impl: ThemePickerCustomizationOptionsBinder
+    ): CustomizationOptionsBinder
+
+    @Binds
+    @Singleton
+    abstract fun bindEffectsController(impl: DefaultEffectsController): EffectsController
+
+    @Binds
+    @Singleton
+    abstract fun bindGoogleCategoryInteractor(impl: CategoryInteractorImpl): CategoryInteractor
+
+    @Binds
+    @Singleton
+    abstract fun bindImageEffectDialogUtil(
+        impl: DefaultImageEffectDialogUtil
+    ): ImageEffectDialogUtil
+
+    @Binds
+    @Singleton
+    abstract fun bindIndividualPickerFactoryFragment(
+        impl: DefaultIndividualPickerFactory
+    ): IndividualPickerFactory
+
+    @Binds
+    @Singleton
+    abstract fun bindLoadingStatusInteractor(
+        impl: DefaultCategoriesLoadingStatusInteractor
+    ): CategoriesLoadingStatusInteractor
+
+    @Binds
+    @Singleton
+    abstract fun bindPartnerProvider(impl: DefaultPartnerProvider): PartnerProvider
 
     @Binds
     @Singleton
@@ -58,39 +145,51 @@
 
     @Binds
     @Singleton
+    abstract fun bindThirdPartyCategoryInteractor(
+        impl: ThirdPartyCategoryInteractorImpl
+    ): ThirdPartyCategoryInteractor
+
+    @Binds @Singleton abstract fun bindToolbarBinder(impl: ThemePickerToolbarBinder): ToolbarBinder
+
+    @Binds
+    @Singleton
+    abstract fun bindUserEventLogger(impl: ThemesUserEventLoggerImpl): UserEventLogger
+
+    @Binds
+    @Singleton
     abstract fun bindWallpaperModelFactory(
         impl: DefaultWallpaperModelFactory
     ): WallpaperModelFactory
 
     @Binds
     @Singleton
-    abstract fun bindLiveWallpaperDownloader(
-        impl: DefaultLiveWallpaperDownloader
-    ): LiveWallpaperDownloader
+    abstract fun bindWallpaperPreferences(
+        impl: DefaultCustomizationPreferences
+    ): WallpaperPreferences
 
     @Binds
     @Singleton
-    abstract fun bindPartnerProvider(impl: DefaultPartnerProvider): PartnerProvider
-
-    @Binds
-    @Singleton
-    abstract fun bindEffectsWallpaperDialogUtil(
-        impl: DefaultImageEffectDialogUtil
-    ): ImageEffectDialogUtil
-
-    @Binds
-    @Singleton
-    abstract fun bindCustomizationOptionsBinder(
-        impl: ThemePickerCustomizationOptionsBinder
-    ): CustomizationOptionsBinder
+    abstract fun bindWorkspaceCallbackBinder(
+        impl: ThemePickerWorkspaceCallbackBinder
+    ): WorkspaceCallbackBinder
 
     companion object {
+
         @Provides
         @Singleton
-        fun provideWallpaperPreferences(
-            @ApplicationContext context: Context
-        ): WallpaperPreferences {
-            return DefaultCustomizationPreferences(context)
+        fun provideClockRegistry(
+            @ApplicationContext context: Context,
+            @MainDispatcher mainScope: CoroutineScope,
+            @MainDispatcher mainDispatcher: CoroutineDispatcher,
+            @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
+        ): ClockRegistry {
+            return ClockRegistryProvider(
+                    context = context,
+                    coroutineScope = mainScope,
+                    mainDispatcher = mainDispatcher,
+                    backgroundDispatcher = bgDispatcher,
+                )
+                .get()
         }
 
         @Provides
@@ -100,5 +199,32 @@
         ): ColorCustomizationManager {
             return ColorCustomizationManager.getInstance(context, OverlayManagerCompat(context))
         }
+
+        @Provides
+        @Singleton
+        fun provideCustomizationProviderClient(
+            @ApplicationContext context: Context,
+            @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
+        ): CustomizationProviderClient {
+            return CustomizationProviderClientImpl(context, bgDispatcher)
+        }
+
+        @Provides
+        @Singleton
+        fun provideSecureSettingsRepository(
+            @ApplicationContext context: Context,
+            @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
+        ): SecureSettingsRepository {
+            return SecureSettingsRepositoryImpl(context.contentResolver, bgDispatcher)
+        }
+
+        @Provides
+        @Singleton
+        fun provideSystemSettingsRepository(
+            @ApplicationContext context: Context,
+            @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
+        ): SystemSettingsRepository {
+            return SystemSettingsRepositoryImpl(context.contentResolver, bgDispatcher)
+        }
     }
 }
diff --git a/src_override/com/android/wallpaper/modules/ThemePickerViewModelModule.kt b/src_override/com/android/wallpaper/modules/ThemePickerViewModelModule.kt
index 3a80437..3a2da15 100644
--- a/src_override/com/android/wallpaper/modules/ThemePickerViewModelModule.kt
+++ b/src_override/com/android/wallpaper/modules/ThemePickerViewModelModule.kt
@@ -17,7 +17,7 @@
 package com.android.wallpaper.modules
 
 import com.android.wallpaper.customization.ui.viewmodel.ThemePickerCustomizationOptionsViewModel
-import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationOptionsViewModel
+import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationOptionsViewModelFactory
 import dagger.Binds
 import dagger.Module
 import dagger.hilt.InstallIn
@@ -30,7 +30,7 @@
 
     @Binds
     @ViewModelScoped
-    abstract fun bindCustomizationOptionsViewModel(
-        impl: ThemePickerCustomizationOptionsViewModel
-    ): CustomizationOptionsViewModel
+    abstract fun bindCustomizationOptionsViewModelFactory(
+        impl: ThemePickerCustomizationOptionsViewModel.Factory
+    ): CustomizationOptionsViewModelFactory
 }
diff --git a/src_override/com/android/wallpaper/picker/di/modules/InteractorModule.kt b/src_override/com/android/wallpaper/picker/di/modules/InteractorModule.kt
deleted file mode 100644
index 81edb2f..0000000
--- a/src_override/com/android/wallpaper/picker/di/modules/InteractorModule.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.wallpaper.picker.di.modules
-
-import android.text.TextUtils
-import com.android.customization.model.color.ColorCustomizationManager
-import com.android.customization.model.color.ColorOptionsProvider.COLOR_SOURCE_PRESET
-import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository
-import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import javax.inject.Singleton
-
-/** This class provides the singleton scoped interactors for theme picker. */
-@InstallIn(SingletonComponent::class)
-@Module
-internal object InteractorModule {
-
-    @Provides
-    @Singleton
-    fun provideWallpaperInteractor(
-        wallpaperRepository: WallpaperRepository,
-        colorCustomizationManager: ColorCustomizationManager,
-    ): WallpaperInteractor {
-        return WallpaperInteractor(wallpaperRepository) {
-            TextUtils.equals(colorCustomizationManager.currentColorSource, COLOR_SOURCE_PRESET)
-        }
-    }
-}
diff --git a/tests/common/src/com/android/customization/model/grid/FakeShapeGridManager.kt b/tests/common/src/com/android/customization/model/grid/FakeShapeGridManager.kt
new file mode 100644
index 0000000..b1f044a
--- /dev/null
+++ b/tests/common/src/com/android/customization/model/grid/FakeShapeGridManager.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.model.grid
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class FakeShapeGridManager @Inject constructor() : ShapeGridManager {
+
+    private var gridOptions: List<GridOptionModel>? = DEFAULT_GRID_OPTION_LIST
+
+    private var shapeOptions: List<ShapeOptionModel>? = DEFAULT_SHAPE_OPTION_LIST
+
+    override suspend fun getGridOptions(): List<GridOptionModel>? = gridOptions
+
+    override suspend fun getShapeOptions(): List<ShapeOptionModel>? = shapeOptions
+
+    override fun applyShapeGridOption(shapeKey: String, gridKey: String): Int {
+        shapeOptions = shapeOptions?.map { it.copy(isCurrent = it.key == shapeKey) }
+        gridOptions = gridOptions?.map { it.copy(isCurrent = it.key == gridKey) }
+        return 0
+    }
+
+    companion object {
+        val DEFAULT_GRID_OPTION_LIST =
+            listOf(
+                GridOptionModel(
+                    key = "normal",
+                    title = "5x5",
+                    isCurrent = true,
+                    rows = 5,
+                    cols = 5,
+                ),
+                GridOptionModel(
+                    key = "practical",
+                    title = "4x5",
+                    isCurrent = false,
+                    rows = 5,
+                    cols = 4,
+                ),
+            )
+
+        val DEFAULT_SHAPE_OPTION_LIST =
+            listOf(
+                ShapeOptionModel(
+                    key = "arch",
+                    title = "arch",
+                    path =
+                        "M100 83.46C100 85.471 100 86.476 99.9 87.321 99.116 93.916 93.916 99.116 87.321 99.9 86.476 100 85.471 100 83.46 100H16.54C14.529 100 13.524 100 12.679 99.9 6.084 99.116.884 93.916.1 87.321 0 86.476 0 85.471 0 83.46L0 50C0 22.386 22.386 0 50 0 77.614 0 100 22.386 100 50V83.46Z",
+                    isCurrent = true,
+                ),
+                ShapeOptionModel(
+                    key = "4-sided-cookie",
+                    title = "4-sided-cookie",
+                    path =
+                        "M63.605 3C84.733-6.176 106.176 15.268 97 36.395L95.483 39.888C92.681 46.338 92.681 53.662 95.483 60.112L97 63.605C106.176 84.732 84.733 106.176 63.605 97L60.112 95.483C53.662 92.681 46.338 92.681 39.888 95.483L36.395 97C15.267 106.176-6.176 84.732 3 63.605L4.517 60.112C7.319 53.662 7.319 46.338 4.517 39.888L3 36.395C-6.176 15.268 15.267-6.176 36.395 3L39.888 4.517C46.338 7.319 53.662 7.319 60.112 4.517L63.605 3Z",
+                    isCurrent = false,
+                ),
+                ShapeOptionModel(
+                    key = "7-sided-cookie",
+                    title = "7-sided-cookie",
+                    path =
+                        "M35.209 4.878C36.326 3.895 36.884 3.404 37.397 3.006 44.82-2.742 55.18-2.742 62.603 3.006 63.116 3.404 63.674 3.895 64.791 4.878 65.164 5.207 65.351 5.371 65.539 5.529 68.167 7.734 71.303 9.248 74.663 9.932 74.902 9.981 75.147 10.025 75.637 10.113 77.1 10.375 77.831 10.506 78.461 10.66 87.573 12.893 94.032 21.011 94.176 30.412 94.186 31.062 94.151 31.805 94.08 33.293 94.057 33.791 94.045 34.04 94.039 34.285 93.958 37.72 94.732 41.121 96.293 44.18 96.404 44.399 96.522 44.618 96.759 45.056 97.467 46.366 97.821 47.021 98.093 47.611 102.032 56.143 99.727 66.266 92.484 72.24 91.983 72.653 91.381 73.089 90.177 73.961 89.774 74.254 89.572 74.4 89.377 74.548 86.647 76.626 84.477 79.353 83.063 82.483 82.962 82.707 82.865 82.936 82.671 83.395 82.091 84.766 81.8 85.451 81.51 86.033 77.31 94.44 67.977 98.945 58.801 96.994 58.166 96.859 57.451 96.659 56.019 96.259 55.54 96.125 55.3 96.058 55.063 95.998 51.74 95.154 48.26 95.154 44.937 95.998 44.699 96.058 44.46 96.125 43.981 96.259 42.549 96.659 41.834 96.859 41.199 96.994 32.023 98.945 22.69 94.44 18.49 86.033 18.2 85.451 17.909 84.766 17.329 83.395 17.135 82.936 17.038 82.707 16.937 82.483 15.523 79.353 13.353 76.626 10.623 74.548 10.428 74.4 10.226 74.254 9.823 73.961 8.619 73.089 8.017 72.653 7.516 72.24.273 66.266-2.032 56.143 1.907 47.611 2.179 47.021 2.533 46.366 3.241 45.056 3.478 44.618 3.596 44.399 3.707 44.18 5.268 41.121 6.042 37.72 5.961 34.285 5.955 34.04 5.943 33.791 5.92 33.293 5.849 31.805 5.814 31.062 5.824 30.412 5.968 21.011 12.427 12.893 21.539 10.66 22.169 10.506 22.9 10.375 24.363 10.113 24.853 10.025 25.098 9.981 25.337 9.932 28.697 9.248 31.833 7.734 34.461 5.529 34.649 5.371 34.836 5.207 35.209 4.878Z",
+                    isCurrent = false,
+                ),
+                ShapeOptionModel(
+                    key = "sunny",
+                    title = "sunny",
+                    path =
+                        "M42.846 4.873C46.084-.531 53.916-.531 57.154 4.873L60.796 10.951C62.685 14.103 66.414 15.647 69.978 14.754L76.851 13.032C82.962 11.5 88.5 17.038 86.968 23.149L85.246 30.022C84.353 33.586 85.897 37.315 89.049 39.204L95.127 42.846C100.531 46.084 100.531 53.916 95.127 57.154L89.049 60.796C85.897 62.685 84.353 66.414 85.246 69.978L86.968 76.851C88.5 82.962 82.962 88.5 76.851 86.968L69.978 85.246C66.414 84.353 62.685 85.898 60.796 89.049L57.154 95.127C53.916 100.531 46.084 100.531 42.846 95.127L39.204 89.049C37.315 85.898 33.586 84.353 30.022 85.246L23.149 86.968C17.038 88.5 11.5 82.962 13.032 76.851L14.754 69.978C15.647 66.414 14.103 62.685 10.951 60.796L4.873 57.154C-.531 53.916-.531 46.084 4.873 42.846L10.951 39.204C14.103 37.315 15.647 33.586 14.754 30.022L13.032 23.149C11.5 17.038 17.038 11.5 23.149 13.032L30.022 14.754C33.586 15.647 37.315 14.103 39.204 10.951L42.846 4.873Z",
+                    isCurrent = false,
+                ),
+                ShapeOptionModel(
+                    key = "circle",
+                    title = "circle",
+                    path =
+                        "M99.18 50C99.18 77.162 77.162 99.18 50 99.18 22.838 99.18.82 77.162.82 50 .82 22.839 22.838.82 50 .82 77.162.82 99.18 22.839 99.18 50Z",
+                    isCurrent = false,
+                ),
+                ShapeOptionModel(
+                    key = "square",
+                    title = "square",
+                    path =
+                        "M99.18 53.689C99.18 67.434 99.18 74.306 97.022 79.758 93.897 87.649 87.649 93.897 79.758 97.022 74.306 99.18 67.434 99.18 53.689 99.18H46.311C32.566 99.18 25.694 99.18 20.242 97.022 12.351 93.897 6.103 87.649 2.978 79.758.82 74.306.82 67.434.82 53.689L.82 46.311C.82 32.566.82 25.694 2.978 20.242 6.103 12.351 12.351 6.103 20.242 2.978 25.694.82 32.566.82 46.311.82L53.689.82C67.434.82 74.306.82 79.758 2.978 87.649 6.103 93.897 12.351 97.022 20.242 99.18 25.694 99.18 32.566 99.18 46.311V53.689Z",
+                    isCurrent = false,
+                ),
+            )
+    }
+}
diff --git a/tests/common/src/com/android/customization/module/logging/TestThemesUserEventLogger.kt b/tests/common/src/com/android/customization/module/logging/TestThemesUserEventLogger.kt
index 8e9dacd..05c95b0 100644
--- a/tests/common/src/com/android/customization/module/logging/TestThemesUserEventLogger.kt
+++ b/tests/common/src/com/android/customization/module/logging/TestThemesUserEventLogger.kt
@@ -31,11 +31,18 @@
     @ColorSource
     var themeColorSource: Int = StyleEnums.COLOR_SOURCE_UNSPECIFIED
         private set
+
     var themeColorStyle: Int = -1
         private set
+
     var themeSeedColor: Int = -1
         private set
 
+    var shortcutLogs: List<Pair<String, String>> = emptyList()
+
+    var useDarkTheme: Boolean = false
+        private set
+
     override fun logThemeColorApplied(@ColorSource source: Int, style: Int, seedColor: Int) {
         this.themeColorSource = source
         this.themeColorStyle = style
@@ -56,9 +63,13 @@
 
     override fun logLockScreenNotificationApplied(showLockScreenNotifications: Boolean) {}
 
-    override fun logShortcutApplied(shortcut: String, shortcutSlotId: String) {}
+    override fun logShortcutApplied(shortcut: String, shortcutSlotId: String) {
+        shortcutLogs = shortcutLogs.toMutableList().apply { add(shortcut to shortcutSlotId) }
+    }
 
-    override fun logDarkThemeApplied(useDarkTheme: Boolean) {}
+    override fun logDarkThemeApplied(useDarkTheme: Boolean) {
+        this.useDarkTheme = useDarkTheme
+    }
 
     @ClockSize
     fun getLoggedClockSize(): Int {
diff --git a/tests/common/src/com/android/customization/testing/TestCustomizationInjector.kt b/tests/common/src/com/android/customization/testing/TestCustomizationInjector.kt
index caa5029..a550119 100644
--- a/tests/common/src/com/android/customization/testing/TestCustomizationInjector.kt
+++ b/tests/common/src/com/android/customization/testing/TestCustomizationInjector.kt
@@ -12,13 +12,19 @@
 import com.android.customization.picker.clock.ui.view.ClockViewFactory
 import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
 import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
-import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
 import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel
 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
-import com.android.systemui.shared.clocks.ClockRegistry
+import com.android.wallpaper.module.NetworkStatusNotifier
+import com.android.wallpaper.module.PartnerProvider
+import com.android.wallpaper.module.WallpaperPreferences
 import com.android.wallpaper.module.logging.UserEventLogger
+import com.android.wallpaper.network.Requester
+import com.android.wallpaper.picker.category.wrapper.WallpaperCategoryWrapper
 import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository
+import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor
+import com.android.wallpaper.testing.FakeWallpaperClient
 import com.android.wallpaper.testing.TestInjector
+import com.android.wallpaper.util.DisplayUtils
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -27,8 +33,28 @@
 @Inject
 constructor(
     private val customPrefs: TestDefaultCustomizationPreferences,
-    private val themesUserEventLogger: ThemesUserEventLogger
-) : TestInjector(themesUserEventLogger), CustomizationInjector {
+    private val themesUserEventLogger: ThemesUserEventLogger,
+    displayUtils: DisplayUtils,
+    requester: Requester,
+    networkStatusNotifier: NetworkStatusNotifier,
+    partnerProvider: PartnerProvider,
+    wallpaperClient: FakeWallpaperClient,
+    injectedWallpaperInteractor: WallpaperInteractor,
+    prefs: WallpaperPreferences,
+    private val fakeWallpaperCategoryWrapper: WallpaperCategoryWrapper,
+) :
+    TestInjector(
+        themesUserEventLogger,
+        displayUtils,
+        requester,
+        networkStatusNotifier,
+        partnerProvider,
+        wallpaperClient,
+        injectedWallpaperInteractor,
+        prefs,
+        fakeWallpaperCategoryWrapper,
+    ),
+    CustomizationInjector {
     /////////////////
     // CustomizationInjector implementations
     /////////////////
@@ -43,32 +69,14 @@
         throw UnsupportedOperationException("not implemented")
     }
 
-    override fun getClockRegistry(context: Context): ClockRegistry? {
-        throw UnsupportedOperationException("not implemented")
-    }
-
-    override fun getClockPickerInteractor(context: Context): ClockPickerInteractor {
-        throw UnsupportedOperationException("not implemented")
-    }
-
     override fun getWallpaperColorResources(
         wallpaperColors: WallpaperColors,
-        context: Context
+        context: Context,
     ): WallpaperColorResources {
         throw UnsupportedOperationException("not implemented")
     }
 
-    override fun getColorPickerInteractor(
-        context: Context,
-        wallpaperColorsRepository: WallpaperColorsRepository,
-    ): ColorPickerInteractor {
-        throw UnsupportedOperationException("not implemented")
-    }
-
-    override fun getColorPickerViewModelFactory(
-        context: Context,
-        wallpaperColorsRepository: WallpaperColorsRepository,
-    ): ColorPickerViewModel.Factory {
+    override fun getColorPickerViewModelFactory(context: Context): ColorPickerViewModel.Factory {
         throw UnsupportedOperationException("not implemented")
     }
 
@@ -99,4 +107,8 @@
     override fun getUserEventLogger(): UserEventLogger {
         return themesUserEventLogger
     }
+
+    override fun getWallpaperCategoryWrapper(): WallpaperCategoryWrapper {
+        return fakeWallpaperCategoryWrapper
+    }
 }
diff --git a/tests/common/src/com/android/wallpaper/di/modules/ThemePickerSharedAppTestModule.kt b/tests/common/src/com/android/wallpaper/di/modules/ThemePickerSharedAppTestModule.kt
new file mode 100644
index 0000000..4969db4
--- /dev/null
+++ b/tests/common/src/com/android/wallpaper/di/modules/ThemePickerSharedAppTestModule.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.di.modules
+
+import com.android.customization.model.grid.FakeShapeGridManager
+import com.android.customization.model.grid.ShapeGridManager
+import com.android.customization.picker.mode.shared.util.DarkModeUtil
+import com.android.customization.picker.mode.shared.util.FakeDarkModeUtil
+import com.android.wallpaper.picker.di.modules.ThemePickerSharedAppModule
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.components.SingletonComponent
+import dagger.hilt.testing.TestInstallIn
+import javax.inject.Singleton
+
+@Module
+@TestInstallIn(
+    components = [SingletonComponent::class],
+    replaces = [ThemePickerSharedAppModule::class],
+)
+abstract class ThemePickerSharedAppTestModule {
+
+    @Binds
+    @Singleton
+    abstract fun bindGridOptionsManager2(impl: FakeShapeGridManager): ShapeGridManager
+
+    @Binds @Singleton abstract fun bindDarkModeUtil(impl: FakeDarkModeUtil): DarkModeUtil
+}
diff --git a/tests/module/src/com/android/wallpaper/ThemePickerTestModule.kt b/tests/module/src/com/android/wallpaper/ThemePickerTestModule.kt
index 5ed8962..94af717 100644
--- a/tests/module/src/com/android/wallpaper/ThemePickerTestModule.kt
+++ b/tests/module/src/com/android/wallpaper/ThemePickerTestModule.kt
@@ -15,6 +15,7 @@
  */
 package com.android.wallpaper
 
+import android.content.Context
 import androidx.test.core.app.ApplicationProvider
 import com.android.customization.model.color.ColorCustomizationManager
 import com.android.customization.model.theme.OverlayManagerCompat
@@ -22,8 +23,19 @@
 import com.android.customization.module.CustomizationPreferences
 import com.android.customization.module.logging.TestThemesUserEventLogger
 import com.android.customization.module.logging.ThemesUserEventLogger
+import com.android.customization.picker.clock.data.repository.ClockPickerRepository
+import com.android.customization.picker.clock.data.repository.ClockPickerRepositoryImpl
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
+import com.android.customization.picker.color.data.repository.ColorPickerRepository
+import com.android.customization.picker.color.data.repository.ColorPickerRepositoryImpl
 import com.android.customization.testing.TestCustomizationInjector
 import com.android.customization.testing.TestDefaultCustomizationPreferences
+import com.android.systemui.shared.clocks.ClockRegistry
+import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
+import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
+import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
+import com.android.systemui.shared.settings.data.repository.SecureSettingsRepositoryImpl
+import com.android.wallpaper.customization.ui.binder.ThemePickerToolbarBinder
 import com.android.wallpaper.effects.EffectsController
 import com.android.wallpaper.effects.FakeEffectsController
 import com.android.wallpaper.module.Injector
@@ -33,47 +45,44 @@
 import com.android.wallpaper.module.logging.UserEventLogger
 import com.android.wallpaper.modules.ThemePickerAppModule
 import com.android.wallpaper.network.Requester
+import com.android.wallpaper.picker.category.domain.interactor.ThirdPartyCategoryInteractor
+import com.android.wallpaper.picker.category.wrapper.WallpaperCategoryWrapper
+import com.android.wallpaper.picker.common.preview.ui.binder.ThemePickerWorkspaceCallbackBinder
+import com.android.wallpaper.picker.common.preview.ui.binder.WorkspaceCallbackBinder
 import com.android.wallpaper.picker.customization.ui.binder.CustomizationOptionsBinder
 import com.android.wallpaper.picker.customization.ui.binder.DefaultCustomizationOptionsBinder
-import com.android.wallpaper.picker.di.modules.EffectsModule
-import com.android.wallpaper.picker.preview.data.util.FakeLiveWallpaperDownloader
-import com.android.wallpaper.picker.preview.data.util.LiveWallpaperDownloader
+import com.android.wallpaper.picker.customization.ui.binder.ToolbarBinder
+import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
+import com.android.wallpaper.picker.di.modules.MainDispatcher
 import com.android.wallpaper.picker.preview.ui.util.DefaultImageEffectDialogUtil
 import com.android.wallpaper.picker.preview.ui.util.ImageEffectDialogUtil
 import com.android.wallpaper.testing.FakeDefaultRequester
+import com.android.wallpaper.testing.FakeThirdPartyCategoryInteractor
+import com.android.wallpaper.testing.FakeWallpaperCategoryWrapper
 import com.android.wallpaper.testing.TestPartnerProvider
 import com.android.wallpaper.util.converter.DefaultWallpaperModelFactory
 import com.android.wallpaper.util.converter.WallpaperModelFactory
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
+import dagger.hilt.android.qualifiers.ApplicationContext
 import dagger.hilt.components.SingletonComponent
 import dagger.hilt.testing.TestInstallIn
 import javax.inject.Singleton
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 
 @Module
-@TestInstallIn(
-    components = [SingletonComponent::class],
-    replaces = [EffectsModule::class, ThemePickerAppModule::class]
-)
+@TestInstallIn(components = [SingletonComponent::class], replaces = [ThemePickerAppModule::class])
 abstract class ThemePickerTestModule {
-    //// WallpaperPicker2 prod
-
-    @Binds @Singleton abstract fun bindInjector(impl: TestCustomizationInjector): Injector
-
-    @Binds @Singleton abstract fun bindUserEventLogger(impl: TestUserEventLogger): UserEventLogger
-
-    @Binds @Singleton abstract fun bindFakeRequester(impl: FakeDefaultRequester): Requester
 
     @Binds
     @Singleton
-    abstract fun bindThemesUserEventLogger(impl: TestThemesUserEventLogger): ThemesUserEventLogger
+    abstract fun bindClockPickerRepository(impl: ClockPickerRepositoryImpl): ClockPickerRepository
 
     @Binds
     @Singleton
-    abstract fun bindWallpaperPrefs(impl: TestDefaultCustomizationPreferences): WallpaperPreferences
-
-    //// ThemePicker prod
+    abstract fun bindColorPickerRepository(impl: ColorPickerRepositoryImpl): ColorPickerRepository
 
     @Binds
     @Singleton
@@ -81,50 +90,116 @@
 
     @Binds
     @Singleton
-    abstract fun bindCustomizationPrefs(
+    abstract fun bindCustomizationOptionsBinder(
+        impl: DefaultCustomizationOptionsBinder
+    ): CustomizationOptionsBinder
+
+    @Binds
+    @Singleton
+    abstract fun bindCustomizationPreferences(
         impl: TestDefaultCustomizationPreferences
     ): CustomizationPreferences
 
     @Binds
     @Singleton
+    abstract fun bindEffectsController(impl: FakeEffectsController): EffectsController
+
+    @Binds
+    @Singleton
+    abstract fun bindWallpaperCategoryWrapper(
+        impl: FakeWallpaperCategoryWrapper
+    ): WallpaperCategoryWrapper
+
+    @Binds
+    @Singleton
+    abstract fun bindImageEffectDialogUtil(
+        impl: DefaultImageEffectDialogUtil
+    ): ImageEffectDialogUtil
+
+    @Binds @Singleton abstract fun bindInjector(impl: TestCustomizationInjector): Injector
+
+    @Binds
+    @Singleton
+    abstract fun providePartnerProvider(impl: TestPartnerProvider): PartnerProvider
+
+    @Binds @Singleton abstract fun bindRequester(impl: FakeDefaultRequester): Requester
+
+    @Binds
+    @Singleton
+    abstract fun bindThemesUserEventLogger(impl: TestThemesUserEventLogger): ThemesUserEventLogger
+
+    @Binds
+    @Singleton
+    abstract fun bindThirdPartyCategoryInteractor(
+        impl: FakeThirdPartyCategoryInteractor
+    ): ThirdPartyCategoryInteractor
+
+    @Binds @Singleton abstract fun bindToolbarBinder(impl: ThemePickerToolbarBinder): ToolbarBinder
+
+    @Binds @Singleton abstract fun bindUserEventLogger(impl: TestUserEventLogger): UserEventLogger
+
+    @Binds
+    @Singleton
     abstract fun bindWallpaperModelFactory(
         impl: DefaultWallpaperModelFactory
     ): WallpaperModelFactory
 
     @Binds
     @Singleton
-    abstract fun bindLiveWallpaperDownloader(
-        impl: FakeLiveWallpaperDownloader
-    ): LiveWallpaperDownloader
+    abstract fun bindWallpaperPreferences(
+        impl: TestDefaultCustomizationPreferences
+    ): WallpaperPreferences
 
     @Binds
     @Singleton
-    abstract fun providePartnerProvider(impl: TestPartnerProvider): PartnerProvider
-
-    @Binds
-    @Singleton
-    abstract fun bindEffectsWallpaperDialogUtil(
-        impl: DefaultImageEffectDialogUtil
-    ): ImageEffectDialogUtil
-
-    @Binds
-    @Singleton
-    abstract fun bindEffectsController(impl: FakeEffectsController): EffectsController
-
-    @Binds
-    @Singleton
-    abstract fun bindCustomizationOptionsBinder(
-        impl: DefaultCustomizationOptionsBinder
-    ): CustomizationOptionsBinder
+    abstract fun bindWorkspaceCallbackBinder(
+        impl: ThemePickerWorkspaceCallbackBinder
+    ): WorkspaceCallbackBinder
 
     companion object {
+
+        @Provides
+        @Singleton
+        fun provideClockRegistry(
+            @ApplicationContext context: Context,
+            @MainDispatcher mainScope: CoroutineScope,
+            @MainDispatcher mainDispatcher: CoroutineDispatcher,
+            @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
+        ): ClockRegistry {
+            return ClockRegistryProvider(
+                    context = context,
+                    coroutineScope = mainScope,
+                    mainDispatcher = mainDispatcher,
+                    backgroundDispatcher = bgDispatcher,
+                )
+                .get()
+        }
+
         @Provides
         @Singleton
         fun provideColorCustomizationManager(): ColorCustomizationManager {
             return ColorCustomizationManager.getInstance(
                 ApplicationProvider.getApplicationContext(),
-                OverlayManagerCompat(ApplicationProvider.getApplicationContext())
+                OverlayManagerCompat(ApplicationProvider.getApplicationContext()),
             )
         }
+
+        @Provides
+        @Singleton
+        fun provideCustomizationProviderClient(
+            @ApplicationContext context: Context,
+            @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
+        ): CustomizationProviderClient {
+            return CustomizationProviderClientImpl(context, bgDispatcher)
+        }
+
+        @Provides
+        @Singleton
+        fun provideSecureSettingsRepository(
+            @ApplicationContext context: Context,
+            @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
+        ): SecureSettingsRepository {
+            return SecureSettingsRepositoryImpl(context.contentResolver, bgDispatcher)
+        }
     }
 }
diff --git a/tests/robotests/src/com/android/customization/model/color/ColorCustomizationManagerTest.kt b/tests/robotests/src/com/android/customization/model/color/ColorCustomizationManagerTest.kt
index 0776cc8..98a1973 100644
--- a/tests/robotests/src/com/android/customization/model/color/ColorCustomizationManagerTest.kt
+++ b/tests/robotests/src/com/android/customization/model/color/ColorCustomizationManagerTest.kt
@@ -64,7 +64,7 @@
                 provider,
                 application.contentResolver,
                 mockOM,
-                MoreExecutors.newDirectExecutorService()
+                MoreExecutors.newDirectExecutorService(),
             )
     }
 
@@ -80,7 +80,7 @@
                 OVERLAY_CATEGORY_COLOR to someOtherColor,
                 OVERLAY_COLOR_SOURCE to source,
                 OVERLAY_THEME_STYLE to style.toString(),
-                ColorOption.TIMESTAMP_FIELD to "12345"
+                ColorOption.TIMESTAMP_FIELD to "12345",
             )
         val json = JSONObject(settings).toString()
 
@@ -106,14 +106,16 @@
             getPresetColorOption(index),
             object : CustomizationManager.Callback {
                 override fun onSuccess() {}
+
                 override fun onError(throwable: Throwable?) {}
-            }
+            },
         )
 
         val overlaysJson = JSONObject(manager.storedOverlays)
 
         assertThat(overlaysJson.getString(OVERLAY_COLOR_INDEX)).isEqualTo(value)
     }
+
     @Test
     fun apply_WallpaperColorOption_index() {
         testApplyWallpaperColorOption(1, "1")
@@ -127,8 +129,9 @@
             getWallpaperColorOption(index),
             object : CustomizationManager.Callback {
                 override fun onSuccess() {}
+
                 override fun onError(throwable: Throwable?) {}
-            }
+            },
         )
 
         val overlaysJson = JSONObject(manager.storedOverlays)
@@ -141,10 +144,11 @@
             mapOf("fake_package" to "fake_color"),
             /* isDefault= */ false,
             COLOR_SOURCE_PRESET,
+            12345,
             Style.TONAL_SPOT,
             index,
             ColorOptionImpl.PreviewInfo(intArrayOf(0), intArrayOf(0)),
-            ColorType.PRESET_COLOR
+            ColorType.PRESET_COLOR,
         )
     }
 
@@ -154,10 +158,11 @@
             mapOf("fake_package" to "fake_color"),
             /* isDefault= */ false,
             COLOR_SOURCE_HOME,
+            12345,
             Style.TONAL_SPOT,
             index,
             ColorOptionImpl.PreviewInfo(intArrayOf(0), intArrayOf(0)),
-            ColorType.WALLPAPER_COLOR
+            ColorType.WALLPAPER_COLOR,
         )
     }
 
@@ -170,8 +175,9 @@
             getWallpaperColorOption(0),
             object : CustomizationManager.Callback {
                 override fun onSuccess() {}
+
                 override fun onError(throwable: Throwable?) {}
-            }
+            },
         )
 
         val overlaysJson = JSONObject(manager.storedOverlays)
@@ -188,8 +194,9 @@
             getWallpaperColorOption(0),
             object : CustomizationManager.Callback {
                 override fun onSuccess() {}
+
                 override fun onError(throwable: Throwable?) {}
-            }
+            },
         )
 
         val overlaysJson = JSONObject(manager.storedOverlays)
diff --git a/tests/robotests/src/com/android/customization/model/color/ColorOptionTest.kt b/tests/robotests/src/com/android/customization/model/color/ColorOptionTest.kt
index b9156d6..ed04d14 100644
--- a/tests/robotests/src/com/android/customization/model/color/ColorOptionTest.kt
+++ b/tests/robotests/src/com/android/customization/model/color/ColorOptionTest.kt
@@ -15,6 +15,7 @@
  */
 package com.android.customization.model.color
 
+import android.graphics.Color
 import com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SYSTEM_PALETTE
 import com.android.customization.model.color.ColorOptionsProvider.COLOR_SOURCE_HOME
 import com.android.customization.model.color.ColorOptionsProvider.COLOR_SOURCE_LOCK
@@ -54,10 +55,11 @@
                 mapOf("fake_package" to "fake_color"),
                 false,
                 source,
+                12345,
                 Style.TONAL_SPOT,
                 /* index= */ 0,
                 ColorOptionImpl.PreviewInfo(intArrayOf(0), intArrayOf(0)),
-                ColorType.WALLPAPER_COLOR
+                ColorType.WALLPAPER_COLOR,
             )
         assertThat(colorOption.source).isEqualTo(source)
     }
@@ -77,10 +79,11 @@
                 mapOf("fake_package" to "fake_color"),
                 /* isDefault= */ false,
                 "fake_source",
+                12345,
                 style,
                 0,
                 ColorOptionImpl.PreviewInfo(intArrayOf(0), intArrayOf(0)),
-                ColorType.WALLPAPER_COLOR
+                ColorType.WALLPAPER_COLOR,
             )
         assertThat(colorOption.style).isEqualTo(style)
     }
@@ -100,17 +103,41 @@
                 mapOf("fake_package" to "fake_color"),
                 /* isDefault= */ false,
                 "fake_source",
+                12345,
                 Style.TONAL_SPOT,
                 index,
                 ColorOptionImpl.PreviewInfo(intArrayOf(0), intArrayOf(0)),
-                ColorType.WALLPAPER_COLOR
+                ColorType.WALLPAPER_COLOR,
             )
         assertThat(colorOption.index).isEqualTo(index)
     }
 
+    @Test
+    fun colorOption_seedColor() {
+        testColorOptionSeed(Color.RED)
+        testColorOptionSeed(Color.WHITE)
+        testColorOptionSeed(Color.BLACK)
+    }
+
+    private fun testColorOptionSeed(seedColor: Int) {
+        val colorOption: ColorOption =
+            ColorOptionImpl(
+                "fake color",
+                mapOf("fake_package" to "fake_color"),
+                /* isDefault= */ false,
+                "fake_source",
+                seedColor,
+                Style.TONAL_SPOT,
+                0,
+                ColorOptionImpl.PreviewInfo(intArrayOf(0), intArrayOf(0)),
+                ColorType.WALLPAPER_COLOR,
+            )
+        assertThat(colorOption.seedColor).isEqualTo(seedColor)
+    }
+
     private fun setUpWallpaperColorOption(
         isDefault: Boolean,
-        source: String = "some_source"
+        source: String = "some_source",
     ): ColorOptionImpl {
         val overlays =
             if (isDefault) {
@@ -124,10 +151,11 @@
             overlays,
             isDefault,
             source,
+            12345,
             Style.TONAL_SPOT,
             /* index= */ 0,
             ColorOptionImpl.PreviewInfo(intArrayOf(0), intArrayOf(0)),
-            ColorType.WALLPAPER_COLOR
+            ColorType.WALLPAPER_COLOR,
         )
     }
 
diff --git a/tests/robotests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt b/tests/robotests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt
index de68bf0..391e270 100644
--- a/tests/robotests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt
+++ b/tests/robotests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt
@@ -18,7 +18,6 @@
 package com.android.customization.model.grid.data.repository
 
 import com.android.customization.model.CustomizationManager
-import com.android.customization.model.grid.GridOption
 import com.android.customization.picker.grid.data.repository.GridRepository
 import com.android.customization.picker.grid.shared.model.GridOptionItemModel
 import com.android.customization.picker.grid.shared.model.GridOptionItemsModel
@@ -54,7 +53,7 @@
         return options
     }
 
-    override fun getSelectedOption(): GridOption? = null
+    override fun getSelectedOption() = MutableStateFlow(null)
 
     override fun applySelectedOption(callback: CustomizationManager.Callback) {}
 
diff --git a/tests/robotests/src/com/android/customization/model/notifications/domain/interactor/NotificationsSnapshotRestorerTest.kt b/tests/robotests/src/com/android/customization/model/notifications/domain/interactor/NotificationsSnapshotRestorerTest.kt
index bf8cfda..094ab81 100644
--- a/tests/robotests/src/com/android/customization/model/notifications/domain/interactor/NotificationsSnapshotRestorerTest.kt
+++ b/tests/robotests/src/com/android/customization/model/notifications/domain/interactor/NotificationsSnapshotRestorerTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
 import com.android.systemui.shared.settings.data.repository.FakeSecureSettingsRepository
+import com.android.systemui.shared.settings.data.repository.FakeSystemSettingsRepository
 import com.android.wallpaper.testing.FakeSnapshotStore
 import com.android.wallpaper.testing.collectLastValue
 import com.google.common.truth.Truth.assertThat
@@ -44,6 +45,7 @@
 
     private lateinit var underTest: NotificationsSnapshotRestorer
     private lateinit var fakeSecureSettingsRepository: FakeSecureSettingsRepository
+    private lateinit var fakeSystemSettingsRepository: FakeSystemSettingsRepository
     private lateinit var interactor: NotificationSettingsInteractor
 
     private lateinit var testScope: TestScope
@@ -54,13 +56,15 @@
         Dispatchers.setMain(testDispatcher)
         testScope = TestScope(testDispatcher)
         fakeSecureSettingsRepository = FakeSecureSettingsRepository()
+        fakeSystemSettingsRepository = FakeSystemSettingsRepository()
         interactor =
             NotificationSettingsInteractor(
                 repository =
                     NotificationSettingsRepository(
-                        scope = testScope.backgroundScope,
+                        backgroundScope = testScope.backgroundScope,
                         backgroundDispatcher = testDispatcher,
                         secureSettingsRepository = fakeSecureSettingsRepository,
+                        systemSettingsRepository = fakeSystemSettingsRepository,
                     ),
             )
         underTest =
diff --git a/tests/robotests/src/com/android/customization/model/picker/color/domain/interactor/ColorPickerInteractorTest.kt b/tests/robotests/src/com/android/customization/model/picker/color/domain/interactor/ColorPickerInteractorTest.kt
index d4f24ee..97d4a9a 100644
--- a/tests/robotests/src/com/android/customization/model/picker/color/domain/interactor/ColorPickerInteractorTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/color/domain/interactor/ColorPickerInteractorTest.kt
@@ -52,11 +52,10 @@
         underTest =
             ColorPickerInteractor(
                 repository = repository,
-                snapshotRestorer = {
-                    ColorPickerSnapshotRestorer(interactor = underTest).apply {
+                snapshotRestorer =
+                    ColorPickerSnapshotRestorer(repository = repository).apply {
                         runBlocking { setUpSnapshotRestorer(store = store) }
-                    }
-                },
+                    },
             )
         repository.setOptions(4, 4, ColorType.WALLPAPER_COLOR, 0)
     }
diff --git a/tests/robotests/src/com/android/customization/model/picker/color/domain/interactor/ColorPickerSnapshotRestorerTest.kt b/tests/robotests/src/com/android/customization/model/picker/color/domain/interactor/ColorPickerSnapshotRestorerTest.kt
index 5f3e39e..b050237 100644
--- a/tests/robotests/src/com/android/customization/model/picker/color/domain/interactor/ColorPickerSnapshotRestorerTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/color/domain/interactor/ColorPickerSnapshotRestorerTest.kt
@@ -21,7 +21,6 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.customization.picker.color.data.repository.FakeColorPickerRepository
-import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
 import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer
 import com.android.customization.picker.color.shared.model.ColorOptionModel
 import com.android.customization.picker.color.shared.model.ColorType
@@ -51,14 +50,7 @@
     fun setUp() {
         context = InstrumentationRegistry.getInstrumentation().targetContext
         repository = FakeColorPickerRepository(context = context)
-        underTest =
-            ColorPickerSnapshotRestorer(
-                interactor =
-                    ColorPickerInteractor(
-                        repository = repository,
-                        snapshotRestorer = { underTest },
-                    )
-            )
+        underTest = ColorPickerSnapshotRestorer(repository = repository)
         store = FakeSnapshotStore()
     }
 
diff --git a/tests/robotests/src/com/android/customization/model/picker/color/ui/viewmodel/ColorPickerViewModelTest.kt b/tests/robotests/src/com/android/customization/model/picker/color/ui/viewmodel/ColorPickerViewModelTest.kt
index 889720e..50602ad 100644
--- a/tests/robotests/src/com/android/customization/model/picker/color/ui/viewmodel/ColorPickerViewModelTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/color/ui/viewmodel/ColorPickerViewModelTest.kt
@@ -17,7 +17,6 @@
 package com.android.customization.model.picker.color.ui.viewmodel
 
 import android.content.Context
-import android.graphics.Color
 import android.stats.style.StyleEnums
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
@@ -76,18 +75,17 @@
         interactor =
             ColorPickerInteractor(
                 repository = repository,
-                snapshotRestorer = {
-                    ColorPickerSnapshotRestorer(interactor = interactor).apply {
+                snapshotRestorer =
+                    ColorPickerSnapshotRestorer(repository = repository).apply {
                         runBlocking { setUpSnapshotRestorer(store = store) }
-                    }
-                },
+                    },
             )
 
         underTest =
             ColorPickerViewModel.Factory(
                     context = context,
                     interactor = interactor,
-                    logger = logger
+                    logger = logger,
                 )
                 .create(ColorPickerViewModel::class.java)
 
@@ -106,19 +104,19 @@
 
             assertColorOptionUiState(
                 colorOptions = colorSectionOptions(),
-                selectedColorOptionIndex = 0
+                selectedColorOptionIndex = 0,
             )
 
             selectColorOption(colorSectionOptions, 2)
             assertColorOptionUiState(
                 colorOptions = colorSectionOptions(),
-                selectedColorOptionIndex = 2
+                selectedColorOptionIndex = 2,
             )
 
             selectColorOption(colorSectionOptions, 4)
             assertColorOptionUiState(
                 colorOptions = colorSectionOptions(),
-                selectedColorOptionIndex = 4
+                selectedColorOptionIndex = 4,
             )
         }
 
@@ -130,12 +128,12 @@
                     repository.buildWallpaperOption(
                         ColorOptionsProvider.COLOR_SOURCE_LOCK,
                         Style.EXPRESSIVE,
-                        "121212"
+                        121212,
                     )
                 ),
-                listOf(repository.buildPresetOption(Style.FRUIT_SALAD, "#ABCDEF")),
+                listOf(repository.buildPresetOption(Style.FRUIT_SALAD, -54321)),
                 ColorType.PRESET_COLOR,
-                0
+                0,
             )
 
             val colorTypes = collectLastValue(underTest.colorTypeTabs)
@@ -150,7 +148,7 @@
             assertThat(logger.themeColorSource)
                 .isEqualTo(StyleEnums.COLOR_SOURCE_LOCK_SCREEN_WALLPAPER)
             assertThat(logger.themeColorStyle).isEqualTo(Style.EXPRESSIVE.toString().hashCode())
-            assertThat(logger.themeSeedColor).isEqualTo(Color.parseColor("#121212"))
+            assertThat(logger.themeSeedColor).isEqualTo(121212)
         }
 
     @Test
@@ -161,12 +159,12 @@
                     repository.buildWallpaperOption(
                         ColorOptionsProvider.COLOR_SOURCE_LOCK,
                         Style.EXPRESSIVE,
-                        "121212"
+                        121212,
                     )
                 ),
-                listOf(repository.buildPresetOption(Style.FRUIT_SALAD, "#ABCDEF")),
+                listOf(repository.buildPresetOption(Style.FRUIT_SALAD, -54321)),
                 ColorType.WALLPAPER_COLOR,
-                0
+                0,
             )
 
             val colorTypes = collectLastValue(underTest.colorTypeTabs)
@@ -180,7 +178,7 @@
 
             assertThat(logger.themeColorSource).isEqualTo(StyleEnums.COLOR_SOURCE_PRESET_COLOR)
             assertThat(logger.themeColorStyle).isEqualTo(Style.FRUIT_SALAD.toString().hashCode())
-            assertThat(logger.themeSeedColor).isEqualTo(Color.parseColor("#ABCDEF"))
+            assertThat(logger.themeSeedColor).isEqualTo(-54321)
         }
 
     @Test
@@ -194,7 +192,7 @@
                 colorTypes = colorTypes(),
                 colorOptions = colorOptions(),
                 selectedColorTypeText = "Wallpaper colors",
-                selectedColorOptionIndex = 0
+                selectedColorOptionIndex = 0,
             )
 
             // Select "Basic colors" tab
@@ -203,7 +201,7 @@
                 colorTypes = colorTypes(),
                 colorOptions = colorOptions(),
                 selectedColorTypeText = "Basic colors",
-                selectedColorOptionIndex = -1
+                selectedColorOptionIndex = -1,
             )
 
             // Select a color option
@@ -215,7 +213,7 @@
                 colorTypes = colorTypes(),
                 colorOptions = colorOptions(),
                 selectedColorTypeText = "Wallpaper colors",
-                selectedColorOptionIndex = -1
+                selectedColorOptionIndex = -1,
             )
 
             // Check new option is selected
@@ -224,7 +222,7 @@
                 colorTypes = colorTypes(),
                 colorOptions = colorOptions(),
                 selectedColorTypeText = "Basic colors",
-                selectedColorOptionIndex = 2
+                selectedColorOptionIndex = 2,
             )
         }
 
diff --git a/tests/robotests/src/com/android/customization/model/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepositoryTest.kt b/tests/robotests/src/com/android/customization/model/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepositoryTest.kt
index 8687b30..55fb2cb 100644
--- a/tests/robotests/src/com/android/customization/model/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepositoryTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepositoryTest.kt
@@ -53,7 +53,7 @@
         underTest =
             KeyguardQuickAffordancePickerRepository(
                 client = client,
-                scope = testScope.backgroundScope,
+                mainScope = testScope.backgroundScope,
             )
     }
 
diff --git a/tests/robotests/src/com/android/customization/model/picker/quickaffordance/domain/interactor/KeyguardQuickAffordancePickerInteractorTest.kt b/tests/robotests/src/com/android/customization/model/picker/quickaffordance/domain/interactor/KeyguardQuickAffordancePickerInteractorTest.kt
index 4b4790a..2b84ee4 100644
--- a/tests/robotests/src/com/android/customization/model/picker/quickaffordance/domain/interactor/KeyguardQuickAffordancePickerInteractorTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/quickaffordance/domain/interactor/KeyguardQuickAffordancePickerInteractorTest.kt
@@ -24,12 +24,10 @@
 import com.android.customization.picker.quickaffordance.shared.model.KeyguardQuickAffordancePickerSelectionModel
 import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
-import com.android.wallpaper.testing.FakeSnapshotStore
 import com.android.wallpaper.testing.collectLastValue
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.resetMain
@@ -62,16 +60,10 @@
                 repository =
                     KeyguardQuickAffordancePickerRepository(
                         client = client,
-                        scope = testScope.backgroundScope,
+                        mainScope = testScope.backgroundScope,
                     ),
                 client = client,
-                snapshotRestorer = {
-                    KeyguardQuickAffordanceSnapshotRestorer(
-                            interactor = underTest,
-                            client = client,
-                        )
-                        .apply { runBlocking { setUpSnapshotRestorer(FakeSnapshotStore()) } }
-                },
+                snapshotRestorer = KeyguardQuickAffordanceSnapshotRestorer(client),
             )
     }
 
diff --git a/tests/robotests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt b/tests/robotests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
index 53ade86..63c27ed 100644
--- a/tests/robotests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
@@ -33,22 +33,27 @@
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
 import com.android.themepicker.R
 import com.android.wallpaper.module.InjectorProvider
+import com.android.wallpaper.module.NetworkStatusNotifier
+import com.android.wallpaper.module.PartnerProvider
+import com.android.wallpaper.module.WallpaperPreferences
+import com.android.wallpaper.network.Requester
+import com.android.wallpaper.picker.category.wrapper.WallpaperCategoryWrapper
 import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
 import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
 import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository
 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor
 import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
-import com.android.wallpaper.testing.FakeSnapshotStore
 import com.android.wallpaper.testing.FakeWallpaperClient
 import com.android.wallpaper.testing.TestCurrentWallpaperInfoFactory
 import com.android.wallpaper.testing.TestInjector
 import com.android.wallpaper.testing.TestWallpaperPreferences
 import com.android.wallpaper.testing.collectLastValue
+import com.android.wallpaper.util.DisplayUtils
+import com.android.wallpaper.util.DisplaysProvider
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.resetMain
@@ -58,6 +63,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
 import org.robolectric.RobolectricTestRunner
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -77,7 +83,6 @@
 
     @Before
     fun setUp() {
-        InjectorProvider.setInjector(TestInjector(logger))
         context = ApplicationProvider.getApplicationContext()
         val testDispatcher = StandardTestDispatcher()
         testScope = TestScope(testDispatcher)
@@ -89,16 +94,10 @@
                 repository =
                     KeyguardQuickAffordancePickerRepository(
                         client = client,
-                        scope = testScope.backgroundScope,
+                        mainScope = testScope.backgroundScope,
                     ),
                 client = client,
-                snapshotRestorer = {
-                    KeyguardQuickAffordanceSnapshotRestorer(
-                            interactor = quickAffordanceInteractor,
-                            client = client,
-                        )
-                        .apply { runBlocking { setUpSnapshotRestorer(FakeSnapshotStore()) } }
-                },
+                snapshotRestorer = KeyguardQuickAffordanceSnapshotRestorer(client),
             )
         wallpaperInteractor =
             WallpaperInteractor(
@@ -108,8 +107,21 @@
                         client = FakeWallpaperClient(),
                         wallpaperPreferences = TestWallpaperPreferences(),
                         backgroundDispatcher = testDispatcher,
-                    ),
+                    )
             )
+        InjectorProvider.setInjector(
+            TestInjector(
+                logger,
+                DisplayUtils(context, mock(DisplaysProvider::class.java)),
+                mock(Requester::class.java),
+                mock(NetworkStatusNotifier::class.java),
+                mock(PartnerProvider::class.java),
+                FakeWallpaperClient(),
+                wallpaperInteractor,
+                mock(WallpaperPreferences::class.java),
+                mock(WallpaperCategoryWrapper::class.java),
+            )
+        )
         underTest =
             KeyguardQuickAffordancePickerViewModel.Factory(
                     context = context,
@@ -356,12 +368,12 @@
                         icon1 =
                             Icon.Loaded(
                                 FakeCustomizationProviderClient.ICON_1,
-                                Text.Loaded("Left shortcut")
+                                Text.Loaded("Left shortcut"),
                             ),
                         icon2 =
                             Icon.Loaded(
                                 FakeCustomizationProviderClient.ICON_3,
-                                Text.Loaded("Right shortcut")
+                                Text.Loaded("Right shortcut"),
                             ),
                     )
                 )
@@ -384,7 +396,7 @@
                         icon1 =
                             Icon.Loaded(
                                 FakeCustomizationProviderClient.ICON_1,
-                                Text.Loaded("Left shortcut")
+                                Text.Loaded("Left shortcut"),
                             ),
                         icon2 = null,
                     )
@@ -412,7 +424,7 @@
                         icon2 =
                             Icon.Loaded(
                                 FakeCustomizationProviderClient.ICON_3,
-                                Text.Loaded("Right shortcut")
+                                Text.Loaded("Right shortcut"),
                             ),
                     )
                 )
@@ -473,11 +485,7 @@
         assertThat(affordances).isNotNull()
         affordances?.forEach { affordance ->
             val nameMatchesSelectedName =
-                Text.evaluationEquals(
-                    context,
-                    affordance.text,
-                    Text.Loaded(selectedAffordanceText),
-                )
+                Text.evaluationEquals(context, affordance.text, Text.Loaded(selectedAffordanceText))
             val isSelected: Boolean? = collectLastValue(affordance.isSelected).invoke()
             assertWithMessage(
                     "Expected affordance with name \"${affordance.text}\" to have" +
diff --git a/tests/robotests/src/com/android/customization/model/picker/settings/data/repository/ColorContrastSectionRepositoryTest.kt b/tests/robotests/src/com/android/customization/model/picker/settings/data/repository/ColorContrastSectionRepositoryTest.kt
index cde597a..9d76b53 100644
--- a/tests/robotests/src/com/android/customization/model/picker/settings/data/repository/ColorContrastSectionRepositoryTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/settings/data/repository/ColorContrastSectionRepositoryTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.customization.model.picker.settings.data.repository
 
+import android.app.UiModeManager.ContrastUtils
 import androidx.test.filters.SmallTest
 import com.android.customization.picker.settings.data.repository.ColorContrastSectionRepository
 import com.android.wallpaper.testing.FakeUiModeManager
@@ -61,8 +62,10 @@
     fun contrastFlowEmitsValues() =
         testScope.runTest {
             val nextContrastValues = listOf(0.5f, 0.7f, 0.8f)
+            val expectedContrastValues =
+                nextContrastValues.map { ContrastUtils.toContrastLevel(it) }
             // Set up a flow to collect all contrast values
-            val flowCollector = mutableListOf<Float>()
+            val flowCollector = mutableListOf<Int>()
             // Start collecting values from the flow, using an unconfined dispatcher to start
             // collecting from the flow right away (rather than explicitly calling `runCurrent`)
             // See https://developer.android.com/kotlin/flow/test#continuous-collection
@@ -74,6 +77,6 @@
 
             // Ignore the first contrast value from constructing the repository
             val collectedValues = flowCollector.drop(1)
-            assertThat(collectedValues).containsExactlyElementsIn(nextContrastValues)
+            assertThat(collectedValues).containsExactlyElementsIn(expectedContrastValues)
         }
 }
diff --git a/tests/robotests/src/com/android/customization/model/picker/settings/domain/interactor/ColorContrastSectionInteractorTest.kt b/tests/robotests/src/com/android/customization/model/picker/settings/domain/interactor/ColorContrastSectionInteractorTest.kt
index afa6427..d66cddf 100644
--- a/tests/robotests/src/com/android/customization/model/picker/settings/domain/interactor/ColorContrastSectionInteractorTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/settings/domain/interactor/ColorContrastSectionInteractorTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.customization.model.picker.settings.domain.interactor
 
+import android.app.UiModeManager.ContrastUtils
 import androidx.test.filters.SmallTest
 import com.android.customization.picker.settings.domain.interactor.ColorContrastSectionInteractor
 import com.android.wallpaper.testing.FakeUiModeManager
@@ -47,11 +48,12 @@
 
     @Test
     fun contrastEmitCorrectValuesFromRepository() = runTest {
-        val expectedContrast = 1.5f
-        uiModeManager.setContrast(expectedContrast)
+        val contrastVal = 0.5f
+        val expectedContrastVal = ContrastUtils.toContrastLevel(contrastVal)
+        uiModeManager.setContrast(contrastVal)
 
         val result = interactor.contrast.first()
 
-        assertThat(result).isEqualTo(expectedContrast)
+        assertThat(result).isEqualTo(expectedContrastVal)
     }
 }
diff --git a/tests/robotests/src/com/android/customization/model/picker/settings/ui/viewmodel/ColorContrastSectionViewModelTest.kt b/tests/robotests/src/com/android/customization/model/picker/settings/ui/viewmodel/ColorContrastSectionViewModelTest.kt
index 0c420e0..2223282 100644
--- a/tests/robotests/src/com/android/customization/model/picker/settings/ui/viewmodel/ColorContrastSectionViewModelTest.kt
+++ b/tests/robotests/src/com/android/customization/model/picker/settings/ui/viewmodel/ColorContrastSectionViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.customization.model.picker.settings.ui.viewmodel
 
+import android.app.UiModeManager.ContrastUtils
 import com.android.customization.picker.settings.ui.viewmodel.ColorContrastSectionDataViewModel
 import com.android.customization.picker.settings.ui.viewmodel.ColorContrastSectionViewModel
 import com.android.themepicker.R
@@ -60,11 +61,13 @@
 
     @Test
     fun summaryEmitsCorrectDataValueForStandard() = runTest {
-        uiModeManager.setContrast(ColorContrastSectionViewModel.ContrastValue.STANDARD.value)
+        uiModeManager.setContrast(
+            ContrastUtils.fromContrastLevel(ContrastUtils.CONTRAST_LEVEL_STANDARD)
+        )
         val expected =
             ColorContrastSectionDataViewModel(
                 Text.Resource(R.string.color_contrast_default_title),
-                Icon.Resource(res = R.drawable.ic_contrast_standard, contentDescription = null)
+                Icon.Resource(res = R.drawable.ic_contrast_standard, contentDescription = null),
             )
 
         val result = viewModel.summary.first()
@@ -74,11 +77,13 @@
 
     @Test
     fun summaryEmitsCorrectDataValueForMedium() = runTest {
-        uiModeManager.setContrast(ColorContrastSectionViewModel.ContrastValue.MEDIUM.value)
+        uiModeManager.setContrast(
+            ContrastUtils.fromContrastLevel(ContrastUtils.CONTRAST_LEVEL_MEDIUM)
+        )
         val expected =
             ColorContrastSectionDataViewModel(
                 Text.Resource(R.string.color_contrast_medium_title),
-                Icon.Resource(res = R.drawable.ic_contrast_medium, contentDescription = null)
+                Icon.Resource(res = R.drawable.ic_contrast_medium, contentDescription = null),
             )
 
         val result = viewModel.summary.first()
@@ -88,11 +93,13 @@
 
     @Test
     fun summaryEmitsCorrectDataValueForHigh() = runTest {
-        uiModeManager.setContrast(ColorContrastSectionViewModel.ContrastValue.HIGH.value)
+        uiModeManager.setContrast(
+            ContrastUtils.fromContrastLevel(ContrastUtils.CONTRAST_LEVEL_HIGH)
+        )
         val expected =
             ColorContrastSectionDataViewModel(
                 Text.Resource(R.string.color_contrast_high_title),
-                Icon.Resource(res = R.drawable.ic_contrast_high, contentDescription = null)
+                Icon.Resource(res = R.drawable.ic_contrast_high, contentDescription = null),
             )
 
         val result = viewModel.summary.first()
diff --git a/tests/robotests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt b/tests/robotests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
index 4d8f32e..0e5a88e 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
@@ -16,15 +16,20 @@
 package com.android.customization.picker.clock.data.repository
 
 import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
 import androidx.annotation.ColorInt
 import androidx.annotation.IntRange
 import com.android.customization.picker.clock.data.repository.FakeClockPickerRepository.Companion.fakeClocks
 import com.android.customization.picker.clock.shared.ClockSize
 import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.systemui.plugins.clocks.AxisType
+import com.android.systemui.plugins.clocks.ClockFontAxis
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.update
 
 /** By default [FakeClockPickerRepository] uses [fakeClocks]. */
 open class FakeClockPickerRepository(clocks: List<ClockMetadataModel> = fakeClocks) :
@@ -35,25 +40,30 @@
     @ColorInt private val selectedColorId = MutableStateFlow<String?>(null)
     private val colorTone = MutableStateFlow(ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS)
     @ColorInt private val seedColor = MutableStateFlow<Int?>(null)
+    private val fontAxes = MutableStateFlow<List<ClockFontAxis>>(listOf(buildFakeAxis(0)))
     override val selectedClock: Flow<ClockMetadataModel> =
-        combine(
+        combine(selectedClockId, selectedColorId, colorTone, seedColor, fontAxes) {
             selectedClockId,
-            selectedColorId,
+            selectedColor,
             colorTone,
             seedColor,
-        ) { selectedClockId, selectedColor, colorTone, seedColor ->
+            fontAxes ->
             val selectedClock = fakeClocks.find { clock -> clock.clockId == selectedClockId }
             checkNotNull(selectedClock)
             ClockMetadataModel(
                 clockId = selectedClock.clockId,
                 isSelected = true,
+                description = "description",
+                thumbnail = ColorDrawable(0),
+                isReactiveToTone = selectedClock.isReactiveToTone,
+                fontAxes = fontAxes,
                 selectedColorId = selectedColor,
                 colorToneProgress = colorTone,
                 seedColor = seedColor,
             )
         }
 
-    private val _selectedClockSize = MutableStateFlow(ClockSize.SMALL)
+    private val _selectedClockSize = MutableStateFlow(ClockSize.DYNAMIC)
     override val selectedClockSize: Flow<ClockSize> = _selectedClockSize.asStateFlow()
 
     override suspend fun setSelectedClock(clockId: String) {
@@ -74,17 +84,73 @@
         _selectedClockSize.value = size
     }
 
+    override suspend fun setClockFontAxes(axisSettings: List<ClockFontAxisSetting>) {
+        fontAxes.update { fontAxes -> ClockFontAxis.merge(fontAxes, axisSettings) }
+    }
+
     companion object {
+        fun buildFakeAxis(i: Int): ClockFontAxis {
+            return ClockFontAxis(
+                key = "key",
+                type = AxisType.Float,
+                maxValue = 0f,
+                minValue = 1000f,
+                currentValue = 50f * (i + 1),
+                name = "FakeAxis",
+                description = "Axis Description",
+            )
+        }
+
         const val CLOCK_ID_0 = "clock0"
         const val CLOCK_ID_1 = "clock1"
         const val CLOCK_ID_2 = "clock2"
         const val CLOCK_ID_3 = "clock3"
         val fakeClocks =
             listOf(
-                ClockMetadataModel(CLOCK_ID_0, true, null, 50, null),
-                ClockMetadataModel(CLOCK_ID_1, false, null, 50, null),
-                ClockMetadataModel(CLOCK_ID_2, false, null, 50, null),
-                ClockMetadataModel(CLOCK_ID_3, false, null, 50, null),
+                ClockMetadataModel(
+                    CLOCK_ID_0,
+                    true,
+                    "description0",
+                    ColorDrawable(0),
+                    true,
+                    listOf(buildFakeAxis(0)),
+                    null,
+                    50,
+                    null,
+                ),
+                ClockMetadataModel(
+                    CLOCK_ID_1,
+                    false,
+                    "description1",
+                    ColorDrawable(0),
+                    true,
+                    listOf(buildFakeAxis(1)),
+                    null,
+                    50,
+                    null,
+                ),
+                ClockMetadataModel(
+                    CLOCK_ID_2,
+                    false,
+                    "description2",
+                    ColorDrawable(0),
+                    true,
+                    listOf(buildFakeAxis(2)),
+                    null,
+                    50,
+                    null,
+                ),
+                ClockMetadataModel(
+                    CLOCK_ID_3,
+                    false,
+                    "description3",
+                    ColorDrawable(0),
+                    false,
+                    listOf(buildFakeAxis(3)),
+                    null,
+                    50,
+                    null,
+                ),
             )
         const val CLOCK_COLOR_ID = "RED"
         const val CLOCK_COLOR_TONE_PROGRESS = 87
diff --git a/tests/robotests/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractorTest.kt b/tests/robotests/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractorTest.kt
index c8e39be..43910ff 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractorTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractorTest.kt
@@ -30,14 +30,14 @@
     fun setUp() {
         val testDispatcher = StandardTestDispatcher()
         Dispatchers.setMain(testDispatcher)
+        val repository = FakeClockPickerRepository()
         underTest =
             ClockPickerInteractor(
-                repository = FakeClockPickerRepository(),
-                snapshotRestorer = {
-                    ClockPickerSnapshotRestorer(interactor = underTest).apply {
+                repository = repository,
+                snapshotRestorer =
+                    ClockPickerSnapshotRestorer(repository = repository).apply {
                         runBlocking { setUpSnapshotRestorer(store = FakeSnapshotStore()) }
-                    }
-                },
+                    },
             )
     }
 
@@ -80,4 +80,14 @@
             .isEqualTo(FakeClockPickerRepository.CLOCK_COLOR_TONE_PROGRESS)
         Truth.assertThat(observedSeedColor()).isEqualTo(FakeClockPickerRepository.SEED_COLOR)
     }
+
+    @Test
+    fun setFontAxisSettings() = runTest {
+        val axisSettings = collectLastValue(underTest.axisSettings)
+        val fakeSettings = listOf(FakeClockPickerRepository.buildFakeAxis(10).toSetting())
+
+        underTest.setClockFontAxes(fakeSettings)
+
+        Truth.assertThat(axisSettings()).isEqualTo(fakeSettings)
+    }
 }
diff --git a/tests/robotests/src/com/android/customization/picker/clock/ui/FakeClockViewFactory.kt b/tests/robotests/src/com/android/customization/picker/clock/ui/FakeClockViewFactory.kt
index 41192e7..418b439 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/ui/FakeClockViewFactory.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/ui/FakeClockViewFactory.kt
@@ -1,27 +1,25 @@
 package com.android.customization.picker.clock.ui
 
-import android.content.res.Resources
 import android.view.View
 import androidx.lifecycle.LifecycleOwner
 import com.android.customization.picker.clock.data.repository.FakeClockPickerRepository
-import com.android.customization.picker.clock.ui.FakeClockViewFactory.Companion.fakeClocks
 import com.android.customization.picker.clock.ui.view.ClockViewFactory
 import com.android.systemui.plugins.clocks.ClockConfig
 import com.android.systemui.plugins.clocks.ClockController
 import com.android.systemui.plugins.clocks.ClockEvents
 import com.android.systemui.plugins.clocks.ClockFaceController
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 import java.io.PrintWriter
+import javax.inject.Inject
 
 /**
  * This is a fake [ClockViewFactory]. Only implement the function if it's actually called in a test.
  */
-class FakeClockViewFactory(
-    val clockControllers: MutableMap<String, ClockController> = fakeClocks.toMutableMap(),
-) : ClockViewFactory {
+class FakeClockViewFactory @Inject constructor() : ClockViewFactory {
 
-    class FakeClockController(
-        override var config: ClockConfig,
-    ) : ClockController {
+    private val clockControllers: MutableMap<String, ClockController> = fakeClocks.toMutableMap()
+
+    class FakeClockController(override var config: ClockConfig) : ClockController {
         override val smallClock: ClockFaceController
             get() = TODO("Not yet implemented")
 
@@ -31,17 +29,13 @@
         override val events: ClockEvents
             get() = TODO("Not yet implemented")
 
-        override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) =
+        override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) =
             TODO("Not yet implemented")
 
         override fun dump(pw: PrintWriter) = TODO("Not yet implemented")
     }
 
-    override fun getController(clockId: String): ClockController = clockControllers.get(clockId)!!
-
-    override fun setReactiveTouchInteractionEnabled(clockId: String, enable: Boolean) {
-        TODO("Not yet implemented")
-    }
+    override fun getController(clockId: String): ClockController = clockControllers[clockId]!!
 
     override fun getLargeView(clockId: String): View {
         TODO("Not yet implemented")
@@ -59,6 +53,10 @@
         TODO("Not yet implemented")
     }
 
+    override fun updateFontAxes(clockId: String, settings: List<ClockFontAxisSetting>) {
+        TODO("Not yet implemented")
+    }
+
     override fun updateRegionDarkness() {
         TODO("Not yet implemented")
     }
@@ -81,17 +79,15 @@
 
     companion object {
         val fakeClocks =
-            FakeClockPickerRepository.fakeClocks
-                .map { clock ->
-                    clock.clockId to
-                        FakeClockController(
-                            ClockConfig(
-                                id = clock.clockId,
-                                name = "Name: ${clock.clockId}",
-                                description = "Desc: ${clock.clockId}"
-                            )
+            FakeClockPickerRepository.fakeClocks.associate { clock ->
+                clock.clockId to
+                    FakeClockController(
+                        ClockConfig(
+                            id = clock.clockId,
+                            name = "Name: ${clock.clockId}",
+                            description = "Desc: ${clock.clockId}",
                         )
-                }
-                .toMap()
+                    )
+            }
     }
 }
diff --git a/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt b/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
index 46afe35..64efed6 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModelTest.kt
@@ -15,6 +15,7 @@
  */
 package com.android.customization.picker.clock.ui.viewmodel
 
+import android.graphics.drawable.ColorDrawable
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.customization.module.logging.TestThemesUserEventLogger
@@ -54,10 +55,14 @@
                 ClockMetadataModel(
                     clockId = FakeClockPickerRepository.CLOCK_ID_0,
                     isSelected = true,
+                    description = "description",
+                    thumbnail = ColorDrawable(0),
+                    isReactiveToTone = true,
+                    fontAxes = listOf(),
                     selectedColorId = null,
                     colorToneProgress = ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS,
                     seedColor = null,
-                ),
+                )
             )
         )
     }
@@ -100,11 +105,10 @@
     private fun getClockPickerInteractor(repository: ClockPickerRepository): ClockPickerInteractor {
         return ClockPickerInteractor(
                 repository = repository,
-                snapshotRestorer = {
-                    ClockPickerSnapshotRestorer(interactor = interactor).apply {
+                snapshotRestorer =
+                    ClockPickerSnapshotRestorer(repository = repository).apply {
                         runBlocking { setUpSnapshotRestorer(store = FakeSnapshotStore()) }
-                    }
-                }
+                    },
             )
             .also { interactor = it }
     }
diff --git a/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModelTest.kt b/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModelTest.kt
index d3ae9cb..dd68589 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModelTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModelTest.kt
@@ -61,23 +61,23 @@
         Dispatchers.setMain(testDispatcher)
         context = InstrumentationRegistry.getInstrumentation().targetContext
         testScope = TestScope(testDispatcher)
+        val repository = FakeClockPickerRepository()
         clockPickerInteractor =
             ClockPickerInteractor(
-                repository = FakeClockPickerRepository(),
-                snapshotRestorer = {
-                    ClockPickerSnapshotRestorer(interactor = clockPickerInteractor).apply {
+                repository = repository,
+                snapshotRestorer =
+                    ClockPickerSnapshotRestorer(repository = repository).apply {
                         runBlocking { setUpSnapshotRestorer(store = FakeSnapshotStore()) }
-                    }
-                },
+                    },
             )
+        val colorPickerRepository = FakeColorPickerRepository(context = context)
         colorPickerInteractor =
             ColorPickerInteractor(
-                repository = FakeColorPickerRepository(context = context),
-                snapshotRestorer = {
-                    ColorPickerSnapshotRestorer(interactor = colorPickerInteractor).apply {
+                repository = colorPickerRepository,
+                snapshotRestorer =
+                    ColorPickerSnapshotRestorer(repository = colorPickerRepository).apply {
                         runBlocking { setUpSnapshotRestorer(store = FakeSnapshotStore()) }
-                    }
-                },
+                    },
             )
         underTest =
             ClockSettingsViewModel.Factory(
diff --git a/tests/robotests/src/com/android/customization/picker/grid/data/repository/ShapeGridRepositoryTest.kt b/tests/robotests/src/com/android/customization/picker/grid/data/repository/ShapeGridRepositoryTest.kt
new file mode 100644
index 0000000..985d983
--- /dev/null
+++ b/tests/robotests/src/com/android/customization/picker/grid/data/repository/ShapeGridRepositoryTest.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.grid.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.customization.model.grid.FakeShapeGridManager
+import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
+import com.android.wallpaper.testing.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import dagger.hilt.android.testing.HiltAndroidRule
+import dagger.hilt.android.testing.HiltAndroidTest
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@HiltAndroidTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(RobolectricTestRunner::class)
+class ShapeGridRepositoryTest {
+
+    @get:Rule var hiltRule = HiltAndroidRule(this)
+    @Inject lateinit var gridOptionsManager: FakeShapeGridManager
+    @Inject lateinit var testScope: TestScope
+    @BackgroundDispatcher @Inject lateinit var bgScope: CoroutineScope
+    @BackgroundDispatcher @Inject lateinit var bgDispatcher: CoroutineDispatcher
+
+    private lateinit var underTest: ShapeGridRepository
+
+    @Before
+    fun setUp() {
+        hiltRule.inject()
+        underTest =
+            ShapeGridRepository(
+                manager = gridOptionsManager,
+                bgScope = bgScope,
+                bgDispatcher = bgDispatcher,
+            )
+    }
+
+    @After
+    fun tearDown() {
+        Dispatchers.resetMain()
+    }
+
+    @Test
+    fun shapeOptions_default() =
+        testScope.runTest {
+            val gridOptions = collectLastValue(underTest.shapeOptions)
+
+            assertThat(gridOptions()).isEqualTo(FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST)
+        }
+
+    @Test
+    fun shapeOptions_shouldUpdateAfterApplyShapeGridOption() =
+        testScope.runTest {
+            val shapeOptions = collectLastValue(underTest.shapeOptions)
+
+            underTest.applySelectedOption("circle", "practical")
+
+            assertThat(shapeOptions())
+                .isEqualTo(
+                    FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST.map {
+                        it.copy(isCurrent = (it.key == "circle"))
+                    }
+                )
+        }
+
+    @Test
+    fun selectedShapeOption_default() =
+        testScope.runTest {
+            val selectedGridOption = collectLastValue(underTest.selectedShapeOption)
+
+            assertThat(selectedGridOption())
+                .isEqualTo(FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[0])
+        }
+
+    @Test
+    fun selectedShapeOption_shouldUpdateAfterApplyShapeGridOption() =
+        testScope.runTest {
+            val selectedShapeOption = collectLastValue(underTest.selectedShapeOption)
+
+            underTest.applySelectedOption("circle", "practical")
+
+            assertThat(selectedShapeOption())
+                .isEqualTo(FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[4].copy(isCurrent = true))
+        }
+
+    @Test
+    fun gridOptions_default() =
+        testScope.runTest {
+            val gridOptions = collectLastValue(underTest.gridOptions)
+
+            assertThat(gridOptions()).isEqualTo(FakeShapeGridManager.DEFAULT_GRID_OPTION_LIST)
+        }
+
+    @Test
+    fun gridOptions_shouldUpdateAfterApplyShapeGridOption() =
+        testScope.runTest {
+            val gridOptions = collectLastValue(underTest.gridOptions)
+
+            underTest.applySelectedOption("circle", "practical")
+
+            assertThat(gridOptions())
+                .isEqualTo(
+                    FakeShapeGridManager.DEFAULT_GRID_OPTION_LIST.map {
+                        it.copy(isCurrent = (it.key == "practical"))
+                    }
+                )
+        }
+
+    @Test
+    fun selectedGridOption_default() =
+        testScope.runTest {
+            val selectedGridOption = collectLastValue(underTest.selectedGridOption)
+
+            assertThat(selectedGridOption())
+                .isEqualTo(FakeShapeGridManager.DEFAULT_GRID_OPTION_LIST[0])
+        }
+
+    @Test
+    fun selectedGridOption_shouldUpdateAfterApplyShapeGridOption() =
+        testScope.runTest {
+            val selectedGridOption = collectLastValue(underTest.selectedGridOption)
+
+            underTest.applySelectedOption("circle", "practical")
+
+            assertThat(selectedGridOption())
+                .isEqualTo(FakeShapeGridManager.DEFAULT_GRID_OPTION_LIST[1].copy(isCurrent = true))
+        }
+}
diff --git a/tests/robotests/src/com/android/customization/picker/grid/domain/interactor/ShapeGridInteractorTest.kt b/tests/robotests/src/com/android/customization/picker/grid/domain/interactor/ShapeGridInteractorTest.kt
new file mode 100644
index 0000000..c0f519c
--- /dev/null
+++ b/tests/robotests/src/com/android/customization/picker/grid/domain/interactor/ShapeGridInteractorTest.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.grid.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.customization.model.grid.FakeShapeGridManager
+import com.android.customization.picker.grid.data.repository.ShapeGridRepository
+import com.android.wallpaper.testing.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import dagger.hilt.android.testing.HiltAndroidRule
+import dagger.hilt.android.testing.HiltAndroidTest
+import javax.inject.Inject
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@HiltAndroidTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(RobolectricTestRunner::class)
+class ShapeGridInteractorTest {
+
+    @get:Rule var hiltRule = HiltAndroidRule(this)
+    @Inject lateinit var gridOptionsManager: FakeShapeGridManager
+    @Inject lateinit var repository: ShapeGridRepository
+    @Inject lateinit var testScope: TestScope
+
+    private lateinit var underTest: ShapeGridInteractor
+
+    @Before
+    fun setUp() {
+        hiltRule.inject()
+        underTest = ShapeGridInteractor(repository)
+    }
+
+    @After
+    fun tearDown() {
+        Dispatchers.resetMain()
+    }
+
+    @Test
+    fun shapeOptions_default() =
+        testScope.runTest {
+            val shapeOptions = collectLastValue(underTest.shapeOptions)
+
+            assertThat(shapeOptions()).isEqualTo(FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST)
+        }
+
+    @Test
+    fun shapeOptions_shouldUpdateAfterApplyGridOption() =
+        testScope.runTest {
+            val shapeOptions = collectLastValue(underTest.shapeOptions)
+
+            underTest.applySelectedOption("circle", "practical")
+
+            assertThat(shapeOptions())
+                .isEqualTo(
+                    FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST.map {
+                        it.copy(isCurrent = (it.key == "circle"))
+                    }
+                )
+        }
+
+    @Test
+    fun selectedShapeOption_default() =
+        testScope.runTest {
+            val selectedShapeOption = collectLastValue(underTest.selectedShapeOption)
+
+            assertThat(selectedShapeOption())
+                .isEqualTo(FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[0])
+        }
+
+    @Test
+    fun selectedShapeOption_shouldUpdateAfterApplyGridOption() =
+        testScope.runTest {
+            val selectedShapeOption = collectLastValue(underTest.selectedShapeOption)
+
+            underTest.applySelectedOption("circle", "practical")
+
+            assertThat(selectedShapeOption())
+                .isEqualTo(FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[4].copy(isCurrent = true))
+        }
+
+    @Test
+    fun gridOptions_default() =
+        testScope.runTest {
+            val gridOptions = collectLastValue(underTest.gridOptions)
+
+            assertThat(gridOptions()).isEqualTo(FakeShapeGridManager.DEFAULT_GRID_OPTION_LIST)
+        }
+
+    @Test
+    fun gridOptions_shouldUpdateAfterApplyGridOption() =
+        testScope.runTest {
+            val gridOptions = collectLastValue(underTest.gridOptions)
+
+            underTest.applySelectedOption("arch", "practical")
+
+            assertThat(gridOptions())
+                .isEqualTo(
+                    FakeShapeGridManager.DEFAULT_GRID_OPTION_LIST.map {
+                        it.copy(isCurrent = (it.key == "practical"))
+                    }
+                )
+        }
+
+    @Test
+    fun selectedGridOption_default() =
+        testScope.runTest {
+            val selectedGridOption = collectLastValue(underTest.selectedGridOption)
+
+            assertThat(selectedGridOption())
+                .isEqualTo(FakeShapeGridManager.DEFAULT_GRID_OPTION_LIST[0])
+        }
+
+    @Test
+    fun selectedGridOption_shouldUpdateAfterApplyGridOption() =
+        testScope.runTest {
+            val selectedGridOption = collectLastValue(underTest.selectedGridOption)
+
+            underTest.applySelectedOption("arch", "practical")
+
+            assertThat(selectedGridOption())
+                .isEqualTo(FakeShapeGridManager.DEFAULT_GRID_OPTION_LIST[1].copy(isCurrent = true))
+        }
+}
diff --git a/tests/robotests/src/com/android/customization/picker/mode/ui/viewmodel/DarkModeViewModelTest.kt b/tests/robotests/src/com/android/customization/picker/mode/ui/viewmodel/DarkModeViewModelTest.kt
new file mode 100644
index 0000000..4078803
--- /dev/null
+++ b/tests/robotests/src/com/android/customization/picker/mode/ui/viewmodel/DarkModeViewModelTest.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.customization.picker.mode.ui.viewmodel
+
+import com.android.customization.module.logging.TestThemesUserEventLogger
+import com.android.customization.picker.mode.data.repository.DarkModeRepository
+import com.android.customization.picker.mode.domain.interactor.DarkModeInteractor
+import com.android.wallpaper.testing.FakePowerManager
+import com.android.wallpaper.testing.FakeUiModeManager
+import com.android.wallpaper.testing.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import dagger.hilt.android.testing.HiltAndroidRule
+import dagger.hilt.android.testing.HiltAndroidTest
+import javax.inject.Inject
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@HiltAndroidTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(RobolectricTestRunner::class)
+class DarkModeViewModelTest {
+    @get:Rule var hiltRule = HiltAndroidRule(this)
+
+    @Inject lateinit var uiModeManager: FakeUiModeManager
+    @Inject lateinit var powerManager: FakePowerManager
+    @Inject lateinit var darkModeRepository: DarkModeRepository
+    @Inject lateinit var darkModeInteractor: DarkModeInteractor
+    @Inject lateinit var logger: TestThemesUserEventLogger
+    lateinit var darkModeViewModel: DarkModeViewModel
+
+    @Inject lateinit var testDispatcher: TestDispatcher
+    @Inject lateinit var testScope: TestScope
+
+    @Before
+    fun setUp() {
+        hiltRule.inject()
+        Dispatchers.setMain(testDispatcher)
+
+        darkModeViewModel = DarkModeViewModel(darkModeInteractor, logger)
+    }
+
+    @Test
+    fun isEnabled_powerSaveModeOn() {
+        testScope.runTest {
+            powerManager.setIsPowerSaveMode(true)
+            darkModeRepository.refreshIsPowerSaveModeActivated()
+
+            val isEnabled = collectLastValue(darkModeViewModel.isEnabled)()
+
+            assertThat(isEnabled).isFalse()
+        }
+    }
+
+    @Test
+    fun isEnabled_powerSaveModeOff() {
+        testScope.runTest {
+            powerManager.setIsPowerSaveMode(false)
+            darkModeRepository.refreshIsPowerSaveModeActivated()
+
+            val isEnabled = collectLastValue(darkModeViewModel.isEnabled)()
+
+            assertThat(isEnabled).isTrue()
+        }
+    }
+
+    @Test
+    fun toggleDarkMode() {
+        testScope.runTest {
+            uiModeManager.setNightModeActivated(false)
+            darkModeRepository.refreshIsDarkModeActivated()
+            val getPreviewingIsDarkMode = collectLastValue(darkModeViewModel.previewingIsDarkMode)
+            val getToggleDarkMode = collectLastValue(darkModeViewModel.toggleDarkMode)
+            assertThat(getPreviewingIsDarkMode()).isFalse()
+
+            getToggleDarkMode()?.invoke()
+
+            assertThat(getPreviewingIsDarkMode()).isTrue()
+
+            getToggleDarkMode()?.invoke()
+
+            assertThat(getPreviewingIsDarkMode()).isFalse()
+        }
+    }
+
+    @Test
+    fun onApply_shouldLogDarkTheme() {
+        testScope.runTest {
+            uiModeManager.setNightModeActivated(false)
+            darkModeRepository.refreshIsDarkModeActivated()
+            val getToggleDarkMode = collectLastValue(darkModeViewModel.toggleDarkMode)
+            val onApply = collectLastValue(darkModeViewModel.onApply)
+
+            getToggleDarkMode()?.invoke()
+            onApply()?.invoke()
+
+            assertThat(logger.useDarkTheme).isTrue()
+        }
+    }
+
+    @Test
+    fun onApply_shouldApplyDarkTheme() {
+        testScope.runTest {
+            uiModeManager.setNightModeActivated(false)
+            darkModeRepository.refreshIsDarkModeActivated()
+            val getToggleDarkMode = collectLastValue(darkModeViewModel.toggleDarkMode)
+            val onApply = collectLastValue(darkModeViewModel.onApply)
+
+            getToggleDarkMode()?.invoke()
+            onApply()?.invoke()
+
+            assertThat(uiModeManager.getIsNightModeActivated()).isTrue()
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModelTest.kt b/tests/robotests/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModelTest.kt
index e9f7ffd..cab4b12 100644
--- a/tests/robotests/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModelTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModelTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
 import com.android.systemui.shared.settings.data.repository.FakeSecureSettingsRepository
+import com.android.systemui.shared.settings.data.repository.FakeSystemSettingsRepository
 import com.android.wallpaper.testing.collectLastValue
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
@@ -59,9 +60,10 @@
             NotificationSettingsInteractor(
                 repository =
                     NotificationSettingsRepository(
-                        scope = testScope.backgroundScope,
+                        backgroundScope = testScope.backgroundScope,
                         backgroundDispatcher = testDispatcher,
                         secureSettingsRepository = FakeSecureSettingsRepository(),
+                        systemSettingsRepository = FakeSystemSettingsRepository(),
                     ),
             )
 
diff --git a/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModelTest.kt b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModelTest.kt
new file mode 100644
index 0000000..0a8aa53
--- /dev/null
+++ b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ClockPickerViewModelTest.kt
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.content.Context
+import androidx.test.filters.SmallTest
+import com.android.customization.module.logging.TestThemesUserEventLogger
+import com.android.customization.picker.clock.data.repository.FakeClockPickerRepository
+import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
+import com.android.customization.picker.clock.domain.interactor.ClockPickerSnapshotRestorer
+import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.customization.picker.clock.ui.viewmodel.ClockColorViewModel
+import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
+import com.android.customization.picker.color.data.repository.FakeColorPickerRepository
+import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer
+import com.android.wallpaper.customization.ui.viewmodel.ClockPickerViewModel.Tab
+import com.android.wallpaper.testing.FakeSnapshotStore
+import com.android.wallpaper.testing.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.android.testing.HiltAndroidRule
+import dagger.hilt.android.testing.HiltAndroidTest
+import javax.inject.Inject
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@HiltAndroidTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(RobolectricTestRunner::class)
+class ClockPickerViewModelTest {
+
+    private val logger = TestThemesUserEventLogger()
+
+    @get:Rule var hiltRule = HiltAndroidRule(this)
+    @Inject @ApplicationContext lateinit var context: Context
+    @Inject lateinit var testDispatcher: TestDispatcher
+    @Inject lateinit var testScope: TestScope
+
+    private lateinit var colorMap: Map<String, ClockColorViewModel>
+    private lateinit var underTest: ClockPickerViewModel
+
+    @Before
+    fun setUp() {
+        hiltRule.inject()
+        Dispatchers.setMain(testDispatcher)
+        val repository = FakeClockPickerRepository()
+        val clockPickerInteractor =
+            ClockPickerInteractor(
+                repository = repository,
+                snapshotRestorer =
+                    ClockPickerSnapshotRestorer(repository = repository).apply {
+                        runBlocking { setUpSnapshotRestorer(store = FakeSnapshotStore()) }
+                    },
+            )
+        val colorPickerRepository = FakeColorPickerRepository(context = context)
+        val colorPickerInteractor =
+            ColorPickerInteractor(
+                repository = colorPickerRepository,
+                snapshotRestorer =
+                    ColorPickerSnapshotRestorer(repository = colorPickerRepository).apply {
+                        runBlocking { setUpSnapshotRestorer(store = FakeSnapshotStore()) }
+                    },
+            )
+        colorMap = ClockColorViewModel.getPresetColorMap(context.resources)
+        underTest =
+            ClockPickerViewModel(
+                context = context,
+                resources = context.resources,
+                clockPickerInteractor = clockPickerInteractor,
+                colorPickerInteractor = colorPickerInteractor,
+                logger = logger,
+                backgroundDispatcher = testDispatcher,
+                viewModelScope = testScope,
+            )
+
+        testScope.launch {
+            clockPickerInteractor.setSelectedClock(FakeClockPickerRepository.CLOCK_ID_0)
+        }
+    }
+
+    @After
+    fun tearDown() {
+        Dispatchers.resetMain()
+    }
+
+    @Test
+    fun selectedTab_whenClickOnTabs() = runTest {
+        val tabs = collectLastValue(underTest.tabs)
+        val selectedTab = collectLastValue(underTest.selectedTab)
+
+        assertThat(selectedTab()).isEqualTo(Tab.STYLE)
+
+        tabs()?.get(1)?.onClick?.invoke()
+
+        assertThat(selectedTab()).isEqualTo(Tab.COLOR)
+    }
+
+    @Test
+    fun tabs_whenClickOnTabs() = runTest {
+        val tabs = collectLastValue(underTest.tabs)
+
+        assertThat(tabs()?.get(0)?.isSelected).isTrue()
+
+        tabs()?.get(1)?.onClick?.invoke()
+
+        assertThat(tabs()?.get(1)?.isSelected).isTrue()
+    }
+
+    @Test
+    fun selectedTab_fontEditorWhenClickSelectedClock() = runTest {
+        val clockStyleOptions = collectLastValue(underTest.clockStyleOptions)
+        val selectedTab = collectLastValue(underTest.selectedTab)
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+        assertThat(selectedTab()).isEqualTo(Tab.STYLE)
+
+        val firstClock = clockStyleOptions()!![0]
+        val onClicked = collectLastValue(firstClock.onClicked)
+        if (!firstClock.isSelected.value) onClicked()?.invoke()
+        onClicked()?.invoke()
+
+        assertThat(selectedTab()).isEqualTo(Tab.FONT)
+    }
+
+    @Test
+    fun previewingClock_whenClickOnStyleOptions() = runTest {
+        val previewingClock = collectLastValue(underTest.previewingClock)
+        val clockStyleOptions = collectLastValue(underTest.clockStyleOptions)
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(previewingClock()?.clockId).isEqualTo(FakeClockPickerRepository.CLOCK_ID_0)
+
+        val option1OnClicked = collectLastValue(clockStyleOptions()!![1].onClicked)
+        option1OnClicked()?.invoke()
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockColorOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(previewingClock()?.clockId).isEqualTo(FakeClockPickerRepository.CLOCK_ID_1)
+    }
+
+    @Test
+    fun clockStyleOptions_whenClickOnStyleOptions() = runTest {
+        val clockStyleOptions = collectLastValue(underTest.clockStyleOptions)
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+        val option0IsSelected = collectLastValue(clockStyleOptions()!![0].isSelected)
+        val option0OnClicked = collectLastValue(clockStyleOptions()!![0].onClicked)
+        val option1IsSelected = collectLastValue(clockStyleOptions()!![1].isSelected)
+        val option1OnClicked = collectLastValue(clockStyleOptions()!![1].onClicked)
+
+        assertThat(option0IsSelected()).isTrue()
+        assertThat(option0OnClicked()).isNotNull()
+
+        option1OnClicked()?.invoke()
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockColorOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(option0IsSelected()).isFalse()
+        assertThat(option1IsSelected()).isTrue()
+        assertThat(option1OnClicked()).isNotNull()
+    }
+
+    @Test
+    fun previewingClockSize_whenCallingOnClockSizeSwitchChecked() = runTest {
+        val previewingClockSize = collectLastValue(underTest.previewingClockSize)
+
+        assertThat(previewingClockSize()).isEqualTo(ClockSize.DYNAMIC)
+
+        val onClockSizeSwitchCheckedChange =
+            collectLastValue(underTest.onClockSizeSwitchCheckedChange)
+        onClockSizeSwitchCheckedChange()?.invoke()
+
+        assertThat(previewingClockSize()).isEqualTo(ClockSize.SMALL)
+    }
+
+    @Test
+    fun previewingFontAxes_defaultWhenNoOverrides() = runTest {
+        val previewingFontAxes = collectLastValue(underTest.previewingFontAxisMap)
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 50f))
+    }
+
+    @Test
+    fun previewingFontAxes_updateAxisChangesSetting() = runTest {
+        val previewingFontAxes = collectLastValue(underTest.previewingFontAxisMap)
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 50f))
+
+        underTest.updatePreviewFontAxis("key", 100f)
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 100f))
+
+        underTest.updatePreviewFontAxis("extra", 10f)
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 100f, "extra" to 10f))
+    }
+
+    @Test
+    fun previewingFontAxes_applyFontEditorExitsTab_keepsPreviewAxis() = runTest {
+        val previewingFontAxes = collectLastValue(underTest.previewingFontAxisMap)
+        val clockStyleOptions = collectLastValue(underTest.clockStyleOptions)
+        val selectedTab = collectLastValue(underTest.selectedTab)
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 50f))
+        assertThat(selectedTab()).isEqualTo(Tab.STYLE)
+
+        val firstClock = clockStyleOptions()!![0]
+        val onClicked = collectLastValue(firstClock.onClicked)
+        if (!firstClock.isSelected.value) onClicked()?.invoke()
+        onClicked()?.invoke()
+        underTest.updatePreviewFontAxis("key", 100f)
+
+        assertThat(selectedTab()).isEqualTo(Tab.FONT)
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 100f))
+
+        underTest.confirmFontAxes()
+
+        assertThat(selectedTab()).isEqualTo(Tab.STYLE)
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 100f))
+    }
+
+    @Test
+    fun previewingFontAxes_revertFontEditorExitsTab_revertsPreviewAxis() = runTest {
+        val previewingFontAxes = collectLastValue(underTest.previewingFontAxisMap)
+        val clockStyleOptions = collectLastValue(underTest.clockStyleOptions)
+        val selectedTab = collectLastValue(underTest.selectedTab)
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 50f))
+        assertThat(selectedTab()).isEqualTo(Tab.STYLE)
+
+        val firstClock = clockStyleOptions()!![0]
+        val onClicked = collectLastValue(firstClock.onClicked)
+        if (!firstClock.isSelected.value) onClicked()?.invoke()
+        onClicked()?.invoke()
+        underTest.updatePreviewFontAxis("key", 100f)
+
+        assertThat(selectedTab()).isEqualTo(Tab.FONT)
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 100f))
+
+        underTest.cancelFontAxes()
+
+        assertThat(selectedTab()).isEqualTo(Tab.STYLE)
+        assertThat(previewingFontAxes()).isEqualTo(mapOf("key" to 50f))
+    }
+
+    @Test
+    fun sliderProgress_whenOnSliderProgressChanged() = runTest {
+        val sliderProgress = collectLastValue(underTest.previewingSliderProgress)
+
+        assertThat(sliderProgress()).isEqualTo(ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS)
+
+        underTest.onSliderProgressChanged(87)
+
+        assertThat(sliderProgress()).isEqualTo(87)
+    }
+
+    @Test
+    fun isSliderEnabledShouldBeTrue_whenTheClockIsReactiveToToneAndSolidColor() = runTest {
+        val clockStyleOptions = collectLastValue(underTest.clockStyleOptions)
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+        val styleOption0OnClicked = collectLastValue(clockStyleOptions()!![0].onClicked)
+        val clockColorOptions = collectLastValue(underTest.clockColorOptions)
+        // Advance COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from
+        // clockColorOptions
+        advanceTimeBy(ClockPickerViewModel.COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS)
+        val colorOption1OnClicked = collectLastValue(clockColorOptions()!![1].onClicked)
+        val isSliderEnabled = collectLastValue(underTest.isSliderEnabled)
+
+        styleOption0OnClicked()?.invoke()
+        colorOption1OnClicked()?.invoke()
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(isSliderEnabled()).isTrue()
+    }
+
+    @Test
+    fun isSliderEnabledShouldBeFalse_whenTheClockIsReactiveToToneAndDefaultColor() = runTest {
+        val clockStyleOptions = collectLastValue(underTest.clockStyleOptions)
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+        val styleOption0OnClicked = collectLastValue(clockStyleOptions()!![0].onClicked)
+        val clockColorOptions = collectLastValue(underTest.clockColorOptions)
+        // Advance COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from
+        // clockColorOptions
+        advanceTimeBy(ClockPickerViewModel.COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS)
+        val colorOption0OnClicked = collectLastValue(clockColorOptions()!![0].onClicked)
+        val isSliderEnabled = collectLastValue(underTest.isSliderEnabled)
+
+        styleOption0OnClicked()?.invoke()
+        colorOption0OnClicked()?.invoke()
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(isSliderEnabled()).isFalse()
+    }
+
+    @Test
+    fun isSliderEnabledShouldBeFalse_whenTheClockIsNotReactiveToTone() = runTest {
+        val clockStyleOptions = collectLastValue(underTest.clockStyleOptions)
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+        val styleOption3OnClicked = collectLastValue(clockStyleOptions()!![3].onClicked)
+        val isSliderEnabled = collectLastValue(underTest.isSliderEnabled)
+
+        styleOption3OnClicked()?.invoke()
+        // Advance CLOCKS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from clockStyleOptions
+        advanceTimeBy(ClockPickerViewModel.CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(isSliderEnabled()).isFalse()
+    }
+
+    @Test
+    fun previewingSeedColor_whenChangeColorOptionAndToneProgress() = runTest {
+        val previewingSeedColor = collectLastValue(underTest.previewingSeedColor)
+        val clockColorOptions = collectLastValue(underTest.clockColorOptions)
+        // Advance COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from
+        // clockColorOptions
+        advanceTimeBy(ClockPickerViewModel.COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS)
+        val option1OnClicked = collectLastValue(clockColorOptions()!![1].onClicked)
+
+        option1OnClicked()?.invoke()
+        // Advance COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from
+        // clockColorOptions
+        advanceTimeBy(ClockPickerViewModel.COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS)
+        val targetProgress = 55
+        underTest.onSliderProgressChanged(targetProgress)
+
+        val expectedSelectedColorModel = colorMap.values.first() // RED
+        assertThat(previewingSeedColor())
+            .isEqualTo(
+                ClockSettingsViewModel.blendColorWithTone(
+                    expectedSelectedColorModel.color,
+                    expectedSelectedColorModel.getColorTone(targetProgress),
+                )
+            )
+    }
+
+    @Test
+    fun clockColorOptions_whenClickOnColorOptions() = runTest {
+        val clockColorOptions = collectLastValue(underTest.clockColorOptions)
+        // Advance COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from
+        // clockColorOptions
+        advanceTimeBy(ClockPickerViewModel.COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS)
+        val option0IsSelected = collectLastValue(clockColorOptions()!![0].isSelected)
+        val option0OnClicked = collectLastValue(clockColorOptions()!![0].onClicked)
+        val option1IsSelected = collectLastValue(clockColorOptions()!![1].isSelected)
+        val option1OnClicked = collectLastValue(clockColorOptions()!![1].onClicked)
+
+        assertThat(option0IsSelected()).isTrue()
+        assertThat(option0OnClicked()).isNull()
+
+        option1OnClicked()?.invoke()
+        // Advance COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS since there is a delay from
+        // clockColorOptions
+        advanceTimeBy(ClockPickerViewModel.COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS)
+
+        assertThat(option0IsSelected()).isFalse()
+        assertThat(option1IsSelected()).isTrue()
+        assertThat(option1OnClicked()).isNull()
+    }
+}
diff --git a/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ColorPickerViewModel2Test.kt b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ColorPickerViewModel2Test.kt
new file mode 100644
index 0000000..a4d0ba0
--- /dev/null
+++ b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ColorPickerViewModel2Test.kt
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.content.Context
+import android.stats.style.StyleEnums
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.customization.model.color.ColorOptionsProvider
+import com.android.customization.module.logging.TestThemesUserEventLogger
+import com.android.customization.picker.color.data.repository.FakeColorPickerRepository
+import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer
+import com.android.customization.picker.color.shared.model.ColorType
+import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel
+import com.android.systemui.monet.Style
+import com.android.wallpaper.picker.customization.ui.viewmodel.FloatingToolbarTabViewModel
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import com.android.wallpaper.testing.FakeSnapshotStore
+import com.android.wallpaper.testing.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(RobolectricTestRunner::class)
+class ColorPickerViewModel2Test {
+    private val logger = TestThemesUserEventLogger()
+    private lateinit var underTest: ColorPickerViewModel2
+    private lateinit var repository: FakeColorPickerRepository
+    private lateinit var interactor: ColorPickerInteractor
+    private lateinit var store: FakeSnapshotStore
+
+    private lateinit var context: Context
+    private lateinit var testScope: TestScope
+
+    @Before
+    fun setUp() {
+        context = InstrumentationRegistry.getInstrumentation().targetContext
+        val testDispatcher = UnconfinedTestDispatcher()
+        Dispatchers.setMain(testDispatcher)
+        testScope = TestScope(testDispatcher)
+        repository = FakeColorPickerRepository(context = context)
+        store = FakeSnapshotStore()
+
+        interactor =
+            ColorPickerInteractor(
+                repository = repository,
+                snapshotRestorer =
+                    ColorPickerSnapshotRestorer(repository = repository).apply {
+                        runBlocking { setUpSnapshotRestorer(store = store) }
+                    },
+            )
+
+        underTest =
+            ColorPickerViewModel2(
+                context = context,
+                interactor = interactor,
+                logger = logger,
+                viewModelScope = testScope.backgroundScope,
+            )
+
+        repository.setOptions(4, 4, ColorType.WALLPAPER_COLOR, 0)
+    }
+
+    @After
+    fun tearDown() {
+        Dispatchers.resetMain()
+    }
+
+    @Test
+    fun onApply_wallpaperColor_shouldLogColor() =
+        testScope.runTest {
+            repository.setOptions(
+                listOf(
+                    repository.buildWallpaperOption(
+                        ColorOptionsProvider.COLOR_SOURCE_LOCK,
+                        Style.EXPRESSIVE,
+                        121212,
+                    )
+                ),
+                listOf(repository.buildPresetOption(Style.FRUIT_SALAD, -54321)),
+                ColorType.PRESET_COLOR,
+                0,
+            )
+
+            val colorTypes = collectLastValue(underTest.colorTypeTabs)
+            val colorOptions = collectLastValue(underTest.colorOptions)
+
+            // Select "Wallpaper colors" tab
+            colorTypes()?.get(0)?.onClick?.invoke()
+            // Select a color option to preview
+            selectColorOption(colorOptions, 0)
+            // Apply the selected color option
+            applySelectedColorOption()
+
+            assertThat(logger.themeColorSource)
+                .isEqualTo(StyleEnums.COLOR_SOURCE_LOCK_SCREEN_WALLPAPER)
+            assertThat(logger.themeColorStyle).isEqualTo(Style.EXPRESSIVE.toString().hashCode())
+            assertThat(logger.themeSeedColor).isEqualTo(121212)
+        }
+
+    @Test
+    fun onApply_presetColor_shouldLogColor() =
+        testScope.runTest {
+            repository.setOptions(
+                listOf(
+                    repository.buildWallpaperOption(
+                        ColorOptionsProvider.COLOR_SOURCE_LOCK,
+                        Style.EXPRESSIVE,
+                        121212,
+                    )
+                ),
+                listOf(repository.buildPresetOption(Style.FRUIT_SALAD, -54321)),
+                ColorType.WALLPAPER_COLOR,
+                0,
+            )
+
+            val colorTypes = collectLastValue(underTest.colorTypeTabs)
+            val colorOptions = collectLastValue(underTest.colorOptions)
+
+            // Select "Wallpaper colors" tab
+            colorTypes()?.get(1)?.onClick?.invoke()
+            // Select a color option to preview
+            selectColorOption(colorOptions, 0)
+            // Apply the selected color option
+            applySelectedColorOption()
+
+            assertThat(logger.themeColorSource).isEqualTo(StyleEnums.COLOR_SOURCE_PRESET_COLOR)
+            assertThat(logger.themeColorStyle).isEqualTo(Style.FRUIT_SALAD.toString().hashCode())
+            assertThat(logger.themeSeedColor).isEqualTo(-54321)
+        }
+
+    @Test
+    fun selectColorOption() =
+        testScope.runTest {
+            val colorTypes = collectLastValue(underTest.colorTypeTabs)
+            val colorOptions = collectLastValue(underTest.colorOptions)
+
+            // Initially, the wallpaper color tab should be selected
+            assertPickerUiState(
+                colorTypes = colorTypes(),
+                colorOptions = colorOptions(),
+                selectedColorTypeText = "Wallpaper colors",
+                selectedColorOptionIndex = 0,
+            )
+
+            // Select "Basic colors" tab
+            colorTypes()?.get(1)?.onClick?.invoke()
+            assertPickerUiState(
+                colorTypes = colorTypes(),
+                colorOptions = colorOptions(),
+                selectedColorTypeText = "Basic colors",
+                selectedColorOptionIndex = -1,
+            )
+
+            // Select a color option
+            selectColorOption(colorOptions, 2)
+
+            // Check original option is no longer selected
+            colorTypes()?.get(0)?.onClick?.invoke()
+            assertPickerUiState(
+                colorTypes = colorTypes(),
+                colorOptions = colorOptions(),
+                selectedColorTypeText = "Wallpaper colors",
+                selectedColorOptionIndex = -1,
+            )
+
+            // Check new option is selected
+            colorTypes()?.get(1)?.onClick?.invoke()
+            assertPickerUiState(
+                colorTypes = colorTypes(),
+                colorOptions = colorOptions(),
+                selectedColorTypeText = "Basic colors",
+                selectedColorOptionIndex = 2,
+            )
+        }
+
+    /** Simulates a user selecting the affordance at the given index, if that is clickable. */
+    private fun TestScope.selectColorOption(
+        colorOptions: () -> List<OptionItemViewModel<ColorOptionIconViewModel>>?,
+        index: Int,
+    ) {
+        val onClickedFlow = colorOptions()?.get(index)?.onClicked
+        val onClickedLastValueOrNull: (() -> (() -> Unit)?)? =
+            onClickedFlow?.let { collectLastValue(it) }
+        onClickedLastValueOrNull?.let { onClickedLastValue ->
+            val onClickedOrNull: (() -> Unit)? = onClickedLastValue()
+            onClickedOrNull?.invoke()
+        }
+    }
+
+    /** Simulates a user selecting the affordance at the given index, if that is clickable. */
+    private suspend fun TestScope.applySelectedColorOption() {
+        val onApply = collectLastValue(underTest.onApply)()
+        onApply?.invoke()
+    }
+
+    /**
+     * Asserts the entire picker UI state is what is expected. This includes the color type tabs and
+     * the color options list.
+     *
+     * @param colorTypes The observed color type view-models, keyed by ColorType
+     * @param colorOptions The observed color options
+     * @param selectedColorTypeText The text of the color type that's expected to be selected
+     * @param selectedColorOptionIndex The index of the color option that's expected to be selected,
+     *   -1 stands for no color option should be selected
+     */
+    private fun TestScope.assertPickerUiState(
+        colorTypes: List<FloatingToolbarTabViewModel>?,
+        colorOptions: List<OptionItemViewModel<ColorOptionIconViewModel>>?,
+        selectedColorTypeText: String,
+        selectedColorOptionIndex: Int,
+    ) {
+        assertColorTypeTabUiState(
+            colorTypes = colorTypes,
+            colorTypeId = ColorType.WALLPAPER_COLOR,
+            isSelected = "Wallpaper colors" == selectedColorTypeText,
+        )
+        assertColorTypeTabUiState(
+            colorTypes = colorTypes,
+            colorTypeId = ColorType.PRESET_COLOR,
+            isSelected = "Basic colors" == selectedColorTypeText,
+        )
+        assertColorOptionUiState(colorOptions, selectedColorOptionIndex)
+    }
+
+    /**
+     * Asserts the picker section UI state is what is expected.
+     *
+     * @param colorOptions The observed color options
+     * @param selectedColorOptionIndex The index of the color option that's expected to be selected,
+     *   -1 stands for no color option should be selected
+     */
+    private fun TestScope.assertColorOptionUiState(
+        colorOptions: List<OptionItemViewModel<ColorOptionIconViewModel>>?,
+        selectedColorOptionIndex: Int,
+    ) {
+        var foundSelectedColorOption = false
+        assertThat(colorOptions).isNotNull()
+        if (colorOptions != null) {
+            for (i in colorOptions.indices) {
+                val colorOptionHasSelectedIndex = i == selectedColorOptionIndex
+                val isSelected: Boolean? = collectLastValue(colorOptions[i].isSelected).invoke()
+                assertWithMessage(
+                        "Expected color option with index \"${i}\" to have" +
+                            " isSelected=$colorOptionHasSelectedIndex but it was" +
+                            " ${isSelected}, num options: ${colorOptions.size}"
+                    )
+                    .that(isSelected)
+                    .isEqualTo(colorOptionHasSelectedIndex)
+                foundSelectedColorOption = foundSelectedColorOption || colorOptionHasSelectedIndex
+            }
+            if (selectedColorOptionIndex == -1) {
+                assertWithMessage(
+                        "Expected no color options to be selected, but a color option is" +
+                            " selected"
+                    )
+                    .that(foundSelectedColorOption)
+                    .isFalse()
+            } else {
+                assertWithMessage(
+                        "Expected a color option to be selected, but no color option is" +
+                            " selected"
+                    )
+                    .that(foundSelectedColorOption)
+                    .isTrue()
+            }
+        }
+    }
+
+    /**
+     * Asserts that a color type tab has the correct UI state.
+     *
+     * @param colorTypes The observed color type view-models, keyed by ColorType enum
+     * @param colorTypeId the ID of the color type to assert
+     * @param isSelected Whether that color type should be selected
+     */
+    private fun assertColorTypeTabUiState(
+        colorTypes: List<FloatingToolbarTabViewModel>?,
+        colorTypeId: ColorType,
+        isSelected: Boolean,
+    ) {
+        val position = if (colorTypeId == ColorType.WALLPAPER_COLOR) 0 else 1
+        val viewModel =
+            colorTypes?.get(position) ?: error("No color type with ID \"$colorTypeId\"!")
+        assertThat(viewModel.isSelected).isEqualTo(isSelected)
+    }
+}
diff --git a/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/KeyguardQuickAffordancePickerViewModel2Test.kt b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/KeyguardQuickAffordancePickerViewModel2Test.kt
new file mode 100644
index 0000000..b6f249e
--- /dev/null
+++ b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/KeyguardQuickAffordancePickerViewModel2Test.kt
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.android.customization.module.logging.TestThemesUserEventLogger
+import com.android.customization.picker.quickaffordance.data.repository.KeyguardQuickAffordancePickerRepository
+import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
+import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordanceSnapshotRestorer
+import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
+import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient
+import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import com.android.themepicker.R
+import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
+import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
+import com.android.wallpaper.picker.customization.ui.viewmodel.FloatingToolbarTabViewModel
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import com.android.wallpaper.testing.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(RobolectricTestRunner::class)
+class KeyguardQuickAffordancePickerViewModel2Test {
+
+    private val logger = TestThemesUserEventLogger()
+
+    private lateinit var underTest: KeyguardQuickAffordancePickerViewModel2
+
+    private lateinit var context: Context
+    private lateinit var testDispatcher: TestDispatcher
+    private lateinit var testScope: TestScope
+    private lateinit var client: FakeCustomizationProviderClient
+
+    @Before
+    fun setUp() {
+        context = ApplicationProvider.getApplicationContext()
+        testDispatcher = UnconfinedTestDispatcher()
+        Dispatchers.setMain(testDispatcher)
+        testScope = TestScope(testDispatcher)
+        client = FakeCustomizationProviderClient()
+        val quickAffordanceInteractor =
+            KeyguardQuickAffordancePickerInteractor(
+                repository =
+                    KeyguardQuickAffordancePickerRepository(
+                        client = client,
+                        mainScope = testScope.backgroundScope,
+                    ),
+                client = client,
+                snapshotRestorer = KeyguardQuickAffordanceSnapshotRestorer(client),
+            )
+        underTest =
+            KeyguardQuickAffordancePickerViewModel2(
+                applicationContext = context,
+                quickAffordanceInteractor = quickAffordanceInteractor,
+                logger = logger,
+                viewModelScope = testScope.backgroundScope,
+            )
+    }
+
+    @After
+    fun tearDown() {
+        Dispatchers.resetMain()
+    }
+
+    @Test
+    fun selectedSlotIdUpdates_whenClickingOnTabsAndCallingResetPreview() =
+        testScope.runTest {
+            val selectedSlotId = collectLastValue(underTest.selectedSlotId)
+
+            val tabs = collectLastValue(underTest.tabs)
+
+            // Default selected slot ID is bottom_start
+            assertThat(selectedSlotId())
+                .isEqualTo(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START)
+
+            // Click on tab1
+            val tab1 = tabs()?.get(1) ?: throw NullPointerException("secondTab should not be null.")
+            tab1.onClick?.invoke()
+            assertThat(selectedSlotId()).isEqualTo(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END)
+
+            underTest.resetPreview()
+            assertThat(selectedSlotId())
+                .isEqualTo(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START)
+        }
+
+    @Test
+    fun selectedQuickAffordancesMapUpdates_whenClickingOnQuickAffordanceOptionsAndCallingResetPreview() =
+        testScope.runTest {
+            val previewingQuickAffordances = collectLastValue(underTest.previewingQuickAffordances)
+
+            val tabs = collectLastValue(underTest.tabs)
+            val quickAffordances = collectLastValue(underTest.quickAffordances)
+
+            // Default selectedQuickAffordances is an empty map
+            assertThat(previewingQuickAffordances()).isEqualTo(emptyMap<String, String>())
+
+            // Click on quick affordance 1 when selected slot ID is bottom_start
+            val onClickAffordance1 =
+                collectLastValue(quickAffordances()?.get(1)?.onClicked ?: emptyFlow())
+            onClickAffordance1()?.invoke()
+            assertThat(previewingQuickAffordances())
+                .isEqualTo(
+                    mapOf(
+                        KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
+                            FakeCustomizationProviderClient.AFFORDANCE_1
+                    )
+                )
+
+            // Click on tab 1 to change the selected slot ID to bottom_end and click on quick
+            // affordance 2
+            tabs()?.get(1)?.onClick?.invoke()
+            val onClickAffordance2 =
+                collectLastValue(quickAffordances()?.get(2)?.onClicked ?: emptyFlow())
+            onClickAffordance2()?.invoke()
+            assertThat(previewingQuickAffordances())
+                .isEqualTo(
+                    mapOf(
+                        KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
+                            FakeCustomizationProviderClient.AFFORDANCE_1,
+                        KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to
+                            FakeCustomizationProviderClient.AFFORDANCE_2
+                    )
+                )
+
+            underTest.resetPreview()
+            assertThat(previewingQuickAffordances()).isEqualTo(emptyMap<String, String>())
+        }
+
+    @Test
+    fun tabsUpdates_whenClickingOnTabsAndQuickAffordanceOptions() =
+        testScope.runTest {
+            val tabs = collectLastValue(underTest.tabs)
+
+            val quickAffordances = collectLastValue(underTest.quickAffordances)
+
+            // Default state of the 2 tabs
+            assertTabUiState(
+                tab = tabs()?.get(0),
+                icon = Icon.Resource(R.drawable.link_off, null),
+                text = "Left shortcut",
+                isSelected = true,
+            )
+            assertTabUiState(
+                tab = tabs()?.get(1),
+                icon = Icon.Resource(R.drawable.link_off, null),
+                text = "Right shortcut",
+                isSelected = false,
+            )
+
+            // Click on tab 1
+            tabs()?.get(1)?.onClick?.invoke()
+            assertTabUiState(
+                tab = tabs()?.get(0),
+                icon = Icon.Resource(R.drawable.link_off, null),
+                text = "Left shortcut",
+                isSelected = false,
+            )
+            val tab1 = tabs()?.get(1)
+            assertTabUiState(
+                tab = tab1,
+                icon = Icon.Resource(R.drawable.link_off, null),
+                text = "Right shortcut",
+                isSelected = true,
+            )
+
+            // Click on quick affordance 1 when tab 1 is selected. Icon should change
+            val clickOnQuickAffordance1 =
+                collectLastValue(quickAffordances()?.get(1)?.onClicked ?: emptyFlow())
+            clickOnQuickAffordance1()?.invoke()
+            assertTabUiState(
+                tab = tabs()?.get(1),
+                icon =
+                    Icon.Loaded(
+                        FakeCustomizationProviderClient.ICON_1,
+                        Text.Loaded("Right shortcut")
+                    ),
+                text = "Right shortcut",
+                isSelected = true,
+            )
+        }
+
+    @Test
+    fun quickAffordancesUpdates_whenClickingOnTabsAndQuickAffordanceOptions() =
+        testScope.runTest {
+            val quickAffordances = collectLastValue(underTest.quickAffordances)
+
+            val tabs = collectLastValue(underTest.tabs)
+
+            // The default quickAffordances snapshot
+            assertThat(quickAffordances()?.size).isEqualTo(4)
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(0),
+                key = "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::none",
+                icon = Icon.Resource(R.drawable.link_off, null),
+                text = Text.Resource(R.string.keyguard_affordance_none),
+                isSelected = true,
+            )
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(1),
+                key =
+                    "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${FakeCustomizationProviderClient.AFFORDANCE_1}",
+                icon = Icon.Loaded(FakeCustomizationProviderClient.ICON_1, null),
+                text = Text.Loaded(FakeCustomizationProviderClient.AFFORDANCE_1),
+                isSelected = false,
+            )
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(2),
+                key =
+                    "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${FakeCustomizationProviderClient.AFFORDANCE_2}",
+                icon = Icon.Loaded(FakeCustomizationProviderClient.ICON_2, null),
+                text = Text.Loaded(FakeCustomizationProviderClient.AFFORDANCE_2),
+                isSelected = false,
+            )
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(3),
+                key =
+                    "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${FakeCustomizationProviderClient.AFFORDANCE_3}",
+                icon = Icon.Loaded(FakeCustomizationProviderClient.ICON_3, null),
+                text = Text.Loaded(FakeCustomizationProviderClient.AFFORDANCE_3),
+                isSelected = false,
+            )
+
+            // Click on quick affordance 2. Quick affordance 0 will be unselected and quick
+            // affordance 2 will be selected.
+            val onClickQuickAffordance2 =
+                collectLastValue(quickAffordances()?.get(2)?.onClicked ?: emptyFlow())
+            onClickQuickAffordance2()?.invoke()
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(0),
+                key = "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::none",
+                icon = Icon.Resource(R.drawable.link_off, null),
+                text = Text.Resource(R.string.keyguard_affordance_none),
+                isSelected = false,
+            )
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(2),
+                key =
+                    "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${FakeCustomizationProviderClient.AFFORDANCE_2}",
+                icon = Icon.Loaded(FakeCustomizationProviderClient.ICON_2, null),
+                text = Text.Loaded(FakeCustomizationProviderClient.AFFORDANCE_2),
+                isSelected = true,
+            )
+
+            tabs()?.get(1)?.onClick?.invoke()
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(0),
+                key = "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::none",
+                icon = Icon.Resource(R.drawable.link_off, null),
+                text = Text.Resource(R.string.keyguard_affordance_none),
+                isSelected = true,
+            )
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(1),
+                key =
+                    "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::${FakeCustomizationProviderClient.AFFORDANCE_1}",
+                icon = Icon.Loaded(FakeCustomizationProviderClient.ICON_1, null),
+                text = Text.Loaded(FakeCustomizationProviderClient.AFFORDANCE_1),
+                isSelected = false,
+            )
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(2),
+                key =
+                    "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::${FakeCustomizationProviderClient.AFFORDANCE_2}",
+                icon = Icon.Loaded(FakeCustomizationProviderClient.ICON_2, null),
+                text = Text.Loaded(FakeCustomizationProviderClient.AFFORDANCE_2),
+                isSelected = false,
+            )
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(3),
+                key =
+                    "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::${FakeCustomizationProviderClient.AFFORDANCE_3}",
+                icon = Icon.Loaded(FakeCustomizationProviderClient.ICON_3, null),
+                text = Text.Loaded(FakeCustomizationProviderClient.AFFORDANCE_3),
+                isSelected = false,
+            )
+
+            // When tab 1 is selected, click on quick affordance 3. Quick affordance 0 will be
+            // unselected and quick affordance 3 will be selected.
+            val onClickQuickAffordance3 =
+                collectLastValue(quickAffordances()?.get(3)?.onClicked ?: emptyFlow())
+            onClickQuickAffordance3()?.invoke()
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(0),
+                key = "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::none",
+                icon = Icon.Resource(R.drawable.link_off, null),
+                text = Text.Resource(R.string.keyguard_affordance_none),
+                isSelected = false,
+            )
+            assertQuickAffordance(
+                testScope = this,
+                quickAffordance = quickAffordances()?.get(3),
+                key =
+                    "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::${FakeCustomizationProviderClient.AFFORDANCE_3}",
+                icon = Icon.Loaded(FakeCustomizationProviderClient.ICON_3, null),
+                text = Text.Loaded(FakeCustomizationProviderClient.AFFORDANCE_3),
+                isSelected = true,
+            )
+        }
+
+    @Test
+    fun loggerShouldLogAndClientShouldUpdate_whenOnApply() =
+        testScope.runTest {
+            val onApply = collectLastValue(underTest.onApply)
+
+            val tabs = collectLastValue(underTest.tabs)
+            val quickAffordances = collectLastValue(underTest.quickAffordances)
+
+            // Select the preview quick affordances
+            val onClickAffordance1 =
+                collectLastValue(quickAffordances()?.get(1)?.onClicked ?: emptyFlow())
+            onClickAffordance1()?.invoke()
+            tabs()?.get(1)?.onClick?.invoke()
+            val onClickAffordance2 =
+                collectLastValue(quickAffordances()?.get(2)?.onClicked ?: emptyFlow())
+            onClickAffordance2()?.invoke()
+
+            onApply()?.invoke()
+            assertThat(client.querySelections())
+                .isEqualTo(
+                    listOf(
+                        CustomizationProviderClient.Selection(
+                            slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+                            affordanceId = FakeCustomizationProviderClient.AFFORDANCE_1,
+                            affordanceName = FakeCustomizationProviderClient.AFFORDANCE_1,
+                        ),
+                        CustomizationProviderClient.Selection(
+                            slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
+                            affordanceId = FakeCustomizationProviderClient.AFFORDANCE_2,
+                            affordanceName = FakeCustomizationProviderClient.AFFORDANCE_2,
+                        ),
+                    )
+                )
+            assertThat(logger.shortcutLogs)
+                .isEqualTo(
+                    listOf(
+                        FakeCustomizationProviderClient.AFFORDANCE_1 to
+                            KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+                        FakeCustomizationProviderClient.AFFORDANCE_2 to
+                            KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
+                    )
+                )
+        }
+
+    private fun assertTabUiState(
+        tab: FloatingToolbarTabViewModel?,
+        icon: Icon?,
+        text: String,
+        isSelected: Boolean,
+    ) {
+        if (tab == null) {
+            throw NullPointerException("tab is null.")
+        }
+        assertThat(tab.icon).isEqualTo(icon)
+        assertThat(tab.text).isEqualTo(text)
+        assertThat(tab.isSelected).isEqualTo(isSelected)
+    }
+
+    private fun assertQuickAffordance(
+        testScope: TestScope,
+        quickAffordance: OptionItemViewModel<Icon>?,
+        key: String,
+        icon: Icon,
+        text: Text,
+        isSelected: Boolean,
+    ) {
+        if (quickAffordance == null) {
+            throw NullPointerException("quickAffordance is null.")
+        }
+        assertThat(testScope.collectLastValue(quickAffordance.key)()).isEqualTo(key)
+        assertThat(quickAffordance.payload).isEqualTo(icon)
+        assertThat(quickAffordance.text).isEqualTo(text)
+        assertThat(quickAffordance.isTextUserVisible).isEqualTo(true)
+        assertThat(testScope.collectLastValue(quickAffordance.isSelected)()).isEqualTo(isSelected)
+        assertThat(quickAffordance.isEnabled).isEqualTo(true)
+    }
+}
diff --git a/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModelTest.kt b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModelTest.kt
new file mode 100644
index 0000000..c99acca
--- /dev/null
+++ b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModelTest.kt
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.customization.ui.viewmodel
+
+import android.content.Context
+import android.content.res.Resources
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.android.customization.model.ResourceConstants
+import com.android.customization.model.grid.FakeShapeGridManager
+import com.android.customization.picker.grid.domain.interactor.ShapeGridInteractor
+import com.android.customization.picker.grid.ui.viewmodel.GridIconViewModel
+import com.android.customization.picker.grid.ui.viewmodel.ShapeIconViewModel
+import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import com.android.wallpaper.testing.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.android.testing.HiltAndroidRule
+import dagger.hilt.android.testing.HiltAndroidTest
+import javax.inject.Inject
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@HiltAndroidTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(RobolectricTestRunner::class)
+class ShapeGridPickerViewModelTest {
+
+    @get:Rule var hiltRule = HiltAndroidRule(this)
+    @Inject lateinit var testScope: TestScope
+    @Inject lateinit var gridOptionsManager: FakeShapeGridManager
+    @Inject lateinit var interactor: ShapeGridInteractor
+    @Inject @ApplicationContext lateinit var appContext: Context
+
+    private val iconShapePath =
+        ApplicationProvider.getApplicationContext<Context>()
+            .resources
+            .getString(
+                Resources.getSystem()
+                    .getIdentifier(
+                        ResourceConstants.CONFIG_ICON_MASK,
+                        "string",
+                        ResourceConstants.ANDROID_PACKAGE,
+                    )
+            )
+
+    private lateinit var underTest: ShapeGridPickerViewModel
+
+    @Before
+    fun setUp() {
+        hiltRule.inject()
+        underTest = ShapeGridPickerViewModel(appContext, interactor, testScope.backgroundScope)
+    }
+
+    @After
+    fun tearDown() {
+        Dispatchers.resetMain()
+    }
+
+    @Test
+    fun selectedTabUpdates_whenClickOnGridTab() =
+        testScope.runTest {
+            val selectedTab = collectLastValue(underTest.selectedTab)
+            val tabs = collectLastValue(underTest.tabs)
+            val onGridTabClicked = tabs()?.get(1)?.onClick
+
+            assertThat(selectedTab()).isEqualTo(ShapeGridPickerViewModel.Tab.SHAPE)
+
+            onGridTabClicked?.invoke()
+
+            assertThat(selectedTab()).isEqualTo(ShapeGridPickerViewModel.Tab.GRID)
+        }
+
+    @Test
+    fun selectedShapeKey() =
+        testScope.runTest {
+            val selectedShapeKey = collectLastValue(underTest.selectedShapeKey)
+
+            assertThat(selectedShapeKey()).isEqualTo("arch")
+        }
+
+    @Test
+    fun shapeOptions() =
+        testScope.runTest {
+            val shapeOptions = collectLastValue(underTest.shapeOptions)
+
+            for (i in 0 until FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST.size) {
+                val (expectedKey, expectedPath, expectedTitle) =
+                    with(FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[i]) {
+                        arrayOf(key, path, title)
+                    }
+                assertShapeItem(
+                    optionItem = shapeOptions()?.get(i),
+                    key = FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[i].key,
+                    payload = ShapeIconViewModel(expectedKey, expectedPath),
+                    text = Text.Loaded(expectedTitle),
+                    isTextUserVisible = true,
+                    isSelected = expectedKey == "arch",
+                    isEnabled = true,
+                )
+            }
+        }
+
+    @Test
+    fun shapeOptions_whenClickOnCircleOption() =
+        testScope.runTest {
+            val shapeOptions = collectLastValue(underTest.shapeOptions)
+            val previewingShapeKey = collectLastValue(underTest.previewingShapeKey)
+            val onCircleOptionClicked =
+                shapeOptions()?.get(4)?.onClicked?.let { collectLastValue(it) }
+            checkNotNull(onCircleOptionClicked)
+
+            onCircleOptionClicked()?.invoke()
+
+            assertThat(previewingShapeKey()).isEqualTo("circle")
+            for (i in 0 until FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST.size) {
+                val expectedKey = FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[i].key
+                val expectedPath = FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[i].path
+                val expectedTitle = FakeShapeGridManager.DEFAULT_SHAPE_OPTION_LIST[i].title
+                assertShapeItem(
+                    optionItem = shapeOptions()?.get(i),
+                    key = expectedKey,
+                    payload = ShapeIconViewModel(expectedKey, expectedPath),
+                    text = Text.Loaded(expectedTitle),
+                    isTextUserVisible = true,
+                    isSelected = expectedKey == "circle",
+                    isEnabled = true,
+                )
+            }
+        }
+
+    @Test
+    fun selectedGridOption() =
+        testScope.runTest {
+            val selectedGridOption = collectLastValue(underTest.selectedGridOption)
+
+            assertOptionItem(
+                optionItem = selectedGridOption(),
+                key = "normal",
+                payload = GridIconViewModel(5, 5, iconShapePath),
+                text = Text.Loaded("5x5"),
+                isTextUserVisible = true,
+                isSelected = true,
+                isEnabled = true,
+            )
+        }
+
+    @Test
+    fun selectedGridOption_shouldUpdate_afterOnApply() =
+        testScope.runTest {
+            val selectedGridOption = collectLastValue(underTest.selectedGridOption)
+            val optionItems = collectLastValue(underTest.gridOptions)
+            val onApply = collectLastValue(underTest.onApply)
+            val onPracticalOptionClick =
+                optionItems()?.get(1)?.onClicked?.let { collectLastValue(it) }
+            checkNotNull(onPracticalOptionClick)
+
+            onPracticalOptionClick()?.invoke()
+            onApply()?.invoke()
+
+            assertOptionItem(
+                optionItem = selectedGridOption(),
+                key = "practical",
+                payload = GridIconViewModel(4, 5, iconShapePath),
+                text = Text.Loaded("4x5"),
+                isTextUserVisible = true,
+                isSelected = true,
+                isEnabled = true,
+            )
+        }
+
+    @Test
+    fun optionItems() =
+        testScope.runTest {
+            val optionItems = collectLastValue(underTest.gridOptions)
+
+            assertOptionItem(
+                optionItem = optionItems()?.get(0),
+                key = "normal",
+                payload = GridIconViewModel(5, 5, iconShapePath),
+                text = Text.Loaded("5x5"),
+                isTextUserVisible = true,
+                isSelected = true,
+                isEnabled = true,
+            )
+            assertOptionItem(
+                optionItem = optionItems()?.get(1),
+                key = "practical",
+                payload = GridIconViewModel(4, 5, iconShapePath),
+                text = Text.Loaded("4x5"),
+                isTextUserVisible = true,
+                isSelected = false,
+                isEnabled = true,
+            )
+        }
+
+    @Test
+    fun optionItems_whenClickOnPracticalOption() =
+        testScope.runTest {
+            val optionItems = collectLastValue(underTest.gridOptions)
+            val onPracticalOptionClick =
+                optionItems()?.get(1)?.onClicked?.let { collectLastValue(it) }
+            checkNotNull(onPracticalOptionClick)
+
+            onPracticalOptionClick()?.invoke()
+
+            assertOptionItem(
+                optionItem = optionItems()?.get(0),
+                key = "normal",
+                payload = GridIconViewModel(5, 5, iconShapePath),
+                text = Text.Loaded("5x5"),
+                isTextUserVisible = true,
+                isSelected = false,
+                isEnabled = true,
+            )
+            assertOptionItem(
+                optionItem = optionItems()?.get(1),
+                key = "practical",
+                payload = GridIconViewModel(4, 5, iconShapePath),
+                text = Text.Loaded("4x5"),
+                isTextUserVisible = true,
+                isSelected = true,
+                isEnabled = true,
+            )
+        }
+
+    private fun TestScope.assertShapeItem(
+        optionItem: OptionItemViewModel<ShapeIconViewModel>?,
+        key: String,
+        payload: ShapeIconViewModel?,
+        text: Text,
+        isTextUserVisible: Boolean,
+        isSelected: Boolean,
+        isEnabled: Boolean,
+    ) {
+        checkNotNull(optionItem)
+        assertThat(collectLastValue(optionItem.key)()).isEqualTo(key)
+        assertThat(optionItem.text).isEqualTo(text)
+        assertThat(optionItem.payload).isEqualTo(payload)
+        assertThat(optionItem.isTextUserVisible).isEqualTo(isTextUserVisible)
+        assertThat(collectLastValue(optionItem.isSelected)()).isEqualTo(isSelected)
+        assertThat(optionItem.isEnabled).isEqualTo(isEnabled)
+    }
+
+    private fun TestScope.assertOptionItem(
+        optionItem: OptionItemViewModel<GridIconViewModel>?,
+        key: String,
+        payload: GridIconViewModel?,
+        text: Text,
+        isTextUserVisible: Boolean,
+        isSelected: Boolean,
+        isEnabled: Boolean,
+    ) {
+        checkNotNull(optionItem)
+        assertThat(collectLastValue(optionItem.key)()).isEqualTo(key)
+        assertThat(optionItem.text).isEqualTo(text)
+        assertThat(optionItem.payload).isEqualTo(payload)
+        assertThat(optionItem.isTextUserVisible).isEqualTo(isTextUserVisible)
+        assertThat(collectLastValue(optionItem.isSelected)()).isEqualTo(isSelected)
+        assertThat(optionItem.isEnabled).isEqualTo(isEnabled)
+    }
+}
diff --git a/themes/res/values-mk/strings.xml b/themes/res/values-mk/strings.xml
index 94d1098..5426e3b 100644
--- a/themes/res/values-mk/strings.xml
+++ b/themes/res/values-mk/strings.xml
@@ -24,5 +24,5 @@
     <string name="rainbow_color_name_blue" msgid="3473176664458856892">"Сина"</string>
     <string name="rainbow_color_name_purple" msgid="2704722524588084868">"Виолетова"</string>
     <string name="rainbow_color_name_magenta" msgid="7248703626077785569">"Магента"</string>
-    <string name="monochromatic_name" msgid="2554823570460886176">"Монохроматски"</string>
+    <string name="monochromatic_name" msgid="2554823570460886176">"Еднобојно"</string>
 </resources>