Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-qpr-dev
diff --git a/res/drawable/keyguard_quick_affordance_icon_container_background_selected.xml b/res/drawable/keyguard_quick_affordance_icon_container_background_selected.xml
index 93a80eb..6b1ab28 100644
--- a/res/drawable/keyguard_quick_affordance_icon_container_background_selected.xml
+++ b/res/drawable/keyguard_quick_affordance_icon_container_background_selected.xml
@@ -13,22 +13,36 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<shape
+<layer-list
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle" >
+    >
 
-    <stroke
-        android:width="2dp"
-        android:color="@color/text_color_primary" />
+    <item
+        android:left="6dp"
+        android:top="6dp"
+        android:right="6dp"
+        android:bottom="6dp"
+        >
+        <shape
+            android:layout_width="wrap_content"
+            android:shape="rectangle">
 
-    <solid android:color="@color/color_surface_variant" />
+            <solid android:color="@color/color_surface_variant" />
 
-    <corners android:radius="20dp" />
+            <corners android:radius="14dp" />
 
-    <padding
-        android:left="5dp"
-        android:top="5dp"
-        android:right="5dp"
-        android:bottom="5dp" />
+        </shape>
+    </item>
 
-</shape>
+    <item>
+        <shape android:shape="rectangle" >
+
+            <stroke
+                android:width="2dp"
+                android:color="@color/text_color_primary" />
+
+            <corners android:radius="20dp" />
+
+        </shape>
+    </item>
+</layer-list>
diff --git a/res/drawable/picker_fragment_tab_background.xml b/res/drawable/picker_fragment_tab_background.xml
index 3fbced3..3dad344 100644
--- a/res/drawable/picker_fragment_tab_background.xml
+++ b/res/drawable/picker_fragment_tab_background.xml
@@ -15,6 +15,6 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <corners android:radius="50dp" />
+    <corners android:radius="12dp" />
     <solid android:color="@color/keyguard_quick_affordance_slot_tab_background_color" />
 </shape>
diff --git a/res/layout/clock_section_view.xml b/res/layout/clock_section_view.xml
index 4a651ca..dfd015e 100644
--- a/res/layout/clock_section_view.xml
+++ b/res/layout/clock_section_view.xml
@@ -14,7 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.customization.picker.clock.ClockSectionView
+<com.android.customization.picker.clock.ui.view.ClockSectionView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -51,4 +51,4 @@
         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
+</com.android.customization.picker.clock.ui.view.ClockSectionView>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index af8dfe1..5da2c33 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -272,18 +272,18 @@
     <string name="adaptive_color_title">Dynamic</string>
 
     <!--
-    Name of the slot on the "start" side of the bottom of the lock screen, where quick affordance
-    buttons can be added to the lock screen. In left-to-right languages, this is the left-hand side
-    button. In right-to-left languages, this is the right-hand side button. [CHAR LIMIT=16].
+    Name of the slot on the "start" side of the bottom of the lock screen, where lock screen
+    shortcuts can be added to the lock screen. In left-to-right languages, this is the left-hand
+    side button. In right-to-left languages, this is the right-hand side button. [CHAR LIMIT=16].
     -->
-    <string name="keyguard_slot_name_bottom_start">Left</string>
+    <string name="keyguard_slot_name_bottom_start">Left shortcut</string>
 
     <!--
-    Name of the slot on the "end" side of the bottom of the lock screen, where quick affordance
-    buttons can be added to the lock screen. In left-to-right languages, this is the right-hand side
-    button. In right-to-left languages, this is the left-hand side button. [CHAR LIMIT=16].
+    Name of the slot on the "end" side of the bottom of the lock screen, where lock screen shortcuts
+    can be added to the lock screen. In left-to-right languages, this is the right-hand side button.
+    In right-to-left languages, this is the left-hand side button. [CHAR LIMIT=16].
     -->
-    <string name="keyguard_slot_name_bottom_end">Right</string>
+    <string name="keyguard_slot_name_bottom_end">Right shortcut</string>
 
     <!--
     Name for an option to have no quick affordance selected for one of the sides of the lock
diff --git a/src/com/android/customization/module/CustomizationInjector.kt b/src/com/android/customization/module/CustomizationInjector.kt
index 2772e56..6194e11 100644
--- a/src/com/android/customization/module/CustomizationInjector.kt
+++ b/src/com/android/customization/module/CustomizationInjector.kt
@@ -20,8 +20,10 @@
 import com.android.customization.model.theme.OverlayManagerCompat
 import com.android.customization.model.theme.ThemeBundleProvider
 import com.android.customization.model.theme.ThemeManager
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
+import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
+import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
-import com.android.systemui.plugins.PluginManager
 import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.wallpaper.module.Injector
 
