Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-qpr-dev
diff --git a/res/drawable/ic_contrast.xml b/res/drawable/ic_contrast.xml
new file mode 100644
index 0000000..6e9f3bd
--- /dev/null
+++ b/res/drawable/ic_contrast.xml
@@ -0,0 +1,11 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:autoMirrored="true"
+    android:tint="@color/text_color_primary_inverse"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,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,22ZM13,19.925Q15.975,19.55 17.988,17.312Q20,15.075 20,12Q20,8.925 17.988,6.687Q15.975,4.45 13,4.075Z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/saturation_progress_drawable.xml b/res/drawable/saturation_progress_drawable.xml
new file mode 100644
index 0000000..6ba7e81
--- /dev/null
+++ b/res/drawable/saturation_progress_drawable.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack" >
+    <item android:id="@android:id/background"
+        android:gravity="center_vertical|fill_horizontal">
+        <inset
+            android:insetLeft="22dp"
+            android:insetRight="22dp" >
+            <shape>
+                <size android:height="4dp" />
+                <corners android:radius="2dp" />
+                <solid android:color="@color/color_surface_variant" />
+            </shape>
+        </inset>
+    </item>
+    <item android:id="@android:id/progress"
+          android:gravity="center_vertical|fill_horizontal">
+            <com.android.customization.picker.clock.ui.view.SaturationProgressDrawable
+                android:drawable="@drawable/saturation_progress_full_drawable"
+            />
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/saturation_progress_full_drawable.xml b/res/drawable/saturation_progress_full_drawable.xml
new file mode 100644
index 0000000..9d14bcd
--- /dev/null
+++ b/res/drawable/saturation_progress_full_drawable.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true">
+    <item android:id="@+id/slider_foreground"
+        android:height="48dp">
+        <shape>
+            <size android:height="48dp" />
+            <solid android:color="@color/color_accent_primary" />
+            <corners android:radius="24dp"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/slider_icon"
+        android:gravity="center_vertical|right"
+        android:height="20dp"
+        android:width="20dp"
+        android:right="14dp"
+        android:drawable="@drawable/ic_contrast" />
+</layer-list>
\ No newline at end of file
diff --git a/res/layout/fragment_clock_settings.xml b/res/layout/fragment_clock_settings.xml
index 696d6eb..3258083 100644
--- a/res/layout/fragment_clock_settings.xml
+++ b/res/layout/fragment_clock_settings.xml
@@ -98,31 +98,50 @@
             android:layout_height="wrap_content"
             android:paddingTop="16dp">
 
-            <FrameLayout
-                android:id="@+id/color_options_container"
+            <LinearLayout
+                android:id="@+id/color_picker_container"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content">
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
 
-                <androidx.recyclerview.widget.RecyclerView
-                    android:id="@+id/color_options"
+                <FrameLayout
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:clipToPadding="false"
-                    android:paddingHorizontal="16dp" />
+                    android:layout_marginBottom="16dp">
 
-                <!--
-                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.
-                -->
-                <include
-                    layout="@layout/color_option_with_background"
-                    android:layout_width="wrap_content"
+                    <androidx.recyclerview.widget.RecyclerView
+                        android:id="@+id/color_options"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:clipToPadding="false"
+                        android:paddingHorizontal="16dp" />
+
+                    <!--
+                    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.
+                    -->
+                    <include
+                        layout="@layout/color_option_with_background"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:visibility="invisible" />
+                </FrameLayout>
+
+                <SeekBar
+                    android:id="@+id/slider"
+                    android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:visibility="invisible" />
-            </FrameLayout>
+                    android:layout_gravity="center_vertical"
+                    android:minHeight="48dp"
+                    android:thumb="@null"
+                    android:background="@null"
+                    android:paddingHorizontal="16dp"
+                    android:progressDrawable="@drawable/saturation_progress_drawable"
+                    android:splitTrack="false" />
+            </LinearLayout>
 
             <com.android.customization.picker.clock.ui.view.ClockSizeRadioButtonGroup
                 android:id="@+id/clock_size_radio_button_group"
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 288dd19..377d4eb 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -18,4 +18,9 @@
 <resources>
     <item name="linear_layout_horizontal_display_options_max" format="float" type="dimen">4.35
     </item>
+
+    <declare-styleable name="SaturationAlphaTintDrawableWrapper">
+        <attr name="android:tint" />
+        <attr name="android:alpha" />
+    </declare-styleable>
 </resources>
\ No newline at end of file
diff --git a/src/com/android/customization/module/DefaultCustomizationSections.java b/src/com/android/customization/module/DefaultCustomizationSections.java
index 487bca8..5fb23cf 100644
--- a/src/com/android/customization/module/DefaultCustomizationSections.java
+++ b/src/com/android/customization/module/DefaultCustomizationSections.java
@@ -118,14 +118,16 @@
                         displayUtils,
                         mClockRegistryProvider,
                         mClockCarouselViewModelProvider,
