[automerger skipped] Import translations. DO NOT MERGE ANYWHERE am: d07c9a303e -s ours am: c54b4cb296 -s ours am: f31e38369c -s ours

am skip reason: subject contains skip directive

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

Change-Id: I43fe69186fd58c07617c73b8968a8d752dd27af2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index c85fd2b..7bbbb10 100644
--- a/Android.bp
+++ b/Android.bp
@@ -24,22 +24,6 @@
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
-        // Min requirement for CustomizationInjector and StatsLogUserEventLogger to build without Clock and Theme feature.
-        "src/com/android/customization/model/clock/BaseClockManager.java",
-        "src/com/android/customization/model/clock/Clockface.java",
-        "src/com/android/customization/model/clock/ClockManager.java",
-        "src/com/android/customization/model/clock/ClockProvider.java",
-        "src/com/android/customization/model/theme/OverlayManagerCompat.java",
-        "src/com/android/customization/model/theme/ThemeBundleProvider.java",
-        "src/com/android/customization/model/theme/ThemeManager.java",
-        "src/com/android/customization/model/theme/ThemeBundle.java",
-        "src/com/android/customization/model/theme/custom/CustomTheme.java",
-    ],
-    exclude_srcs: [
-        "src/com/android/customization/model/clock/**/*.java",
-        "src/com/android/customization/model/theme/**/*.java",
-        "src/com/android/customization/picker/clock/**/*.java",
-        "src/com/android/customization/picker/theme/**/*.java",
     ],
 }
 
@@ -54,7 +38,7 @@
     name: "ThemePicker_res",
     tools: ["soong_zip"],
     srcs: [
-        "res/**/*"
+        "res/**/*",
     ],
     out: ["ThemePicker_res.zip"],
     cmd: "INPUTS=($(in)) && "
@@ -89,6 +73,10 @@
         "src_override/**/*.kt",
     ],
 
+    resource_dirs: [
+        "res_override",
+    ],
+
     use_embedded_native_libs: true,
 
     resource_zips: [":WallpaperPicker2_res", ":ThemePicker_res"],
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ff8f187..ee96ae3 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -13,6 +13,8 @@
 
     <queries>
         <!-- Specific intents Wallpaper picker query for -->
+        <!-- Package for theme stub -->
+        <package android:name="com.android.customization.themes" />
         <!-- Intent filter with action SET_WALLPAPER -->
         <intent>
             <action android:name="android.intent.action.SET_WALLPAPER" />
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index f3db20e..b659bfa 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,4 @@
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+
+ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/packages/apps/ThemePicker/ktfmt_includes.txt ${PREUPLOAD_FILES}
diff --git a/ktfmt_includes.txt b/ktfmt_includes.txt
new file mode 100644
index 0000000..703e852
--- /dev/null
+++ b/ktfmt_includes.txt
@@ -0,0 +1,7 @@
++src/
++src_override/
++tests/
+-src/com/android/customization/model/color/ColorProvider.kt
+-src/com/android/customization/model/color/ColorUtils.kt
+-src/com/android/customization/module/SysUiStatsLogger.kt
+-src/com/android/customization/picker/clock/ClockSectionView.kt
diff --git a/res/drawable/ic_clock_24px.xml b/res/drawable/ic_clock_24px.xml
new file mode 100644
index 0000000..b3f1fee
--- /dev/null
+++ b/res/drawable/ic_clock_24px.xml
@@ -0,0 +1,25 @@
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M15.3,16.7 L16.7,15.3 13,11.6V7H11V12.4ZM12,22Q9.925,22 8.1,21.212Q6.275,20.425 4.925,19.075Q3.575,17.725 2.788,15.9Q2,14.075 2,12Q2,9.925 2.788,8.1Q3.575,6.275 4.925,4.925Q6.275,3.575 8.1,2.787Q9.925,2 12,2Q14.075,2 15.9,2.787Q17.725,3.575 19.075,4.925Q20.425,6.275 21.212,8.1Q22,9.925 22,12Q22,14.075 21.212,15.9Q20.425,17.725 19.075,19.075Q17.725,20.425 15.9,21.212Q14.075,22 12,22ZM12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12ZM12,20Q15.325,20 17.663,17.663Q20,15.325 20,12Q20,8.675 17.663,6.337Q15.325,4 12,4Q8.675,4 6.338,6.337Q4,8.675 4,12Q4,15.325 6.338,17.663Q8.675,20 12,20Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout/check_circle_grey_large_not_select_background_color.xml b/res/layout/check_circle_grey_large_not_select_background_color.xml
new file mode 100644
index 0000000..c023611
--- /dev/null
+++ b/res/layout/check_circle_grey_large_not_select_background_color.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <item android:color="?androidprv:attr/textColorSecondaryInverse" />
+</selector>
\ No newline at end of file
diff --git a/res/layout/clock_section_view.xml b/res/layout/clock_section_view.xml
new file mode 100644
index 0000000..d95e651
--- /dev/null
+++ b/res/layout/clock_section_view.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.customization.picker.clock.ClockSectionView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?selectableItemBackground"
+    android:clickable="true"
+    android:paddingVertical="@dimen/section_top_padding"
+    android:paddingHorizontal="@dimen/section_horizontal_padding"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/clock_title"
+            style="@style/SectionTitleTextStyle" />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/clock_description"
+            style="@style/SectionSubtitleTextStyle"/>
+    </LinearLayout>
+
+    <ImageView
+        android:layout_width="@dimen/option_tile_width"
+        android:layout_height="@dimen/option_tile_width"
+        android:scaleType="center"
+        android:src="@drawable/ic_clock_24px"
+        android:background="@drawable/option_border_color"
+        android:contentDescription="@string/clock_picker_entry_content_description" />
+
+</com.android.customization.picker.clock.ClockSectionView>
\ No newline at end of file
diff --git a/res/layout/dark_mode_section_view.xml b/res/layout/dark_mode_section_view.xml
index b9ab0e3..e1b4b81 100644
--- a/res/layout/dark_mode_section_view.xml
+++ b/res/layout/dark_mode_section_view.xml
@@ -40,6 +40,7 @@
         android:background="@null"
         android:clickable="false"
         android:focusable="false"