@@ -39,7 +41,15 @@
         context: Context
     ): KeyguardQuickAffordancePickerInteractor
 
-    fun getClockRegistry(context: Context): ClockRegistry
+    fun getClockRegistryProvider(context: Context): ClockRegistryProvider
 
-    fun getPluginManager(context: Context): PluginManager
+    fun getClockPickerInteractor(
+        context: Context,
+        clockRegistry: ClockRegistry
+    ): ClockPickerInteractor
+
+    fun getClockSectionViewModel(
+        context: Context,
+        clockRegistry: ClockRegistry
+    ): ClockSectionViewModel
 }
diff --git a/src/com/android/customization/module/ThemePickerInjector.kt b/src/com/android/customization/module/ThemePickerInjector.kt
index b448283..9723326 100644
--- a/src/com/android/customization/module/ThemePickerInjector.kt
+++ b/src/com/android/customization/module/ThemePickerInjector.kt
@@ -15,21 +15,20 @@
  */
 package com.android.customization.module
 
-import android.app.NotificationManager
-import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
-import android.os.Handler
-import android.os.UserHandle
-import android.view.LayoutInflater
 import androidx.activity.ComponentActivity
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentActivity
 import com.android.customization.model.theme.OverlayManagerCompat
 import com.android.customization.model.theme.ThemeBundleProvider
 import com.android.customization.model.theme.ThemeManager
+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.ui.viewmodel.ClockSectionViewModel
 import com.android.customization.picker.notifications.data.repository.NotificationsRepository
 import com.android.customization.picker.notifications.domain.interactor.NotificationsInteractor
 import com.android.customization.picker.notifications.ui.viewmodel.NotificationSectionViewModel
@@ -37,18 +36,9 @@
 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.systemui.plugins.Plugin
-import com.android.systemui.plugins.PluginManager
 import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.systemui.shared.clocks.DefaultClockProvider
 import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
 import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
-import com.android.systemui.shared.plugins.PluginActionManager
-import com.android.systemui.shared.plugins.PluginEnabler
-import com.android.systemui.shared.plugins.PluginInstance
-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.model.LiveWallpaperInfo
 import com.android.wallpaper.model.WallpaperInfo
 import com.android.wallpaper.module.CustomizationSections
@@ -61,7 +51,6 @@
 import com.android.wallpaper.picker.LivePreviewFragment
 import com.android.wallpaper.picker.PreviewFragment
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
-import java.util.concurrent.Executors
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.GlobalScope
 
@@ -78,8 +67,9 @@
     private var fragmentFactory: FragmentFactory? = null
     private var keyguardQuickAffordanceSnapshotRestorer: KeyguardQuickAffordanceSnapshotRestorer? =
         null
-    private var clockRegistry: ClockRegistry? = null
-    private var pluginManager: PluginManager? = null
+    private var clockRegistryProvider: ClockRegistryProvider? = null
+    private var clockPickerInteractor: ClockPickerInteractor? = null
+    private var clockSectionViewModel: ClockSectionViewModel? = null
     private var notificationsInteractor: NotificationsInteractor? = null
     private var notificationSectionViewModelFactory: NotificationSectionViewModel.Factory? = null
 
@@ -182,7 +172,6 @@
             ?: KeyguardQuickAffordancePickerViewModel.Factory(
                     context,
                     getKeyguardQuickAffordancePickerInteractor(context),
-                    getUndoInteractor(context),
                     getCurrentWallpaperInfoFactory(context),
                 ) { intent ->
                     context.startActivity(intent)
@@ -230,78 +219,29 @@
                 .also { keyguardQuickAffordanceSnapshotRestorer = it }
     }
 