-                        mClockViewFactoryProvider)
+                        mClockViewFactoryProvider,
+                        sectionNavigationController)
                         : new ScreenPreviewSectionController(
                                 activity,
                                 lifecycleOwner,
                                 screen,
                                 wallpaperInfoFactory,
                                 wallpaperColorsViewModel,
-                                displayUtils));
+                                displayUtils,
+                                sectionNavigationController));
 
         sectionControllers.add(
                 new ConnectedSectionController(
diff --git a/src/com/android/customization/module/ThemePickerInjector.kt b/src/com/android/customization/module/ThemePickerInjector.kt
index 56ef2e6..2924135 100644
--- a/src/com/android/customization/module/ThemePickerInjector.kt
+++ b/src/com/android/customization/module/ThemePickerInjector.kt
@@ -285,7 +285,13 @@
 
     override fun getClockRegistryProvider(context: Context): ClockRegistryProvider {
         return clockRegistryProvider
-            ?: ClockRegistryProvider(context).also { clockRegistryProvider = it }
+            ?: ClockRegistryProvider(
+                    context = context,
+                    coroutineScope = GlobalScope,
+                    mainDispatcher = Dispatchers.Main,
+                    backgroundDispatcher = Dispatchers.IO,
+                )
+                .also { clockRegistryProvider = it }
     }
 
     override fun getClockPickerInteractor(
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 2529958..f5001f0 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
@@ -18,8 +18,6 @@
 import android.app.NotificationManager
 import android.content.ComponentName
 import android.content.Context
-import android.os.Handler
-import android.os.UserHandle
 import android.view.LayoutInflater
 import com.android.systemui.plugins.ClockProviderPlugin
 import com.android.systemui.plugins.Plugin
@@ -34,6 +32,8 @@
 import com.android.systemui.shared.plugins.PluginPrefs
 import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager_Factory
 import java.util.concurrent.Executors
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.suspendCancellableCoroutine
 
 /**
@@ -42,17 +42,23 @@
  */
 class ClockRegistryProvider(
     private val context: Context,
+    private val coroutineScope: CoroutineScope,
+    private val mainDispatcher: CoroutineDispatcher,
+    private val backgroundDispatcher: CoroutineDispatcher,
 ) {
     private val pluginManager: PluginManager by lazy { createPluginManager(context) }
     private val clockRegistry: ClockRegistry by lazy {
         ClockRegistry(
-            context,
-            pluginManager,
-            Handler.getMain(),
-            isEnabled = true,
-            userHandle = UserHandle.USER_SYSTEM,
-            DefaultClockProvider(context, LayoutInflater.from(context), context.resources)
-        )
+                context,
+                pluginManager,
+                coroutineScope,
+                mainDispatcher,
+                backgroundDispatcher,
+                isEnabled = true,
+                handleAllUsers = false,
+                DefaultClockProvider(context, LayoutInflater.from(context), context.resources)
+            )
+            .apply { registerListeners() }
     }
 
     suspend fun get(): ClockRegistry {
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 b460bc1..4e838aa 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
@@ -41,7 +41,7 @@
         lifecycleOwner: LifecycleOwner,
     ) {
         val tabView: RecyclerView = view.requireViewById(R.id.tabs)
-        val colorOptionContainer = view.requireViewById<View>(R.id.color_options_container)
+        val colorOptionContainer = view.requireViewById<View>(R.id.color_picker_container)
         val sizeOptions =
             view.requireViewById<ClockSizeRadioButtonGroup>(R.id.clock_size_radio_button_group)
 
diff --git a/src/com/android/customization/picker/clock/ui/view/SaturationProgressDrawable.kt b/src/com/android/customization/picker/clock/ui/view/SaturationProgressDrawable.kt
new file mode 100644
index 0000000..9e1d789
--- /dev/null
+++ b/src/com/android/customization/picker/clock/ui/view/SaturationProgressDrawable.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.content.pm.ActivityInfo
+import android.content.res.Resources
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.DrawableWrapper
+import android.graphics.drawable.InsetDrawable
+
+/**
+ * [DrawableWrapper] to use in the progress of brightness slider.
+ *
+ * This drawable is used to change the bounds of the enclosed drawable depending on the level to
+ * simulate a sliding progress, instead of using clipping or scaling. That way, the shape of the
+ * edges is maintained.
+ *
+ * Meant to be used with a rounded ends background, it will also prevent deformation when the slider
+ * is meant to be smaller than the rounded corner. The background should have rounded corners that
+ * are half of the height.
+ *
+ * This class also assumes that a "thumb" icon exists within the end's edge of the progress
+ * drawable, and the slider's width, when interacted on, if offset by half the size of the thumb
+ * icon which puts the icon directly underneath the user's finger.
+ */
+class SaturationProgressDrawable @JvmOverloads constructor(drawable: Drawable? = null) :
+    InsetDrawable(drawable, 0) {
+
+    companion object {
+        private const val MAX_LEVEL = 10000
+    }
+
+    override fun onLayoutDirectionChanged(layoutDirection: Int): Boolean {
+        onLevelChange(level)
+        return super.onLayoutDirectionChanged(layoutDirection)
+    }
+
+    override fun onBoundsChange(bounds: Rect) {
+        super.onBoundsChange(bounds)
+        onLevelChange(level)
+    }
+
+    override fun onLevelChange(level: Int): Boolean {
+        val drawableBounds = drawable?.bounds!!
+
+        // The thumb offset shifts the sun icon directly under the user's thumb
+        val thumbOffset = bounds.height() / 2
+        val width = bounds.width() * level / MAX_LEVEL + thumbOffset
+
+        // On 0, the width is bounds.height (a circle), and on MAX_LEVEL, the width is bounds.width
+        // TODO (b/268541542) Test if RTL devices also works for the slider
+        drawable?.setBounds(
+            bounds.left,
+            drawableBounds.top,
+            width.coerceAtMost(bounds.width()).coerceAtLeast(bounds.height()),
+            drawableBounds.bottom
+        )
+        return super.onLevelChange(level)
+    }
+
+    override fun getConstantState(): ConstantState {
+        // This should not be null as it was created with a state in the constructor.
+        return RoundedCornerState(super.getConstantState()!!)
+    }
+
+    override fun getChangingConfigurations(): Int {
+        return super.getChangingConfigurations() or ActivityInfo.CONFIG_DENSITY
+    }
+
+    override fun canApplyTheme(): Boolean {
+        return (drawable?.canApplyTheme() ?: false) || super.canApplyTheme()
+    }
+
+    private class RoundedCornerState(private val wrappedState: ConstantState) : ConstantState() {
+        override fun newDrawable(): Drawable {
+            return newDrawable(null, null)
+        }
+
+        override fun newDrawable(res: Resources?, theme: Resources.Theme?): Drawable {
+            val wrapper = wrappedState.newDrawable(res, theme) as DrawableWrapper
+            return SaturationProgressDrawable(wrapper.drawable)
+        }
+
+        override fun getChangingConfigurations(): Int {
+            return wrappedState.changingConfigurations
+        }
+
+        override fun canApplyTheme(): Boolean {
+            return true
+        }
+    }
+}
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 6522d84..186611e 100644
--- a/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
+++ b/src/com/android/customization/picker/preview/ui/section/PreviewWithClockCarouselSectionController.kt
@@ -30,6 +30,7 @@
 import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
 import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.wallpaper.R
+import com.android.wallpaper.model.CustomizationSectionController
 import com.android.wallpaper.model.WallpaperColorsViewModel
 import com.android.wallpaper.module.CurrentWallpaperInfoFactory
 import com.android.wallpaper.module.CustomizationSections
@@ -44,15 +45,16 @@
 /** Controls the screen preview section. */
 @OptIn(ExperimentalCoroutinesApi::class)
 class PreviewWithClockCarouselSectionController(
-    private val activity: Activity,
+    activity: Activity,
     private val lifecycleOwner: LifecycleOwner,
     private val initialScreen: CustomizationSections.Screen,
-    private val wallpaperInfoFactory: CurrentWallpaperInfoFactory,
-    private val colorViewModel: WallpaperColorsViewModel,
-    private val displayUtils: DisplayUtils,
+    wallpaperInfoFactory: CurrentWallpaperInfoFactory,
+    colorViewModel: WallpaperColorsViewModel,
+    displayUtils: DisplayUtils,
     private val clockRegistryProvider: ClockRegistryProvider,
     private val clockCarouselViewModelProvider: ClockCarouselViewModelProvider,
     private val clockViewFactoryProvider: ClockViewFactoryProvider,
+    navigator: CustomizationSectionController.CustomizationSectionNavigationController,
 ) :
     ScreenPreviewSectionController(
         activity,
@@ -61,6 +63,7 @@
         wallpaperInfoFactory,
         colorViewModel,
         displayUtils,
+        navigator,
     ) {
     private var clockCarouselBinding: ClockCarouselViewBinder.Binding? = null
     override fun createView(context: Context): ScreenPreviewView {
diff --git a/tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt b/tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
index 3a31a47..f7e9ecf 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
@@ -1,13 +1,10 @@
 package com.android.customization.picker.clock.ui.fragment
 
-import android.os.Handler
-import android.os.UserHandle
 import android.view.View
 import androidx.appcompat.app.AppCompatActivity
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.android.systemui.plugins.ClockMetadata
-import com.android.systemui.plugins.ClockProvider
 import com.android.systemui.plugins.ClockSettings
 import com.android.systemui.plugins.PluginManager
 import com.android.systemui.shared.clocks.ClockRegistry
@@ -16,7 +13,8 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 import org.robolectric.Robolectric
 import org.robolectric.RobolectricTestRunner
@@ -28,10 +26,8 @@
 class ClockCustomDemoFragmentTest {
     private lateinit var mActivity: AppCompatActivity
     private var mClockCustomDemoFragment: ClockCustomDemoFragment? = null
-    private lateinit var registry: ClockRegistry
+    @Mock private lateinit var registry: ClockRegistry
     @Mock private lateinit var mockPluginManager: PluginManager
-    @Mock private lateinit var mockHandler: Handler
-    @Mock private lateinit var defaultClockProvider: ClockProvider
 
     private var settingValue: ClockSettings? = null
 
@@ -40,33 +36,14 @@
         MockitoAnnotations.initMocks(this)
         mActivity = Robolectric.buildActivity(AppCompatActivity::class.java).get()
         mClockCustomDemoFragment = ClockCustomDemoFragment()
-        Mockito.`when`(defaultClockProvider.getClocks())
-            .thenReturn(listOf(ClockMetadata("DEFAULT", "Default Clock")))
-        registry =
-            object :
-                ClockRegistry(
-                    mActivity,
-                    mockPluginManager,
-                    mockHandler,
-                    isEnabled = true,
-                    userHandle = UserHandle.USER_ALL,
-                    defaultClockProvider = defaultClockProvider
-                ) {
-                override var settings: ClockSettings?
-                    get() = settingValue
-                    set(value) {
-                        settingValue = value
-                    }
-
-                override fun getClocks(): List<ClockMetadata> {
-                    return defaultClockProvider.getClocks() +
-                        listOf(
-                            ClockMetadata("CLOCK_1", "Clock 1"),
-                            ClockMetadata("CLOCK_2", "Clock 2"),
-                            ClockMetadata("CLOCK_NOT_IN_USE", "Clock not in use")
-                        )
-                }
-            }
+        whenever(registry.getClocks())
+            .thenReturn(
+                listOf(
+                    ClockMetadata("CLOCK_1", "Clock 1"),
+                    ClockMetadata("CLOCK_2", "Clock 2"),
+                    ClockMetadata("CLOCK_NOT_IN_USE", "Clock not in use")
+                )
+            )
 
         mClockCustomDemoFragment!!.clockRegistry = registry
         mClockCustomDemoFragment!!.recyclerView = RecyclerView(mActivity)
@@ -91,6 +68,6 @@
             .findViewHolderForAdapterPosition(testPosition)
             ?.itemView
             ?.performClick()
-        Assert.assertEquals("CLOCK_1", settingValue?.clockId)
+        verify(registry).currentClockId = "CLOCK_1"
     }
 }
diff --git a/tests/src/com/android/customization/testing/TestCustomizationInjector.kt b/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
index e4ceb4f..71b2028 100644
--- a/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
+++ b/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
@@ -30,7 +30,8 @@
 import com.android.wallpaper.module.UserEventLogger
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
 import com.android.wallpaper.testing.TestInjector
-import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
 
 /** Test implementation of the dependency injector. */
 class TestCustomizationInjector : TestInjector(), CustomizationInjector {
@@ -98,9 +99,10 @@
     private fun createCustomizationProviderClient(
         context: Context
     ): KeyguardQuickAffordancePickerInteractor {
-        val client: CustomizationProviderClient = CustomizationProviderClientImpl(context, IO)
+        val client: CustomizationProviderClient =
+            CustomizationProviderClientImpl(context, Dispatchers.IO)
         return KeyguardQuickAffordancePickerInteractor(
-            KeyguardQuickAffordancePickerRepository(client, IO),
+            KeyguardQuickAffordancePickerRepository(client, Dispatchers.IO),
             client
         ) { getKeyguardQuickAffordanceSnapshotRestorer(context) }
     }
@@ -121,7 +123,7 @@
         context: Context
     ): CustomizationProviderClient {
         return customizationProviderClient
-            ?: CustomizationProviderClientImpl(context, IO).also {
+            ?: CustomizationProviderClientImpl(context, Dispatchers.IO).also {
                 customizationProviderClient = it
             }
     }
@@ -139,7 +141,9 @@
 
     override fun getClockRegistryProvider(context: Context): ClockRegistryProvider {
         return clockRegistryProvider
-            ?: ClockRegistryProvider(context).also { clockRegistryProvider = it }
+            ?: ClockRegistryProvider(context, GlobalScope, Dispatchers.Main, Dispatchers.IO).also {
+                clockRegistryProvider = it
+            }
     }
 
     override fun getClockPickerInteractor(