+        android:minHeight="0dp"
         style="@style/Switch.SettingsLib" />
 
 </com.android.customization.picker.mode.DarkModeSectionView>
diff --git a/res/layout/fragment_clock_custom_picker.xml b/res/layout/fragment_clock_custom_picker.xml
new file mode 100644
index 0000000..f1bd12b
--- /dev/null
+++ b/res/layout/fragment_clock_custom_picker.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+     Copyright (C) 2022 The Android Open Source Project
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+          http://www.apache.org/licenses/LICENSE-2.0
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<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="match_parent"
+    android:paddingBottom="108dp">
+
+    <FrameLayout
+        android:id="@+id/section_header_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toTopOf="@+id/preview_card_container"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <include layout="@layout/section_header" />
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/preview_card_container"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        app:layout_constrainedHeight="true"
+        app:layout_constraintBottom_toTopOf="@+id/clock_preview_card_list"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/section_header_container"
+        android:paddingBottom="@dimen/preview_page_bottom_margin"
+        android:paddingTop="@dimen/preview_page_top_margin"
+        android:clipToPadding="false" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/clock_preview_card_list"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/options_container_height"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/preview_card_container"
+        android:paddingHorizontal="@dimen/grid_options_container_horizontal_margin"
+        android:scrollbars="horizontal"
+        android:clipToPadding="false" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1a15fd0..7aef401 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -24,7 +24,14 @@
 
     <!-- Title of a section of the customization picker where the user can select a Clock face.
         [CHAR LIMIT=15] -->
-    <string name="clock_title">Clock</string>
+    <string name="clock_title">Custom Clock</string>
+
+    <!-- Description of a section of the customization picker where the user can select a Clock
+        face. [CHAR LIMIT=15] -->
+    <string name="clock_description">Pick a custom clock</string>
+
+    <!-- The content description of clock entry. [CHAR LIMIT=NONE] -->
+    <string name="clock_picker_entry_content_description">Change a custom clock</string>
 
     <!-- Title of a section of the customization picker where the user can select a Grid size for
         the home screen. [CHAR LIMIT=15] -->
diff --git a/res/layout/theme_cover_qsb.xml b/res_override/layout/theme_cover_qsb.xml
similarity index 100%
rename from res/layout/theme_cover_qsb.xml
rename to res_override/layout/theme_cover_qsb.xml
diff --git a/res/values/override.xml b/res_override/values/override.xml
similarity index 77%
rename from res/values/override.xml
rename to res_override/values/override.xml
index a070dbe..05af982 100644
--- a/res/values/override.xml
+++ b/res_override/values/override.xml
@@ -16,10 +16,18 @@
      limitations under the License.
 -->
 <resources>
-    <string name="themes_stub_package" translatable="false"/>
+    <!-- Package of the stub apk containing the themes descriptions -->
+    <string name="themes_stub_package" translatable="false">
+        com.android.customization.themes
+    </string>
+
+    <!-- Package of the stub apk containing the clock content -->
     <string name="clocks_stub_package" translatable="false"/>
-    <!-- Authority of a provider in System UI that will provide preview info for available clockfaces. -->
-    <string name="clocks_provider_authority" translatable="false">com.android.keyguard.clock</string>
+
+    <!-- Authority of a System UI provider that provides preview info for available clockfaces. -->
+    <string name="clocks_provider_authority" translatable="false">
+        com.android.keyguard.clock
+    </string>
 
     <string name="launcher_overlayable_package" translatable="false">com.android.launcher3</string>
 
diff --git a/src/com/android/customization/model/clock/ClockSectionController.java b/src/com/android/customization/model/clock/ClockSectionController.java
new file mode 100644
index 0000000..8f98b88
--- /dev/null
+++ b/src/com/android/customization/model/clock/ClockSectionController.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.model.clock;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+
+import androidx.annotation.Nullable;
+
+import com.android.customization.picker.clock.ClockCustomFragment;
+import com.android.customization.picker.clock.ClockSectionView;
+import com.android.wallpaper.R;
+import com.android.wallpaper.config.Flags;
+import com.android.wallpaper.model.CustomizationSectionController;
+
+/** A {@link CustomizationSectionController} for clock customization. */
+public class ClockSectionController implements CustomizationSectionController<ClockSectionView> {
+
+    private final CustomizationSectionNavigationController mNavigationController;
+
+    public ClockSectionController(CustomizationSectionNavigationController navigationController) {
+        mNavigationController = navigationController;
+    }
+
+    @Override
+    public boolean isAvailable(@Nullable Context context) {
+        return Flags.enableClockCustomization;
+    }
+
+    @Override
+    public ClockSectionView createView(Context context) {
+        ClockSectionView view = (ClockSectionView) LayoutInflater.from(context).inflate(
+                R.layout.clock_section_view,
+                null);
+        view.setOnClickListener(v -> mNavigationController.navigateTo(new ClockCustomFragment()));
+        return view;
+    }
+}
diff --git a/src/com/android/customization/model/clock/custom/ClockCustomManager.java b/src/com/android/customization/model/clock/custom/ClockCustomManager.java
new file mode 100644
index 0000000..0815a3e
--- /dev/null
+++ b/src/com/android/customization/model/clock/custom/ClockCustomManager.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.model.clock.custom;
+
+import com.android.customization.model.CustomizationManager;
+
+import com.google.common.collect.Lists;
+
+/**
+ * {@link CustomizationManager} for clock faces.
+ */
+public class ClockCustomManager implements CustomizationManager<ClockOption> {
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public void apply(ClockOption option, Callback callback) {
+        // TODO(/b241966062) execute applying the clock when user selects a clock
+    }
+
+    @Override
+    public void fetchOptions(OptionsFetchedListener<ClockOption> callback, boolean reload) {
+        // TODO(/b241966062) fetch the real clock metadata from the ClockRegistry
+        callback.onOptionsLoaded(
+                Lists.newArrayList(new ClockOption(), new ClockOption(), new ClockOption(),
+                        new ClockOption(), new ClockOption()));
+    }
+}
diff --git a/src/com/android/customization/model/clock/custom/ClockOption.java b/src/com/android/customization/model/clock/custom/ClockOption.java
new file mode 100644
index 0000000..5a9f051
--- /dev/null
+++ b/src/com/android/customization/model/clock/custom/ClockOption.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.model.clock.custom;
+
+import android.view.View;
+
+import com.android.customization.model.CustomizationManager;
+import com.android.customization.model.CustomizationOption;
+import com.android.wallpaper.R;
+
+/**
+ * {@link CustomizationOption} for a clock face.
+ */
+public class ClockOption implements CustomizationOption<ClockOption> {
+
+    @Override
+    public String getTitle() {
+        // TODO(/b241966062) use the title from the clock metadata
+        return "title";
+    }
+
+    @Override
+    public void bindThumbnailTile(View view) {
+        // TODO(/b241966062) bind the thumbnail
+    }
+
+    @Override
+    public boolean isActive(CustomizationManager<ClockOption> manager) {
+        return false;
+    }
+
+
+    @Override
+    public int getLayoutResId() {
+        return R.layout.clock_option;
+    }
+}
diff --git a/src/com/android/customization/module/DefaultCustomizationSections.java b/src/com/android/customization/module/DefaultCustomizationSections.java
index a4510ea..21f2c84 100644
--- a/src/com/android/customization/module/DefaultCustomizationSections.java
+++ b/src/com/android/customization/module/DefaultCustomizationSections.java
@@ -6,6 +6,7 @@
 import androidx.annotation.Nullable;
 import androidx.lifecycle.LifecycleOwner;
 