-    override fun getClockRegistry(context: Context): ClockRegistry {
-        return clockRegistry
-            ?: ClockRegistry(
-                    context,
-                    getPluginManager(context),
-                    Handler.getMain(),
-                    isEnabled = true,
-                    userHandle = UserHandle.USER_SYSTEM,
-                    DefaultClockProvider(context, LayoutInflater.from(context), context.resources)
-                )
-                .also { clockRegistry = it }
+    override fun getClockRegistryProvider(context: Context): ClockRegistryProvider {
+        return clockRegistryProvider
+            ?: ClockRegistryProvider(context).also { clockRegistryProvider = it }
     }
 
-    override fun getPluginManager(context: Context): PluginManager {
-        return pluginManager ?: createPluginManager(context).also { pluginManager = it }
-    }
-
-    private fun createPluginManager(context: Context): PluginManager {
-        val privilegedPlugins = listOf<String>()
-        val isDebugDevice = true
-
-        val instanceFactory =
-            PluginInstance.Factory(
-                this::class.java.classLoader,
-                PluginInstance.InstanceFactory<Plugin>(),
-                PluginInstance.VersionChecker(),
-                privilegedPlugins,
-                isDebugDevice,
-            )
-
-        /*
-         * let SystemUI handle plugin, in this class assume plugins are enabled
-         */
-        val pluginEnabler =
-            object : PluginEnabler {
-                override fun setEnabled(component: ComponentName) = Unit
-
-                override fun setDisabled(
-                    component: ComponentName,
-                    @PluginEnabler.DisableReason reason: Int
-                ) = Unit
-
-                override fun isEnabled(component: ComponentName): Boolean {
-                    return true
-                }
-
-                @PluginEnabler.DisableReason
-                override fun getDisableReason(componentName: ComponentName): Int {
-                    return PluginEnabler.ENABLED
-                }
+    override fun getClockPickerInteractor(
+        context: Context,
+        clockRegistry: ClockRegistry,
+    ): ClockPickerInteractor {
+        return clockPickerInteractor
+            ?: ClockPickerInteractor(ClockPickerRepositoryImpl(clockRegistry)).also {
+                clockPickerInteractor = it
             }
+    }
 
-        val pluginActionManager =
-            PluginActionManager.Factory(
-                context,
-                context.packageManager,
-                context.mainExecutor,
-                Executors.newSingleThreadExecutor(),
-                context.getSystemService(NotificationManager::class.java),
-                pluginEnabler,
-                privilegedPlugins,
-                instanceFactory,
-            )
-        return PluginManagerImpl(
-            context,
-            pluginActionManager,
-            isDebugDevice,
-            UncaughtExceptionPreHandlerManager_Factory.create().get(),
-            pluginEnabler,
-            PluginPrefs(context),
-            listOf(),
-        )
+    override fun getClockSectionViewModel(
+        context: Context,
+        clockRegistry: ClockRegistry,
+    ): ClockSectionViewModel {
+        return clockSectionViewModel
+            ?: ClockSectionViewModel(getClockPickerInteractor(context, clockRegistry)).also {
+                clockSectionViewModel = it
+            }
     }
 
     protected fun getNotificationsInteractor(
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 52c2430..f160a3d 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
@@ -14,48 +14,15 @@
  * limitations under the License.
  *
  */
-
 package com.android.customization.picker.clock.data.repository
 
-import android.util.Log
 import com.android.customization.picker.clock.shared.model.ClockMetadataModel
-import com.android.systemui.plugins.ClockMetadata
-import com.android.systemui.shared.clocks.ClockRegistry
-import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.callbackFlow
 
 /**
  * Repository for accessing application clock settings, as well as selecting and configuring custom
  * clocks.
  */
-class ClockPickerRepository(registry: ClockRegistry) {
-
-    /** The currently-selected clock. */
-    val selectedClock: Flow<ClockMetadataModel?> = callbackFlow {
-        fun send() {
-            val model =
-                registry
-                    .getClocks()
-                    .find { clockMetadata -> clockMetadata.clockId == registry.currentClockId }
-                    ?.toModel()
-            if (model == null) {
-                Log.e(TAG, "Currently selected clock ID is not one of the available clocks.")
-            }
-            trySend(model)
-        }
-
-        val listener = ClockRegistry.ClockChangeListener { send() }
-        registry.registerClockChangeListener(listener)
-        send()
-        awaitClose { registry.unregisterClockChangeListener(listener) }
-    }
-
-    private fun ClockMetadata.toModel(): ClockMetadataModel {
-        return ClockMetadataModel(clockId = clockId, name = name)
-    }
-
-    companion object {
-        private const val TAG = "ClockPickerRepository"
-    }
+interface ClockPickerRepository {
+    val selectedClock: Flow<ClockMetadataModel?>
 }
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
new file mode 100644
index 0000000..c307ca6
--- /dev/null
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.data.repository
+
+import android.util.Log
+import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.systemui.plugins.ClockMetadata
+import com.android.systemui.shared.clocks.ClockRegistry
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+
+/** Implementation of [ClockPickerRepository], using [ClockRegistry]. */
+class ClockPickerRepositoryImpl(registry: ClockRegistry) : ClockPickerRepository {
+
+    /** The currently-selected clock. */
+    override val selectedClock: Flow<ClockMetadataModel?> = callbackFlow {
+        fun send() {
+            val model =
+                registry
+                    .getClocks()
+                    .find { clockMetadata -> clockMetadata.clockId == registry.currentClockId }
+                    ?.toModel()
+            if (model == null) {
+                Log.e(TAG, "Currently selected clock ID is not one of the available clocks.")
+            }
+            trySend(model)
+        }
+
+        val listener = ClockRegistry.ClockChangeListener { send() }
+        registry.registerClockChangeListener(listener)
+        send()
+        awaitClose { registry.unregisterClockChangeListener(listener) }
+    }
+
+    private fun ClockMetadata.toModel(): ClockMetadataModel {
+        return ClockMetadataModel(clockId = clockId, name = name)
+    }
+
+    companion object {
+        private const val TAG = "ClockPickerRepositoryImpl"
+    }
+}
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
new file mode 100644
index 0000000..2529958
--- /dev/null
+++ b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
@@ -0,0 +1,135 @@
+/*
+ * 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.data.repository
+
+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
+import com.android.systemui.plugins.PluginListener
+import com.android.systemui.plugins.PluginManager
+import com.android.systemui.shared.clocks.ClockRegistry
+import com.android.systemui.shared.clocks.DefaultClockProvider
+import com.android.systemui.shared.plugins.PluginActionManager
+import com.android.systemui.shared.plugins.PluginEnabler
+import com.android.systemui.shared.plugins.PluginInstance
+import com.android.systemui.shared.plugins.PluginManagerImpl
+import com.android.systemui.shared.plugins.PluginPrefs
+import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager_Factory
+import java.util.concurrent.Executors
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+/**
+ * Provide the [ClockRegistry] singleton. Note that we need to make sure that the [PluginManager]
+ * needs to be connected before [ClockRegistry] is ready to use.
+ */
+class ClockRegistryProvider(
+    private val context: Context,
+) {
+    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)
+        )
+    }
+
+    suspend fun get(): ClockRegistry {
+        return suspendCancellableCoroutine { continuation ->
+            val pluginListener =
+                object : PluginListener<ClockProviderPlugin> {
+                    var hasConnected = false
+                    override fun onPluginConnected(
+                        plugin: ClockProviderPlugin?,
+                        pluginContext: Context?
+                    ) {
+                        if (!hasConnected) {
+                            pluginManager.removePluginListener(this)
+                            hasConnected = true
+                            continuation.resumeWith(Result.success(clockRegistry))
+                        }
+                    }
+                }
+            pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java, true)
+            continuation.invokeOnCancellation { pluginManager.removePluginListener(pluginListener) }
+        }
+    }
+
+    private fun createPluginManager(context: Context): PluginManager {
+        val privilegedPlugins = listOf<String>()
+        val isDebugDevice = true
+
+        val instanceFactory =
+            PluginInstance.Factory(
+                this::class.java.classLoader,
+                PluginInstance.InstanceFactory<Plugin>(),
+                PluginInstance.VersionChecker(),
+                privilegedPlugins,
+                isDebugDevice,
+            )
+
+        /*
+         * let SystemUI handle plugin, in this class assume plugins are enabled
+         */
+        val pluginEnabler =
+            object : PluginEnabler {
+                override fun setEnabled(component: ComponentName) = Unit
+
+                override fun setDisabled(
+                    component: ComponentName,
+                    @PluginEnabler.DisableReason reason: Int
+                ) = Unit
+
+                override fun isEnabled(component: ComponentName): Boolean {
+                    return true
+                }
+
+                @PluginEnabler.DisableReason
+                override fun getDisableReason(componentName: ComponentName): Int {
+                    return PluginEnabler.ENABLED
+                }
+            }
+
+        val pluginActionManager =
+            PluginActionManager.Factory(
+                context,
+                context.packageManager,
+                context.mainExecutor,
+                Executors.newSingleThreadExecutor(),
+                context.getSystemService(NotificationManager::class.java),
+                pluginEnabler,
+                privilegedPlugins,
+                instanceFactory,
+            )
+        return PluginManagerImpl(
+            context,
+            pluginActionManager,
+            isDebugDevice,
+            UncaughtExceptionPreHandlerManager_Factory.create().get(),
+            pluginEnabler,
+            PluginPrefs(context),
+            listOf(),
+        )
+    }
+}
diff --git a/src/com/android/customization/picker/clock/ClockCustomDemoFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
similarity index 73%
rename from src/com/android/customization/picker/clock/ClockCustomDemoFragment.kt
rename to src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
index 4f65080..4aa5de4 100644
--- a/src/com/android/customization/picker/clock/ClockCustomDemoFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
@@ -1,4 +1,4 @@
-package com.android.customization.picker.clock
+package com.android.customization.picker.clock.ui.fragment
 
 import android.content.Context
 import android.os.Bundle
@@ -13,43 +13,23 @@
 import android.widget.TextView
 import android.widget.Toast
 import androidx.core.view.setPadding
+import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.android.customization.module.ThemePickerInjector
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.plugins.ClockMetadata
-import com.android.systemui.plugins.ClockProviderPlugin
-import com.android.systemui.plugins.PluginListener
-import com.android.systemui.plugins.PluginManager
 import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.wallpaper.R
 import com.android.wallpaper.module.InjectorProvider
 import com.android.wallpaper.picker.AppbarFragment
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 
 class ClockCustomDemoFragment : AppbarFragment() {
-    @VisibleForTesting lateinit var clockRegistry: ClockRegistry
     @VisibleForTesting lateinit var recyclerView: RecyclerView
-    lateinit var pluginManager: PluginManager
-    @VisibleForTesting
-    val pluginListener =
-        object : PluginListener<ClockProviderPlugin> {
-            override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) {
-                val listInUse = clockRegistry.getClocks().filter { "NOT_IN_USE" !in it.clockId }
-                recyclerView.adapter =
-                    ClockRecyclerAdapter(listInUse, context) {
-                        clockRegistry.currentClockId = it.clockId
-                        Toast.makeText(context, "${it.name} selected", Toast.LENGTH_SHORT).show()
-                    }
-            }
-        }
-
-    override fun onAttach(context: Context) {
-        super.onAttach(context)
-        val injector = InjectorProvider.getInjector() as ThemePickerInjector
-        pluginManager = injector.getPluginManager(context)
-        clockRegistry = injector.getClockRegistry(context)
-        pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java, true)
-    }
+    @VisibleForTesting lateinit var clockRegistry: ClockRegistry
 
     override fun onCreateView(
         inflater: LayoutInflater,
@@ -58,6 +38,20 @@
     ): View {
         val view = inflater.inflate(R.layout.fragment_clock_custom_picker_demo, container, false)
         setUpToolbar(view)
+        lifecycleScope.launch {
+            clockRegistry =
+                withContext(Dispatchers.IO) {
+                    (InjectorProvider.getInjector() as ThemePickerInjector)
+                        .getClockRegistryProvider(requireContext())
+                        .get()
+                }
+            val listInUse = clockRegistry.getClocks().filter { "NOT_IN_USE" !in it.clockId }
+            recyclerView.adapter =
+                ClockRecyclerAdapter(listInUse, requireContext()) {
+                    clockRegistry.currentClockId = it.clockId
+                    Toast.makeText(context, "${it.name} selected", Toast.LENGTH_SHORT).show()
+                }
+        }
         return view
     }
 