+import com.android.customization.model.color.ColorSectionController;
 import com.android.customization.model.grid.GridOptionsManager;
 import com.android.customization.model.grid.GridSectionController;
 import com.android.customization.model.mode.DarkModeSectionController;
@@ -41,6 +42,10 @@
                 workspaceViewModel, sectionNavigationController, wallpaperPreviewNavigator,
                 savedInstanceState));
 
+        // Theme color section.
+        sectionControllers.add(new ColorSectionController(
+                activity, wallpaperColorsViewModel, lifecycleOwner, savedInstanceState));
+
         // Dark/Light theme section.
         sectionControllers.add(new DarkModeSectionController(activity,
                 lifecycleOwner.getLifecycle()));
diff --git a/src/com/android/customization/module/StatsLogUserEventLogger.java b/src/com/android/customization/module/StatsLogUserEventLogger.java
index 216395d..e3e4336 100644
--- a/src/com/android/customization/module/StatsLogUserEventLogger.java
+++ b/src/com/android/customization/module/StatsLogUserEventLogger.java
@@ -28,7 +28,6 @@
 import static com.android.systemui.shared.system.SysUiStatsLog.STYLE_UICHANGED__LAUNCHED_PREFERENCE__LAUNCHED_SETTINGS_SEARCH;
 import static com.android.systemui.shared.system.SysUiStatsLog.STYLE_UICHANGED__LAUNCHED_PREFERENCE__LAUNCHED_SUW;
 import static com.android.systemui.shared.system.SysUiStatsLog.STYLE_UICHANGED__LAUNCHED_PREFERENCE__LAUNCHED_TIPS;
-import static com.android.systemui.shared.system.SysUiStatsLog.STYLE_UI_CHANGED;
 import static com.android.wallpaper.util.LaunchSourceUtils.LAUNCH_SETTINGS_SEARCH;
 import static com.android.wallpaper.util.LaunchSourceUtils.LAUNCH_SOURCE_DEEP_LINK;
 import static com.android.wallpaper.util.LaunchSourceUtils.LAUNCH_SOURCE_LAUNCHER;
@@ -49,7 +48,6 @@
 import com.android.customization.model.color.ColorOption;
 import com.android.customization.model.grid.GridOption;
 import com.android.customization.model.theme.ThemeBundle;
-import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.wallpaper.module.Injector;
 import com.android.wallpaper.module.InjectorProvider;
 import com.android.wallpaper.module.NoOpUserEventLogger;
@@ -78,60 +76,67 @@
 
     @Override
     public void logAppLaunched(Intent launchSource) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, STYLE_UICHANGED__ACTION__APP_LAUNCHED,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, getAppLaunchSource(launchSource), 0, 0,
-                0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(STYLE_UICHANGED__ACTION__APP_LAUNCHED)
+                .setLaunchedPreference(getAppLaunchSource(launchSource))
+                .log();
     }
 
     @Override
     public void logResumed(boolean provisioned, boolean wallpaper) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.ONRESUME,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.ONRESUME)
+                .log();
     }
 
     @Override
     public void logStopped() {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.ONSTOP,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.ONSTOP)
+                .log();
     }
 
     @Override
     public void logActionClicked(String collectionId, int actionLabelResId) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.WALLPAPER_EXPLORE, 0, 0, 0, 0, 0,
-                getIdHashCode(collectionId), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.WALLPAPER_EXPLORE)
+                .setWallpaperCategoryHash(getIdHashCode(collectionId))
+                .log();
     }
 
     @Override
     public void logIndividualWallpaperSelected(String collectionId) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.WALLPAPER_SELECT, 0, 0, 0, 0, 0,
-                getIdHashCode(collectionId), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.WALLPAPER_SELECT)
+                .setWallpaperCategoryHash(getIdHashCode(collectionId))
+                .log();
     }
 
     @Override
     public void logCategorySelected(String collectionId) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.WALLPAPER_OPEN_CATEGORY,