diff --git a/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt b/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt
index 748fa17..052d0f5 100644
--- a/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt
+++ b/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt
@@ -18,21 +18,27 @@
 import android.content.Context
 import android.view.LayoutInflater
 import androidx.lifecycle.LifecycleOwner
-import com.android.customization.picker.clock.ClockCustomDemoFragment
-import com.android.customization.picker.clock.ClockSectionView
+import androidx.lifecycle.lifecycleScope
+import com.android.customization.module.ThemePickerInjector
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
 import com.android.customization.picker.clock.ui.binder.ClockSectionViewBinder
-import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
+import com.android.customization.picker.clock.ui.fragment.ClockCustomDemoFragment
+import com.android.customization.picker.clock.ui.view.ClockSectionView
 import com.android.wallpaper.R
 import com.android.wallpaper.config.BaseFlags
 import com.android.wallpaper.model.CustomizationSectionController
 import com.android.wallpaper.model.CustomizationSectionController.CustomizationSectionNavigationController
+import com.android.wallpaper.module.InjectorProvider
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 
 /** A [CustomizationSectionController] for clock customization. */
 class ClockSectionController(
     private val navigationController: CustomizationSectionNavigationController,
-    private val viewModel: ClockSectionViewModel,
     private val lifecycleOwner: LifecycleOwner,
     private val flag: BaseFlags,
+    private val clockRegistryProvider: ClockRegistryProvider,
 ) : CustomizationSectionController<ClockSectionView?> {
 
     override fun isAvailable(context: Context?): Boolean {
@@ -46,11 +52,16 @@
                     R.layout.clock_section_view,
                     null,
                 ) as ClockSectionView
-        ClockSectionViewBinder.bind(
-            view = view,
-            viewModel = viewModel,
-            lifecycleOwner = lifecycleOwner
-        ) { navigationController.navigateTo(ClockCustomDemoFragment()) }
+        lifecycleOwner.lifecycleScope.launch {
+            val registry = withContext(Dispatchers.IO) { clockRegistryProvider.get() }
+            ClockSectionViewBinder.bind(
+                view = view,
+                viewModel =
+                    (InjectorProvider.getInjector() as ThemePickerInjector)
+                        .getClockSectionViewModel(context, registry),
+                lifecycleOwner = lifecycleOwner
+            ) { navigationController.navigateTo(ClockCustomDemoFragment()) }
+        }
         return view
     }
 }
diff --git a/src/com/android/customization/picker/clock/ClockSectionView.kt b/src/com/android/customization/picker/clock/ui/view/ClockSectionView.kt
similarity index 93%
rename from src/com/android/customization/picker/clock/ClockSectionView.kt
rename to src/com/android/customization/picker/clock/ui/view/ClockSectionView.kt
index fac975a..cca107c 100644
--- a/src/com/android/customization/picker/clock/ClockSectionView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockSectionView.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.customization.picker.clock
+package com.android.customization.picker.clock.ui.view
 
 import android.content.Context
 import android.util.AttributeSet
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 57e9401..30372fe 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
@@ -54,12 +54,12 @@
         slotTabView.adapter = slotTabAdapter
         slotTabView.layoutManager =
             LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false)
-        slotTabView.addItemDecoration(ItemSpacing())
+        slotTabView.addItemDecoration(ItemSpacing(SLOT_TAB_ITEM_SPACING_DP))
         val affordancesAdapter = AffordancesAdapter()
         affordancesView.adapter = affordancesAdapter
         affordancesView.layoutManager =
             LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false)
-        affordancesView.addItemDecoration(ItemSpacing())
+        affordancesView.addItemDecoration(ItemSpacing(AFFORDANCE_ITEM_SPACING_DP))
 
         var dialog: Dialog? = null
 