-                0, 0, 0, 0, 0,
-                getIdHashCode(collectionId),
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.WALLPAPER_OPEN_CATEGORY)
+                .setWallpaperCategoryHash(getIdHashCode(collectionId))
+                .log();
     }
 
     @Override
     public void logLiveWallpaperInfoSelected(String collectionId, @Nullable String wallpaperId) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.LIVE_WALLPAPER_INFO_SELECT,
-                0, 0, 0, 0, 0,
-                getIdHashCode(collectionId),
-                getIdHashCode(wallpaperId),
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.LIVE_WALLPAPER_INFO_SELECT)
+                .setWallpaperCategoryHash(getIdHashCode(collectionId))
+                .setWallpaperIdHash(getIdHashCode(wallpaperId))
+                .log();
     }
 
     @Override
     public void logLiveWallpaperCustomizeSelected(String collectionId,
             @Nullable String wallpaperId) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.LIVE_WALLPAPER_CUSTOMIZE_SELECT,
-                0, 0, 0, 0, 0,
-                getIdHashCode(collectionId),
-                getIdHashCode(wallpaperId),
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger().setAction(StyleEnums.LIVE_WALLPAPER_CUSTOMIZE_SELECT)
+                .setWallpaperCategoryHash(getIdHashCode(collectionId))
+                .setWallpaperIdHash(getIdHashCode(wallpaperId))
+                .log();
+
     }
 
     @Override
@@ -139,6 +144,7 @@
         final boolean isLockWallpaperSet = mWallpaperStatusChecker.isLockWallpaperSet(mContext);
         final String homeCollectionId = mPreferences.getHomeWallpaperCollectionId();
         final String homeRemoteId = mPreferences.getHomeWallpaperRemoteId();
+        final String effects = mPreferences.getWallpaperEffects();
         String homeWallpaperId = TextUtils.isEmpty(homeRemoteId)
                 ? mPreferences.getHomeWallpaperServiceName() : homeRemoteId;
         String lockCollectionId = isLockWallpaperSet ? mPreferences.getLockWallpaperCollectionId()
@@ -146,35 +152,37 @@
         String lockWallpaperId = isLockWallpaperSet ? mPreferences.getLockWallpaperRemoteId()
                 : homeWallpaperId;
 
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.SNAPSHOT,
-                0, 0, 0, 0, 0,
-                getIdHashCode(homeCollectionId),
-                getIdHashCode(homeWallpaperId),
-                0, 0, 0, 0, 0, 0,
-                getIdHashCode(lockCollectionId),
-                getIdHashCode(lockWallpaperId),
-                mPreferences.getFirstLaunchDateSinceSetup(),
-                mPreferences.getFirstWallpaperApplyDateSinceSetup(),
-                mPreferences.getAppLaunchCount(),
-                0);
+        new SysUiStatsLogger().setAction(StyleEnums.SNAPSHOT)
+                .setWallpaperCategoryHash(getIdHashCode(homeCollectionId))
+                .setWallpaperIdHash(getIdHashCode(homeWallpaperId))
+                .setLockWallpaperCategoryHash(getIdHashCode(lockCollectionId))
+                .setLockWallpaperIdHash(getIdHashCode(lockWallpaperId))
+                .setFirstLaunchDateSinceSetup(mPreferences.getFirstLaunchDateSinceSetup())
+                .setFirstWallpaperApplyDateSinceSetup(
+                        mPreferences.getFirstWallpaperApplyDateSinceSetup())
+                .setAppLaunchCount(mPreferences.getAppLaunchCount())
+                .setEffectIdHash(getIdHashCode(effects))
+                .log();
     }
 
     @Override
     public void logWallpaperSet(String collectionId, @Nullable String wallpaperId,
             @Nullable String effects) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.WALLPAPER_APPLIED,
-                0, 0, 0, 0, 0,
-                getIdHashCode(collectionId),
-                getIdHashCode(wallpaperId),
-                0, 0, 0, 0, 0, effects != null ? effects.hashCode() : 0,
-                0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.WALLPAPER_APPLIED)
+                .setWallpaperCategoryHash(getIdHashCode(collectionId))
+                .setWallpaperIdHash(getIdHashCode(wallpaperId))
+                .setEffectIdHash(getIdHashCode(effects))
+                .log();
     }
 
     @Override
     public void logEffectApply(String effect, @EffectStatus int status) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.WALLPAPER_EFFECT_APPLIED,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, status, effect != null ? effect.hashCode() : 0,
-                0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.WALLPAPER_EFFECT_APPLIED)
+                .setEffectPreference(status)
+                .setEffectIdHash(getIdHashCode(effect))
+                .log();
     }
 
     @Nullable
@@ -185,60 +193,67 @@
 
     @Override
     public void logThemeSelected(ThemeBundle theme, boolean isCustomTheme) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.PICKER_SELECT,
-                Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_COLOR)),
-                Objects.hashCode(getThemePackage(theme,OVERLAY_CATEGORY_FONT)),
-                Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_SHAPE)),
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.PICKER_SELECT)
+                .setColorPackageHash(
+                        Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_COLOR)))
+                .setFontPackageHash(Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_FONT)))
+                .setShapePackageHash(
+                        Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_SHAPE)))
+                .log();
     }
 
     @Override
     public void logThemeApplied(ThemeBundle theme, boolean isCustomTheme) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.PICKER_APPLIED,
-                Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_COLOR)),
-                Objects.hashCode(getThemePackage(theme,OVERLAY_CATEGORY_FONT)),
-                Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_SHAPE)),
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.PICKER_APPLIED)
+                .setColorPackageHash(
+                        Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_COLOR)))
+                .setFontPackageHash(Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_FONT)))
+                .setShapePackageHash(
+                        Objects.hashCode(getThemePackage(theme, OVERLAY_CATEGORY_SHAPE)))
+                .log();
     }
 
     @Override
     public void logColorApplied(int action, ColorOption colorOption) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, action,