@@ -74,6 +74,16 @@
                 launch {
                     viewModel.quickAffordances.collect { affordances ->
                         affordancesAdapter.setItems(affordances)
+
+                        // Scroll the view to show the first selected affordance.
+                        val selectedPosition = affordances.indexOfFirst { it.isSelected }
+                        if (selectedPosition != -1) {
+                            // We use "post" because we need to give the adapter item a pass to
+                            // update the view.
+                            affordancesView.post {
+                                affordancesView.smoothScrollToPosition(selectedPosition)
+                            }
+                        }
                     }
                 }
 
@@ -108,27 +118,29 @@
         )
     }
 
-    private class ItemSpacing : RecyclerView.ItemDecoration() {
+    private 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) ITEM_SPACING_DP.toPx(density) else 0
-                outRect.right = if (addSpacingToEnd) ITEM_SPACING_DP.toPx(density) else 0
+                outRect.left = if (addSpacingToStart) halfItemSpacingPx else 0
+                outRect.right = if (addSpacingToEnd) halfItemSpacingPx else 0
             } else {
-                outRect.left = if (addSpacingToEnd) ITEM_SPACING_DP.toPx(density) else 0
-                outRect.right = if (addSpacingToStart) ITEM_SPACING_DP.toPx(density) else 0
+                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 {
-            private const val ITEM_SPACING_DP = 8
-        }
     }
+
+    private const val SLOT_TAB_ITEM_SPACING_DP = 12
+    private const val AFFORDANCE_ITEM_SPACING_DP = 8
 }
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 51b98ef..8d8a517 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt
@@ -30,7 +30,6 @@
 import com.android.wallpaper.R
 import com.android.wallpaper.module.InjectorProvider
 import com.android.wallpaper.picker.AppbarFragment
-import com.android.wallpaper.picker.undo.ui.binder.RevertToolbarButtonBinder
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -62,12 +61,6 @@
                     injector.getKeyguardQuickAffordancePickerViewModelFactory(requireContext()),
                 )
                 .get()
-        setUpToolbarMenu(R.menu.undoable_customization_menu)
-        RevertToolbarButtonBinder.bind(
-            view = view.requireViewById(toolbarId),
-            viewModel = viewModel.undo,
-            lifecycleOwner = this,
-        )
 
         KeyguardQuickAffordancePreviewBinder.bind(
             activity = requireActivity(),
diff --git a/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt b/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt
index b5954e5..92917ed 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt
@@ -38,8 +38,6 @@
 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.ScreenPreviewViewModel
-import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor
-import com.android.wallpaper.picker.undo.ui.viewmodel.UndoViewModel
 import com.android.wallpaper.util.PreviewUtils
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -57,7 +55,6 @@
 private constructor(
     context: Context,
     private val quickAffordanceInteractor: KeyguardQuickAffordancePickerInteractor,
-    undoInteractor: UndoInteractor,
     private val wallpaperInfoFactory: CurrentWallpaperInfoFactory,
     activityStarter: (Intent) -> Unit,
 ) : ViewModel() {
@@ -94,11 +91,6 @@
             },
         )
 
-    val undo: UndoViewModel =
-        UndoViewModel(
-            interactor = undoInteractor,
-        )
-
     private val _selectedSlotId = MutableStateFlow<String?>(null)
     val selectedSlotId: StateFlow<String?> = _selectedSlotId.asStateFlow()
 
@@ -390,7 +382,6 @@
     class Factory(
         private val context: Context,
         private val quickAffordanceInteractor: KeyguardQuickAffordancePickerInteractor,
-        private val undoInteractor: UndoInteractor,
         private val wallpaperInfoFactory: CurrentWallpaperInfoFactory,
         private val activityStarter: (Intent) -> Unit,
     ) : ViewModelProvider.Factory {
@@ -399,7 +390,6 @@
             return KeyguardQuickAffordancePickerViewModel(
                 context = context,
                 quickAffordanceInteractor = quickAffordanceInteractor,
-                undoInteractor = undoInteractor,
                 wallpaperInfoFactory = wallpaperInfoFactory,
                 activityStarter = activityStarter,
             )
diff --git a/tests/robotests/src/com/android/customization/picker/clock/ClockCustomDemoFragmentTest.kt b/tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
similarity index 93%
rename from tests/robotests/src/com/android/customization/picker/clock/ClockCustomDemoFragmentTest.kt
rename to tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
index ad3dd1c..430dd27 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/ClockCustomDemoFragmentTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
@@ -1,4 +1,4 @@
-package com.android.customization.picker.clock
+package com.android.customization.picker.clock.ui.fragment
 
 import android.os.Handler
 import android.os.UserHandle
@@ -9,7 +9,6 @@
 import com.android.systemui.plugins.ClockId
 import com.android.systemui.plugins.ClockMetadata
 import com.android.systemui.plugins.ClockProvider
-import com.android.systemui.plugins.ClockProviderPlugin
 import com.android.systemui.plugins.PluginManager
 import com.android.systemui.shared.clocks.ClockRegistry
 import org.junit.Assert
@@ -32,7 +31,6 @@
     private lateinit var registry: ClockRegistry
     @Mock private lateinit var mockPluginManager: PluginManager
     @Mock private lateinit var mockHandler: Handler
-    @Mock private lateinit var fakePlugin: ClockProviderPlugin
     @Mock private lateinit var defaultClockProvider: ClockProvider
 
     private var settingValue: String = ""
@@ -74,7 +72,6 @@
         mClockCustomDemoFragment!!.recyclerView = RecyclerView(mActivity)
         mClockCustomDemoFragment!!.recyclerView.layoutManager =
             LinearLayoutManager(mActivity, RecyclerView.VERTICAL, false)
-        mClockCustomDemoFragment!!.pluginListener.onPluginConnected(fakePlugin, mActivity)
     }
 
     @Test
diff --git a/tests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt b/tests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
index 85d5e3b..fd03285 100644
--- a/tests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
+++ b/tests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
@@ -34,9 +34,6 @@
 import com.android.wallpaper.module.InjectorProvider
 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.undo.data.repository.UndoRepository
-import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor
-import com.android.wallpaper.testing.FAKE_RESTORERS
 import com.android.wallpaper.testing.FakeSnapshotStore
 import com.android.wallpaper.testing.TestCurrentWallpaperInfoFactory
 import com.android.wallpaper.testing.TestInjector
@@ -96,17 +93,10 @@
                         .apply { runBlocking { setUpSnapshotRestorer(FakeSnapshotStore()) } }
                 },
             )