-                0, 0, 0, 0, 0, 0, 0,
-                colorOption.getIndex(),
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, colorOption.getStyle().ordinal() + 1);
+        new SysUiStatsLogger()
+                .setAction(action)
+                .setColorPreference(colorOption.getIndex())
+                .setColorVariant(colorOption.getStyle().ordinal() + 1)
+                .log();
     }
 
     @Override
     public void logClockSelected(Clockface clock) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.PICKER_SELECT,
-                0, 0, 0,
-                Objects.hashCode(clock.getId()),
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.PICKER_SELECT)
+                .setClockPackageHash(Objects.hashCode(clock.getId()))
+                .log();
     }
 
     @Override
     public void logClockApplied(Clockface clock) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.PICKER_APPLIED,
-                0, 0, 0,
-                Objects.hashCode(clock.getId()),
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.PICKER_APPLIED)
+                .setClockPackageHash(Objects.hashCode(clock.getId()))
+                .log();
     }
 
     @Override
     public void logGridSelected(GridOption grid) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.PICKER_SELECT,
-                0, 0, 0, 0,
-                grid.cols,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.PICKER_SELECT)
+                .setLauncherGrid(grid.cols)
+                .log();
     }
 
     @Override
     public void logGridApplied(GridOption grid) {
-        SysUiStatsLog.write(STYLE_UI_CHANGED, StyleEnums.PICKER_APPLIED,
-                0, 0, 0, 0,
-                grid.cols,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        new SysUiStatsLogger()
+                .setAction(StyleEnums.PICKER_APPLIED)
+                .setLauncherGrid(grid.cols)
+                .log();
     }
 
     private int getAppLaunchSource(Intent launchSource) {
diff --git a/src/com/android/customization/module/SysUiStatsLogger.kt b/src/com/android/customization/module/SysUiStatsLogger.kt
new file mode 100644
index 0000000..eb3bcc0
--- /dev/null
+++ b/src/com/android/customization/module/SysUiStatsLogger.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.module
+
+import android.stats.style.StyleEnums
+import com.android.systemui.shared.system.SysUiStatsLog
+import com.android.systemui.shared.system.SysUiStatsLog.STYLE_UI_CHANGED
+
+/**
+ * The builder for [SysUiStatsLog].
+ */
+class SysUiStatsLogger {
+
+    private var atom = STYLE_UI_CHANGED
+    private var action = StyleEnums.DEFAULT_ACTION
+    private var colorPackageHash = 0
+    private var fontPackageHash = 0
+    private var shapePackageHash = 0
+    private var clockPackageHash = 0
+    private var launcherGrid = 0
+    private var wallpaperCategoryHash = 0
+    private var wallpaperIdHash = 0
+    private var colorPreference = 0
+    private var locationPreference = StyleEnums.EFFECT_PREFERENCE_UNSPECIFIED
+    private var datePreference = StyleEnums.DATE_PREFERENCE_UNSPECIFIED
+    private var launchedPreference = StyleEnums.LAUNCHED_PREFERENCE_UNSPECIFIED
+    private var effectPreference = StyleEnums.EFFECT_PREFERENCE_UNSPECIFIED
+    private var effectIdHash = 0
+    private var lockWallpaperCategoryHash = 0
+    private var lockWallpaperIdHash = 0
+    private var firstLaunchDateSinceSetup = 0
+    private var firstWallpaperApplyDateSinceSetup = 0
+    private var appLaunchCount = 0
+    private var colorVariant = 0
+
+    fun setAction(action: Int) =
+        apply { this.action = action }
+
+    fun setColorPackageHash(color_package_hash: Int) =
+        apply { this.colorPackageHash = color_package_hash }
+
+    fun setFontPackageHash(font_package_hash: Int) =
+        apply { this.fontPackageHash = font_package_hash }
+
+    fun setShapePackageHash(shape_package_hash: Int) =
+        apply { this.shapePackageHash = shape_package_hash }
+
+    fun setClockPackageHash(clock_package_hash: Int) =
+        apply { this.clockPackageHash = clock_package_hash }
+
+    fun setLauncherGrid(launcher_grid: Int) =
+        apply { this.launcherGrid = launcher_grid }
+
+    fun setWallpaperCategoryHash(wallpaper_category_hash: Int) =
+        apply { this.wallpaperCategoryHash = wallpaper_category_hash }
+
+    fun setWallpaperIdHash(wallpaper_id_hash: Int) =
+        apply { this.wallpaperIdHash = wallpaper_id_hash }
+
+    fun setColorPreference(color_preference: Int) =
+        apply { this.colorPreference = color_preference }
+
+    fun setLocationPreference(location_preference: Int) =
+        apply { this.locationPreference = location_preference }
+
+    fun setDatePreference(date_preference: Int) =
+        apply { this.datePreference = date_preference }
+
+    fun setLaunchedPreference(launched_preference: Int) =
+        apply { this.launchedPreference = launched_preference }
+
+    fun setEffectPreference(effect_preference: Int) =
+        apply { this.effectPreference = effect_preference }
+
+    fun setEffectIdHash(effect_id_hash: Int) =
+        apply { this.effectIdHash = effect_id_hash }
+
+    fun setLockWallpaperCategoryHash(lock_wallpaper_category_hash: Int) =
+        apply { this.lockWallpaperCategoryHash = lock_wallpaper_category_hash }
+
+    fun setLockWallpaperIdHash(lock_wallpaper_id_hash: Int) =
+        apply { this.lockWallpaperIdHash = lock_wallpaper_id_hash }
+
+    fun setFirstLaunchDateSinceSetup(first_launch_date_since_setup: Int) =
+        apply { this.firstLaunchDateSinceSetup = first_launch_date_since_setup }
+
+    fun setFirstWallpaperApplyDateSinceSetup(first_wallpaper_apply_date_since_setup: Int) =
+        apply {
+            this.firstWallpaperApplyDateSinceSetup = first_wallpaper_apply_date_since_setup
+        }
+
+    fun setAppLaunchCount(app_launch_count: Int) =
+        apply { this.appLaunchCount = app_launch_count }
+
+    fun setColorVariant(color_variant: Int) =
+        apply { this.colorVariant = color_variant }
+
+    fun log() {
+        SysUiStatsLog.write(
+            atom,
+            action,
+            colorPackageHash,
+            fontPackageHash,
+            shapePackageHash,
+            clockPackageHash,
+            launcherGrid,
+            wallpaperCategoryHash,
+            wallpaperIdHash,
+            colorPreference,
+            locationPreference,
+            datePreference,
+            launchedPreference,
+            effectPreference,
+            effectIdHash,
+            lockWallpaperCategoryHash,
+            lockWallpaperIdHash,
+            firstLaunchDateSinceSetup,
+            firstWallpaperApplyDateSinceSetup,
+            appLaunchCount,
+            colorVariant
+        )
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/customization/picker/clock/ClockCustomFragment.java b/src/com/android/customization/picker/clock/ClockCustomFragment.java
new file mode 100644
index 0000000..56860fe
--- /dev/null
+++ b/src/com/android/customization/picker/clock/ClockCustomFragment.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.clock;
+
+import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
+import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.customization.model.clock.custom.ClockCustomManager;
+import com.android.customization.model.clock.custom.ClockOption;
+import com.android.customization.widget.OptionSelectorController;
+import com.android.wallpaper.R;
+import com.android.wallpaper.picker.AppbarFragment;
+import com.android.wallpaper.widget.BottomActionBar;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Fragment that contains the main UI for selecting and applying a custom clock.
+ */
+public class ClockCustomFragment extends AppbarFragment {
+
+    OptionSelectorController<ClockOption> mClockSelectorController;
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.fragment_clock_custom_picker, container, false);
+
+        setUpToolbar(view);
+
+        RecyclerView clockPreviewCardList = view.requireViewById(R.id.clock_preview_card_list);
+
+        mClockSelectorController = new OptionSelectorController<>(clockPreviewCardList,
+                Lists.newArrayList(new ClockOption(), new ClockOption(), new ClockOption(),
+                        new ClockOption(), new ClockOption()), false,
+                OptionSelectorController.CheckmarkStyle.CENTER_CHANGE_COLOR_WHEN_NOT_SELECTED);
+        mClockSelectorController.initOptions(new ClockCustomManager());
+
+        return view;
+    }
+
+    @Override
+    public CharSequence getDefaultTitle() {
+        return getString(R.string.clock_title);
+    }
+
+    @Override
+    protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
+        super.onBottomActionBarReady(bottomActionBar);
+        bottomActionBar.showActionsOnly(INFORMATION, APPLY);
+        bottomActionBar.show();
+    }
+}
diff --git a/src/com/android/customization/picker/clock/ClockSectionView.kt b/src/com/android/customization/picker/clock/ClockSectionView.kt
new file mode 100644
index 0000000..c043209
--- /dev/null
+++ b/src/com/android/customization/picker/clock/ClockSectionView.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.clock
+
+import android.content.Context
+import android.util.AttributeSet
+import com.android.wallpaper.picker.SectionView
+
+/** The [SectionView] for app clock.  */
+class ClockSectionView(context: Context?, attrs: AttributeSet?) : SectionView(context, attrs)
\ No newline at end of file
diff --git a/src/com/android/customization/widget/OptionSelectorController.java b/src/com/android/customization/widget/OptionSelectorController.java
index a66dd44..ffd70e0 100644
--- a/src/com/android/customization/widget/OptionSelectorController.java
+++ b/src/com/android/customization/widget/OptionSelectorController.java
@@ -45,6 +45,7 @@
 import com.android.customization.model.CustomizationOption;
 import com.android.wallpaper.R;
 import com.android.wallpaper.widget.GridPaddingDecoration;
+import com.android.wallpaper.widget.GridRowSpacerDecoration;
 
 import java.util.HashSet;
 import java.util.List;
@@ -84,7 +85,8 @@
     private final RecyclerView mContainer;
     private final List<T> mOptions;
     private final boolean mUseGrid;
-    @CheckmarkStyle private final int mCheckmarkStyle;
+    @CheckmarkStyle
+    private final int mCheckmarkStyle;
 
     private final Set<OptionSelectedListener> mListeners = new HashSet<>();
     private RecyclerView.Adapter<TileViewHolder> mAdapter;
@@ -141,7 +143,6 @@
     /**
      * Mark an option as the one which is currently applied on the device. This will result in a
      * check being displayed in the lower-right corner of the corresponding ViewHolder.
-     * @param option
      */
     public void setAppliedOption(T option) {
         if (!mOptions.contains(option)) {
@@ -157,6 +158,7 @@
 
     /**
      * Notify that a given option has changed.
+     *
      * @param option the option that changed
      */
     public void optionChanged(T option) {
@@ -217,7 +219,7 @@
                                     mContainer.getContext().getTheme()),
                             Gravity.CENTER, res.getDimensionPixelSize(R.dimen.center_check_size),
                             0, true);
-                }  else if (mCheckmarkStyle == CheckmarkStyle.CENTER_CHANGE_COLOR_WHEN_NOT_SELECTED
+                } else if (mCheckmarkStyle == CheckmarkStyle.CENTER_CHANGE_COLOR_WHEN_NOT_SELECTED
                         && option.equals(mAppliedOption)) {
                     int drawableRes = option.equals(mSelectedOption)
                             ? R.drawable.check_circle_grey_large
@@ -230,7 +232,7 @@
                 } else if (option.equals(mAppliedOption)) {
                     // Initialize with "previewed" description if we don't show checkmark
                     holder.setContentDescription(mContainer.getContext(), option,
-                        R.string.option_previewed_description);
+                            R.string.option_previewed_description);
                 } else if (mCheckmarkStyle != CheckmarkStyle.NONE) {
                     if (mCheckmarkStyle == CheckmarkStyle.CENTER_CHANGE_COLOR_WHEN_NOT_SELECTED) {
                         if (option.equals(mSelectedOption)) {
@@ -282,72 +284,66 @@
         };
 
         Resources res = mContainer.getContext().getResources();
-        if (mUseGrid) {
-            mContainer.setLayoutManager(new GridLayoutManager(mContainer.getContext(),
-                    res.getInteger(R.integer.options_grid_num_columns)));
-        } else {
-            mContainer.setLayoutManager(new LinearLayoutManager(mContainer.getContext(),
-                    LinearLayoutManager.HORIZONTAL, false));
-        }
-
         mContainer.setAdapter(mAdapter);
-
-        // Measure RecyclerView to get to the total amount of space used by all options.
-        mContainer.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-        int fixWidth = res.getDimensionPixelSize(R.dimen.options_container_width);
-        int availableWidth;
-        if (fixWidth == 0) {
-            DisplayMetrics metrics = new DisplayMetrics();
-            mContainer.getContext().getSystemService(WindowManager.class)
-                    .getDefaultDisplay().getMetrics(metrics);
-            availableWidth = metrics.widthPixels;
-        } else {
-            availableWidth = fixWidth;
-        }
-        int totalWidth = mContainer.getMeasuredWidth();
-        int widthPerItem = res.getDimensionPixelOffset(R.dimen.option_tile_width);
+        final int padding = res.getDimensionPixelSize(
+                R.dimen.option_tile_grid_padding_horizontal);
+        final int fixWidth = res.getDimensionPixelSize(R.dimen.options_container_width);
+        final DisplayMetrics metrics = new DisplayMetrics();
+        mContainer.getContext().getSystemService(WindowManager.class)
+                .getDefaultDisplay().getMetrics(metrics);
+        // This is based on the assumption that the parent view is the same width as the screen.
+        final int availableDynamicWidth = metrics.widthPixels - 2 * res.getDimensionPixelSize(
+                R.dimen.section_horizontal_padding);
+        final int availableWidth = (fixWidth != 0) ? fixWidth : availableDynamicWidth;
+        final boolean hasDecoration = mContainer.getItemDecorationCount() != 0;
 
         if (mUseGrid) {
             int numColumns = res.getInteger(R.integer.options_grid_num_columns);
-            int extraSpace = availableWidth - widthPerItem * numColumns;
-            while (extraSpace < 0) {
+            GridLayoutManager gridLayoutManager = new GridLayoutManager(mContainer.getContext(),
+                    numColumns);
+            mContainer.setLayoutManager(gridLayoutManager);
+            if (!hasDecoration) {
+                mContainer.addItemDecoration(new GridPaddingDecoration(padding, 0));
+            }
+            // Measure RecyclerView to get to the total amount of space used by all options.
+            mContainer.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+            while (mContainer.getMeasuredWidth() > availableWidth && numColumns > 1) {
                 numColumns -= 1;
-                extraSpace = availableWidth - widthPerItem * numColumns;
+                gridLayoutManager.setSpanCount(numColumns);
+                mContainer.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+            }
+            if (!hasDecoration && numColumns > 1) {
+                mContainer.addItemDecoration(new GridRowSpacerDecoration(2 * padding));
+            }
+        } else {
+            final int widthPerItem = res.getDimensionPixelSize(R.dimen.option_tile_width) + (
+                    hasDecoration ? 0 : 2 * padding);
+            mContainer.setLayoutManager(new LinearLayoutManager(mContainer.getContext(),
+                    LinearLayoutManager.HORIZONTAL, false));
+            int extraSpace = availableWidth - mContainer.getMeasuredWidth();
+            if (extraSpace >= 0) {
+                mContainer.setOverScrollMode(View.OVER_SCROLL_NEVER);
             }
 
-            if (mContainer.getLayoutManager() != null) {
-                ((GridLayoutManager) mContainer.getLayoutManager()).setSpanCount(numColumns);
+            if (mAdapter.getItemCount() >= mLinearLayoutHorizontalDisplayOptionsMax) {
+                int spaceBetweenItems = availableWidth
+                        - Math.round(widthPerItem * mLinearLayoutHorizontalDisplayOptionsMax)
+                        - mContainer.getPaddingLeft();
+                int itemEndMargin =
+                        spaceBetweenItems / (int) mLinearLayoutHorizontalDisplayOptionsMax;
+                if (itemEndMargin <= 0) {
+                    itemEndMargin = res.getDimensionPixelOffset(
+                            R.dimen.option_tile_margin_horizontal);
+                }
+                mContainer.addItemDecoration(new ItemEndHorizontalSpaceItemDecoration(
+                        mContainer.getContext(), itemEndMargin));
+                return;
             }
-            if (mContainer.getItemDecorationCount() == 0) {
-                mContainer.addItemDecoration(new GridPaddingDecoration(
-                        mContainer.getContext().getResources().getDimensionPixelSize(
-                                R.dimen.option_tile_grid_padding_horizontal), 0));
-            }
-            return;
+
+            int spaceBetweenItems = extraSpace / (mAdapter.getItemCount() + 1);
+            int itemSideMargin = spaceBetweenItems / 2;
+            mContainer.addItemDecoration(new HorizontalSpacerItemDecoration(itemSideMargin));
         }
-
-        int extraSpace = availableWidth - totalWidth;
-        if (extraSpace >= 0) {
-            mContainer.setOverScrollMode(View.OVER_SCROLL_NEVER);
-        }
-
-        if (mAdapter.getItemCount() >= mLinearLayoutHorizontalDisplayOptionsMax) {
-            int spaceBetweenItems = availableWidth
-                    - Math.round(widthPerItem * mLinearLayoutHorizontalDisplayOptionsMax)
-                    - mContainer.getPaddingLeft();
-            int itemEndMargin =
-                    spaceBetweenItems / (int) mLinearLayoutHorizontalDisplayOptionsMax;
-            if (itemEndMargin <= 0) {
-                itemEndMargin = res.getDimensionPixelOffset(R.dimen.option_tile_margin_horizontal);
-            }
-            mContainer.addItemDecoration(new ItemEndHorizontalSpaceItemDecoration(
-                    mContainer.getContext(), itemEndMargin));
-            return;
-        }
-
-        int spaceBetweenItems = extraSpace / (mAdapter.getItemCount() + 1);
-        int itemSideMargin = spaceBetweenItems / 2;
-        mContainer.addItemDecoration(new HorizontalSpacerItemDecoration(itemSideMargin));
     }
 
     public void resetOptions(List<T> options) {
@@ -382,9 +378,10 @@
         /**
          * Set the content description for this holder using the given string id.
          * If the option does not have a label, the description will be set on the tile view.
+         *
          * @param context The view's context
-         * @param option The customization option
-         * @param id Resource ID of the string to use for the content description
+         * @param option  The customization option
+         * @param id      Resource ID of the string to use for the content description
          */
         public void setContentDescription(Context context, CustomizationOption<?> option, int id) {
             title = option.getTitle();
diff --git a/src_override/com/android/wallpaper/config/Flags.java b/src_override/com/android/wallpaper/config/Flags.java
index d35d88f..76549cb 100644
--- a/src_override/com/android/wallpaper/config/Flags.java
+++ b/src_override/com/android/wallpaper/config/Flags.java
@@ -16,4 +16,5 @@
 package com.android.wallpaper.config;
 
 public class Flags extends BaseFlags {
+    public static boolean enableClockCustomization = false;
 }
diff --git a/themes/Android.bp b/themes/Android.bp
new file mode 100644
index 0000000..fb3d9be
--- /dev/null
+++ b/themes/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// ==================================================
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "Android-Apache-2.0",
+    ],
+}
+
+android_app {
+
+    name: "ThemesStub",
+    optimize: {
+        enabled: false,
+    },
+
+    aaptflags: ["--auto-add-overlay"],
+
+    sdk_version: "current",
+
+    product_specific: true,
+
+}
+
+// ==================================================
diff --git a/themes/AndroidManifest.xml b/themes/AndroidManifest.xml
new file mode 100755
index 0000000..68ead89
--- /dev/null
+++ b/themes/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.customization.themes"
+    android:versionCode="1">
+
+    <uses-sdk
+      android:minSdkVersion="31"
+      android:targetSdkVersion="31"/>
+
+    <application
+        android:hasCode="false"
+        android:label="@string/app_name"/>
+
+</manifest>
diff --git a/themes/res/values/color-bundles.xml b/themes/res/values/color-bundles.xml
new file mode 100644
index 0000000..4d7cc63
--- /dev/null
+++ b/themes/res/values/color-bundles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <array name="color_bundles">
+        <item>rainbow1</item>
+        <item>rainbow2</item>
+        <item>rainbow3</item>
+        <item>rainbow4</item>
+        <item>rainbow5</item>
+        <item>rainbow6</item>
+        <item>rainbow7</item>
+    </array>
+</resources>
diff --git a/themes/res/values/colors.xml b/themes/res/values/colors.xml
new file mode 100644
index 0000000..3ffb9fc
--- /dev/null
+++ b/themes/res/values/colors.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <color name="color_secondary_rainbow1">#FFB2B5</color>
+    <color name="color_secondary_rainbow2">#FFB868</color>
+    <color name="color_secondary_rainbow3">#E9C44A</color>
+    <color name="color_secondary_rainbow4">#BAF293</color>
+    <color name="color_secondary_rainbow5">#96CBFF</color>
+    <color name="color_secondary_rainbow6">#CBBFFF</color>
+    <color name="color_secondary_rainbow7">#F5ACFB</color>
+</resources>
diff --git a/themes/res/values/strings.xml b/themes/res/values/strings.xml
new file mode 100644
index 0000000..8bc04bd
--- /dev/null
+++ b/themes/res/values/strings.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <string name="app_name" translatable="false">Themes</string>
+    <string name="rainbow_color_name_red">Red</string>
+    <string name="rainbow_color_name_orange">Orange</string>
+    <string name="rainbow_color_name_yellow">Yellow</string>
+    <string name="rainbow_color_name_green">Green</string>
+    <string name="rainbow_color_name_blue">Blue</string>
+    <string name="rainbow_color_name_purple">Purple</string>
+    <string name="rainbow_color_name_magenta">Magenta</string>
+
+    <string name="bundle_name_rainbow1" translatable="false">@string/rainbow_color_name_red</string>
+    <string name="bundle_name_rainbow2" translatable="false">@string/rainbow_color_name_orange</string>
+    <string name="bundle_name_rainbow3" translatable="false">@string/rainbow_color_name_yellow</string>
+    <string name="bundle_name_rainbow4" translatable="false">@string/rainbow_color_name_green</string>
+    <string name="bundle_name_rainbow5" translatable="false">@string/rainbow_color_name_blue</string>
+    <string name="bundle_name_rainbow6" translatable="false">@string/rainbow_color_name_purple</string>
+    <string name="bundle_name_rainbow7" translatable="false">@string/rainbow_color_name_magenta</string>
+
+    <string name="color_style_rainbow1" translatable="false">RAINBOW</string>
+    <string name="color_style_rainbow2" translatable="false">RAINBOW</string>
+    <string name="color_style_rainbow3" translatable="false">RAINBOW</string>
+    <string name="color_style_rainbow4" translatable="false">RAINBOW</string>
+    <string name="color_style_rainbow5" translatable="false">RAINBOW</string>
+    <string name="color_style_rainbow6" translatable="false">RAINBOW</string>
+    <string name="color_style_rainbow7" translatable="false">RAINBOW</string>
+</resources>