-        val undoInteractor =
-            UndoInteractor(
-                scope = testScope.backgroundScope,
-                repository = UndoRepository(),
-                restorerByOwnerId = FAKE_RESTORERS,
-            )
         underTest =
             KeyguardQuickAffordancePickerViewModel.Factory(
                     context = context,
                     quickAffordanceInteractor = quickAffordanceInteractor,
-                    undoInteractor = undoInteractor,
                     wallpaperInfoFactory = TestCurrentWallpaperInfoFactory(context),
                     activityStarter = { intent -> latestStartedActivityIntent = intent },
                 )
diff --git a/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt b/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
new file mode 100644
index 0000000..ea97c9a
--- /dev/null
+++ b/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.data.repository
+
+import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeClockPickerRepository : ClockPickerRepository {
+
+    override val selectedClock: Flow<ClockMetadataModel?> = MutableStateFlow(null)
+}
diff --git a/tests/src/com/android/customization/testing/TestCustomizationInjector.kt b/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
index afc7131..735ba8e 100644
--- a/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
+++ b/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
@@ -1,9 +1,6 @@
 package com.android.customization.testing
 
 import android.content.Context
-import android.os.Handler
-import android.os.UserHandle
-import android.view.LayoutInflater
 import androidx.fragment.app.FragmentActivity
 import com.android.customization.model.theme.OverlayManagerCompat
 import com.android.customization.model.theme.ThemeBundleProvider
@@ -11,12 +8,14 @@
 import com.android.customization.module.CustomizationInjector
 import com.android.customization.module.CustomizationPreferences
 import com.android.customization.module.ThemesUserEventLogger
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
+import com.android.customization.picker.clock.data.repository.FakeClockPickerRepository
+import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
+import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
 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.plugins.PluginManager
 import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.systemui.shared.clocks.DefaultClockProvider
 import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
 import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
 import com.android.wallpaper.config.BaseFlags
@@ -25,7 +24,6 @@
 import com.android.wallpaper.module.UserEventLogger
 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
 import com.android.wallpaper.testing.TestInjector
-import java.util.HashMap
 import kotlinx.coroutines.Dispatchers.IO
 
 /** Test implementation of the dependency injector. */
@@ -41,8 +39,9 @@
     private var customizationProviderClient: CustomizationProviderClient? = null
     private var keyguardQuickAffordanceSnapshotRestorer: KeyguardQuickAffordanceSnapshotRestorer? =
         null
-    private var clockRegistry: ClockRegistry? = null
-    private var pluginManager: PluginManager? = null
+    private var clockRegistryProvider: ClockRegistryProvider? = null
+    private var clockPickerInteractor: ClockPickerInteractor? = null
+    private var clockSectionViewModel: ClockSectionViewModel? = null
 
     override fun getCustomizationPreferences(context: Context): CustomizationPreferences {
         return customizationPreferences
@@ -128,21 +127,29 @@
                 .also { keyguardQuickAffordanceSnapshotRestorer = it }
     }
 
-    override fun getClockRegistry(context: Context): ClockRegistry {
-        return clockRegistry
-            ?: ClockRegistry(
-                    context,
-                    getPluginManager(context),
-                    Handler.getMain(),
-                    isEnabled = true,
-                    userHandle = UserHandle.USER_SYSTEM,
-                    DefaultClockProvider(context, LayoutInflater.from(context), context.resources)
-                )
-                .also { clockRegistry = it }
+    override fun getClockRegistryProvider(context: Context): ClockRegistryProvider {
+        return clockRegistryProvider
+            ?: ClockRegistryProvider(context).also { clockRegistryProvider = it }
     }
 
-    override fun getPluginManager(context: Context): PluginManager {
-        return pluginManager ?: TestPluginManager().also { pluginManager = it }
+    override fun getClockPickerInteractor(
+        context: Context,
+        clockRegistry: ClockRegistry
+    ): ClockPickerInteractor {
+        return clockPickerInteractor
+            ?: ClockPickerInteractor(FakeClockPickerRepository()).also {
+                clockPickerInteractor = it
+            }
+    }
+
+    override fun getClockSectionViewModel(
+        context: Context,
+        clockRegistry: ClockRegistry
+    ): ClockSectionViewModel {
+        return clockSectionViewModel
+            ?: ClockSectionViewModel(getClockPickerInteractor(context, clockRegistry)).also {
+                clockSectionViewModel = it
+            }
     }
 
     companion object {