Merge "Conform the logic to decide wallpaper darkness" into udc-dev
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 11e51c6..72b9f3a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,6 +1,14 @@
 {
   "presubmit": [
     {
+      "name": "WallpaperPicker2Tests",
+      "options": [
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    },
+    {
       "name": "ThemePickerTests",
       "options": [
         {
diff --git a/res/layout/keyguard_quick_affordance.xml b/res/layout/keyguard_quick_affordance.xml
index 1e5c339..a86489a 100644
--- a/res/layout/keyguard_quick_affordance.xml
+++ b/res/layout/keyguard_quick_affordance.xml
@@ -62,8 +62,10 @@
         android:id="@id/text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:gravity="center_horizontal"
         android:textColor="@color/text_color_primary"
-        android:singleLine="true"
+        android:maxLines="2"
+        android:hyphenationFrequency="normal"
         android:ellipsize="end"
         android:text="Placeholder for stable size calculation, please do not remove."
         tools:ignore="HardcodedText" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 543ddfb..a3e0d4a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -161,7 +161,7 @@
     <dimen name="clock_carousel_guideline_margin">100dp</dimen>
     <dimen name="clock_carousel_item_card_width">100dp</dimen>
     <dimen name="clock_carousel_item_card_height">108dp</dimen>
-    <dimen name="clock_carousel_guideline_margin_for_2_pane_small_width">130dp</dimen>
+    <dimen name="clock_carousel_guideline_margin_for_2_pane_small_width">122dp</dimen>
 
     <!-- Clock color and size button -->
     <dimen name="clock_color_size_button_min_height">32dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c023924..40142d1 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -34,7 +34,7 @@
     <string name="clock_picker_entry_content_description">Change a custom clock</string>
 
     <!-- Title of a section of the customization picker where the user can configure Clock face. [CHAR LIMIT=19] -->
-    <string name="clock_settings_title">Clock Settings</string>
+    <string name="clock_settings_title">Clock color &amp; size</string>
 
     <!-- Title of a section of the customization picker where the user can configure clock color and size. [CHAR LIMIT=20] -->
     <string name="clock_color_and_size_title">Clock color &amp; size</string>
@@ -360,14 +360,7 @@
     enabled. The dialog contains a list of instructions that the user needs to take in order to
     enable the option before it can be selected again. [CHAR LIMIT=NONE].
     -->
-    <string name="keyguard_affordance_enablement_dialog_headline">Shortcut unavailable</string>
-
-    <!--
-    Supporting text for a popup dialog shown when the user attempts to select an option that is not
-    currently enabled. The dialog contains a list of instructions that the user needs to take in
-    order to enable the option before it can be selected again. [CHAR LIMIT=NONE].
-    -->
-    <string name="keyguard_affordance_enablement_dialog_title">To select `<xliff:g id="appName" example="Wallet">%1$s</xliff:g>` check the following</string>
+    <string name="keyguard_affordance_enablement_dialog_headline">Can\'t add shortcut</string>
 
     <!--
     Template for an action that opens a specific app. [CHAR LIMIT=16]
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 87aae10..c70b596 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -124,7 +124,7 @@
         <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
         <item name="android:textColor">?android:textColorSecondary</item>
         <item name="android:textSize">14sp</item>
-        <item name="android:lineHeight">20dp</item>
+        <item name="android:lineHeight">16sp</item>
     </style>
 
     <style name="BetaTagTextStyle" parent="SectionTitleTextStyle">
diff --git a/src/com/android/customization/module/CustomizationInjector.kt b/src/com/android/customization/module/CustomizationInjector.kt
index b943925..8b0d90f 100644
--- a/src/com/android/customization/module/CustomizationInjector.kt
+++ b/src/com/android/customization/module/CustomizationInjector.kt
@@ -18,7 +18,6 @@
 import android.content.Context
 import androidx.activity.ComponentActivity
 import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.LifecycleOwner
 import com.android.customization.model.theme.OverlayManagerCompat
 import com.android.customization.model.theme.ThemeBundleProvider
 import com.android.customization.model.theme.ThemeManager
@@ -48,16 +47,12 @@
         context: Context,
     ): KeyguardQuickAffordancePickerInteractor
 
-    fun getClockRegistry(context: Context, lifecycleOwner: LifecycleOwner): ClockRegistry
+    fun getClockRegistry(context: Context): ClockRegistry?
 
-    fun getClockPickerInteractor(
-        context: Context,
-        lifecycleOwner: LifecycleOwner
-    ): ClockPickerInteractor
+    fun getClockPickerInteractor(context: Context): ClockPickerInteractor
 
     fun getClockSectionViewModel(
         context: Context,
-        lifecycleOwner: LifecycleOwner
     ): ClockSectionViewModel
 
     fun getColorPickerInteractor(
@@ -80,6 +75,5 @@
         context: Context,
         wallpaperColorsViewModel: WallpaperColorsViewModel,
         clockViewFactory: ClockViewFactory,
-        lifecycleOwner: LifecycleOwner,
     ): ClockSettingsViewModel.Factory
 }
diff --git a/src/com/android/customization/module/ThemePickerInjector.kt b/src/com/android/customization/module/ThemePickerInjector.kt
index b23d912..a9d2874 100644
--- a/src/com/android/customization/module/ThemePickerInjector.kt
+++ b/src/com/android/customization/module/ThemePickerInjector.kt
@@ -134,7 +134,7 @@
                     ),
                     getFlags(),
                     getClockCarouselViewModelFactory(
-                        getClockPickerInteractor(activity.applicationContext, activity),
+                        getClockPickerInteractor(activity.applicationContext),
                     ),
                     getClockViewFactory(activity),
                     getDarkModeSnapshotRestorer(activity),
@@ -181,7 +181,7 @@
     @Synchronized
     override fun getUserEventLogger(context: Context): ThemesUserEventLogger {
         return if (userEventLogger != null) userEventLogger as ThemesUserEventLogger
-        else StatsLogUserEventLogger(context).also { userEventLogger = it }
+        else StatsLogUserEventLogger(context.applicationContext).also { userEventLogger = it }
     }
 
     @Synchronized
@@ -196,24 +196,22 @@
 
     override fun getSnapshotRestorers(
         context: Context,
-        lifecycleOwner: LifecycleOwner
     ): Map<Int, SnapshotRestorer> {
-        return super<WallpaperPicker2Injector>.getSnapshotRestorers(context, lifecycleOwner)
-            .toMutableMap()
-            .apply {
-                this[KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER] =
-                    getKeyguardQuickAffordanceSnapshotRestorer(context)
+        return super<WallpaperPicker2Injector>.getSnapshotRestorers(context).toMutableMap().apply {
+            this[KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER] =
+                getKeyguardQuickAffordanceSnapshotRestorer(context)
+            // TODO(b/285047815): Enable after adding wallpaper id for default static wallpaper
+            if (getFlags().isWallpaperRestorerEnabled()) {
                 this[KEY_WALLPAPER_SNAPSHOT_RESTORER] = getWallpaperSnapshotRestorer(context)
-                this[KEY_NOTIFICATIONS_SNAPSHOT_RESTORER] =
-                    getNotificationsSnapshotRestorer(context)
-                this[KEY_DARK_MODE_SNAPSHOT_RESTORER] = getDarkModeSnapshotRestorer(context)
-                this[KEY_THEMED_ICON_SNAPSHOT_RESTORER] = getThemedIconSnapshotRestorer(context)
-                this[KEY_APP_GRID_SNAPSHOT_RESTORER] = getGridSnapshotRestorer(context)
-                this[KEY_COLOR_PICKER_SNAPSHOT_RESTORER] =
-                    getColorPickerSnapshotRestorer(context, getWallpaperColorsViewModel())
-                this[KEY_CLOCKS_SNAPSHOT_RESTORER] =
-                    getClockPickerSnapshotRestorer(context, lifecycleOwner)
             }
+            this[KEY_NOTIFICATIONS_SNAPSHOT_RESTORER] = getNotificationsSnapshotRestorer(context)
+            this[KEY_DARK_MODE_SNAPSHOT_RESTORER] = getDarkModeSnapshotRestorer(context)
+            this[KEY_THEMED_ICON_SNAPSHOT_RESTORER] = getThemedIconSnapshotRestorer(context)
+            this[KEY_APP_GRID_SNAPSHOT_RESTORER] = getGridSnapshotRestorer(context)
+            this[KEY_COLOR_PICKER_SNAPSHOT_RESTORER] =
+                getColorPickerSnapshotRestorer(context, getWallpaperColorsViewModel())
+            this[KEY_CLOCKS_SNAPSHOT_RESTORER] = getClockPickerSnapshotRestorer(context)
+        }
     }
 
     override fun getCustomizationPreferences(context: Context): CustomizationPreferences {
@@ -230,6 +228,7 @@
     }
 
     override fun getWallpaperInteractor(context: Context): WallpaperInteractor {
+        val appContext = context.applicationContext
         return wallpaperInteractor
             ?: WallpaperInteractor(
                     repository =
@@ -237,16 +236,16 @@
                             scope = getApplicationCoroutineScope(),
                             client =
                                 WallpaperClientImpl(
-                                    context = context,
+                                    context = appContext,
                                     infoFactory = getCurrentWallpaperInfoFactory(context),
                                     wallpaperManager = WallpaperManager.getInstance(context)
                                 ),
-                            wallpaperPreferences = getPreferences(context = context),
+                            wallpaperPreferences = getPreferences(context = appContext),
                             backgroundDispatcher = Dispatchers.IO,
                         ),
                     shouldHandleReload = {
                         TextUtils.equals(
-                            getColorCustomizationManager(context).currentColorSource,
+                            getColorCustomizationManager(appContext).currentColorSource,
                             ColorOptionsProvider.COLOR_SOURCE_PRESET
                         )
                     }
@@ -268,7 +267,7 @@
     ): KeyguardQuickAffordancePickerViewModel.Factory {
         return keyguardQuickAffordancePickerViewModelFactory
             ?: KeyguardQuickAffordancePickerViewModel.Factory(
-                    context,
+                    context.applicationContext,
                     getKeyguardQuickAffordancePickerInteractor(context),
                     getWallpaperInteractor(context),
                     getCurrentWallpaperInfoFactory(context),
@@ -280,11 +279,12 @@
         context: Context
     ): KeyguardQuickAffordancePickerInteractor {
         val client = getKeyguardQuickAffordancePickerProviderClient(context)
+        val appContext = context.applicationContext
         return KeyguardQuickAffordancePickerInteractor(
             KeyguardQuickAffordancePickerRepository(client, Dispatchers.IO),
             client
         ) {
-            getKeyguardQuickAffordanceSnapshotRestorer(context)
+            getKeyguardQuickAffordanceSnapshotRestorer(appContext)
         }
     }
 
@@ -292,7 +292,7 @@
         context: Context
     ): CustomizationProviderClient {
         return customizationProviderClient
-            ?: CustomizationProviderClientImpl(context, Dispatchers.IO).also {
+            ?: CustomizationProviderClientImpl(context.applicationContext, Dispatchers.IO).also {
                 customizationProviderClient = it
             }
     }
@@ -321,6 +321,7 @@
     private fun getNotificationsInteractor(
         context: Context,
     ): NotificationsInteractor {
+        val appContext = context.applicationContext
         return notificationsInteractor
             ?: NotificationsInteractor(
                     repository =
@@ -329,7 +330,7 @@
                             backgroundDispatcher = Dispatchers.IO,
                             secureSettingsRepository = getSecureSettingsRepository(context),
                         ),
-                    snapshotRestorer = { getNotificationsSnapshotRestorer(context) },
+                    snapshotRestorer = { getNotificationsSnapshotRestorer(appContext) },
                 )
                 .also { notificationsInteractor = it }
     }
@@ -345,42 +346,44 @@
                 .also { notificationsSnapshotRestorer = it }
     }
 
-    override fun getClockRegistry(context: Context, lifecycleOwner: LifecycleOwner): ClockRegistry {
+    override fun getClockRegistry(context: Context): ClockRegistry {
         return (clockRegistryProvider
                 ?: ClockRegistryProvider(
-                        context = context,
+                        context = context.applicationContext,
                         coroutineScope = getApplicationCoroutineScope(),
                         mainDispatcher = Dispatchers.Main,
                         backgroundDispatcher = Dispatchers.IO,
                     )
                     .also { clockRegistryProvider = it })
-            .getForOwner(lifecycleOwner)
+            .get()
     }
 
     override fun getClockPickerInteractor(
         context: Context,
-        lifecycleOwner: LifecycleOwner,
     ): ClockPickerInteractor {
+        val appContext = context.applicationContext
         return clockPickerInteractor
             ?: ClockPickerInteractor(
                     repository =
                         ClockPickerRepositoryImpl(
-                            secureSettingsRepository = getSecureSettingsRepository(context),
-                            registry = getClockRegistry(context, lifecycleOwner),
+                            secureSettingsRepository = getSecureSettingsRepository(appContext),
+                            registry = getClockRegistry(appContext),
                             scope = getApplicationCoroutineScope(),
                             mainDispatcher = Dispatchers.Main,
                         ),
-                    snapshotRestorer = { getClockPickerSnapshotRestorer(context, lifecycleOwner) },
+                    snapshotRestorer = { getClockPickerSnapshotRestorer(appContext) },
                 )
                 .also { clockPickerInteractor = it }
     }
 
     override fun getClockSectionViewModel(
         context: Context,
-        lifecycleOwner: LifecycleOwner
     ): ClockSectionViewModel {
         return clockSectionViewModel
-            ?: ClockSectionViewModel(context, getClockPickerInteractor(context, lifecycleOwner))
+            ?: ClockSectionViewModel(
+                    context.applicationContext,
+                    getClockPickerInteractor(context.applicationContext)
+                )
                 .also { clockSectionViewModel = it }
     }
 
@@ -401,10 +404,7 @@
                     ScreenSizeCalculator.getInstance()
                         .getScreenSize(activity.windowManager.defaultDisplay),
                     WallpaperManager.getInstance(activity.applicationContext),
-                    getClockRegistry(
-                        context = activity.applicationContext,
-                        lifecycleOwner = activity,
-                    ),
+                    getClockRegistry(activity.applicationContext),
                 )
                 .also {
                     clockViewFactories[activityHashCode] = it
@@ -422,10 +422,9 @@
 
     private fun getClockPickerSnapshotRestorer(
         context: Context,
-        lifecycleOwner: LifecycleOwner
     ): ClockPickerSnapshotRestorer {
         return clockPickerSnapshotRestorer
-            ?: ClockPickerSnapshotRestorer(getClockPickerInteractor(context, lifecycleOwner)).also {
+            ?: ClockPickerSnapshotRestorer(getClockPickerInteractor(context)).also {
                 clockPickerSnapshotRestorer = it
             }
     }
@@ -434,15 +433,16 @@
         context: Context,
         wallpaperColorsViewModel: WallpaperColorsViewModel,
     ): ColorPickerInteractor {
+        val appContext = context.applicationContext
         return colorPickerInteractor
             ?: ColorPickerInteractor(
                     repository =
                         ColorPickerRepositoryImpl(
                             wallpaperColorsViewModel,
-                            getColorCustomizationManager(context)
+                            getColorCustomizationManager(appContext)
                         ),
                     snapshotRestorer = {
-                        getColorPickerSnapshotRestorer(context, wallpaperColorsViewModel)
+                        getColorPickerSnapshotRestorer(appContext, wallpaperColorsViewModel)
                     }
                 )
                 .also { colorPickerInteractor = it }
@@ -454,7 +454,7 @@
     ): ColorPickerViewModel.Factory {
         return colorPickerViewModelFactory
             ?: ColorPickerViewModel.Factory(
-                    context,
+                    context.applicationContext,
                     getColorPickerInteractor(context, wallpaperColorsViewModel),
                 )
                 .also { colorPickerViewModelFactory = it }
@@ -481,10 +481,11 @@
     fun getDarkModeSnapshotRestorer(
         context: Context,
     ): DarkModeSnapshotRestorer {
+        val appContext = context.applicationContext
         return darkModeSnapshotRestorer
             ?: DarkModeSnapshotRestorer(
-                    context = context,
-                    manager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager,
+                    context = appContext,
+                    manager = appContext.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager,
                     backgroundDispatcher = Dispatchers.IO,
                 )
                 .also { darkModeSnapshotRestorer = it }
@@ -517,12 +518,11 @@
         context: Context,
         wallpaperColorsViewModel: WallpaperColorsViewModel,
         clockViewFactory: ClockViewFactory,
-        lifecycleOwner: LifecycleOwner,
     ): ClockSettingsViewModel.Factory {
         return clockSettingsViewModelFactory
             ?: ClockSettingsViewModel.Factory(
-                    context,
-                    getClockPickerInteractor(context, lifecycleOwner),
+                    context.applicationContext,
+                    getClockPickerInteractor(context),
                     getColorPickerInteractor(
                         context,
                         wallpaperColorsViewModel,
@@ -548,6 +548,7 @@
     private fun getGridInteractor(
         context: Context,
     ): GridInteractor {
+        val appContext = context.applicationContext
         return gridInteractor
             ?: GridInteractor(
                     applicationScope = getApplicationCoroutineScope(),
@@ -557,7 +558,7 @@
                             manager = GridOptionsManager.getInstance(context),
                             backgroundDispatcher = Dispatchers.IO,
                         ),
-                    snapshotRestorer = { getGridSnapshotRestorer(context) },
+                    snapshotRestorer = { getGridSnapshotRestorer(appContext) },
                 )
                 .also { gridInteractor = it }
     }
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 52c3c4e..652ffdd 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
@@ -19,8 +19,6 @@
 import android.content.ComponentName
 import android.content.Context
 import android.view.LayoutInflater
-import androidx.lifecycle.DefaultLifecycleObserver
-import androidx.lifecycle.LifecycleOwner
 import com.android.systemui.plugins.Plugin
 import com.android.systemui.plugins.PluginManager
 import com.android.systemui.shared.clocks.ClockRegistry
@@ -45,50 +43,28 @@
     private val mainDispatcher: CoroutineDispatcher,
     private val backgroundDispatcher: CoroutineDispatcher,
 ) {
-    private val lifecycleOwners = mutableSetOf<Int>()
-    private val pluginManager: PluginManager by lazy { createPluginManager(context) }
     private val clockRegistry: ClockRegistry by lazy {
         ClockRegistry(
-                context,
-                pluginManager,
-                coroutineScope,
-                mainDispatcher,
-                backgroundDispatcher,
-                isEnabled = true,
-                handleAllUsers = false,
-                DefaultClockProvider(context, LayoutInflater.from(context), context.resources),
-                keepAllLoaded = true,
-                subTag = "Picker",
-            )
-            .apply { registerListeners() }
-    }
-
-    fun getForOwner(lifecycleOwner: LifecycleOwner): ClockRegistry {
-        registerLifecycleOwner(lifecycleOwner)
-        return clockRegistry
-    }
-
-    private fun registerLifecycleOwner(lifecycleOwner: LifecycleOwner) {
-        lifecycleOwners.add(lifecycleOwner.hashCode())
-
-        lifecycleOwner.lifecycle.addObserver(
-            object : DefaultLifecycleObserver {
-                override fun onDestroy(owner: LifecycleOwner) {
-                    super.onDestroy(owner)
-                    unregisterLifecycleOwner(owner)
-                }
-            }
+            context,
+            createPluginManager(context),
+            coroutineScope,
+            mainDispatcher,
+            backgroundDispatcher,
+            isEnabled = true,
+            handleAllUsers = false,
+            DefaultClockProvider(context, LayoutInflater.from(context), context.resources),
+            keepAllLoaded = true,
+            subTag = "Picker",
         )
     }
 
-    private fun unregisterLifecycleOwner(lifecycleOwner: LifecycleOwner) {
-        lifecycleOwners.remove(lifecycleOwner.hashCode())
-
-        if (lifecycleOwners.isEmpty()) {
-            clockRegistry.unregisterListeners()
-        }
+    init {
+        // Listeners in ClockRegistry get cleaned up when app ended
+        clockRegistry.registerListeners()
     }
 
+    fun get() = clockRegistry
+
     private fun createPluginManager(context: Context): PluginManager {
         val privilegedPlugins = listOf<String>()
         val isDebugDevice = true
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 053ac55..4f4bd1b 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
@@ -176,23 +176,23 @@
                             ::Pair,
                         )
                         .collect { (clockId, size) ->
-                            val clockView =
-                                if (size == ClockSize.DYNAMIC) {
-                                    clockViewFactory.getLargeView(clockId)
-                                } else {
-                                    clockViewFactory.getSmallView(clockId)
-                                }
-                            (clockView.parent as? ViewGroup)?.removeView(clockView)
                             clockHostView.removeAllViews()
+                            val clockView =
+                                when (size) {
+                                    ClockSize.DYNAMIC -> clockViewFactory.getLargeView(clockId)
+                                    ClockSize.SMALL -> clockViewFactory.getSmallView(clockId)
+                                }
+                            // The clock view might still be attached to an existing parent. Detach
+                            // before adding to another parent.
+                            (clockView.parent as? ViewGroup)?.removeView(clockView)
                             clockHostView.addView(clockView)
-
                             when (size) {
                                 ClockSize.DYNAMIC -> {
                                     sizeOptions.radioButtonDynamic.isChecked = true
                                     sizeOptions.radioButtonSmall.isChecked = false
                                     clockHostView.doOnPreDraw {
-                                        it.pivotX = (it.width / 2).toFloat()
-                                        it.pivotY = (it.height / 2).toFloat()
+                                        it.pivotX = it.width / 2F
+                                        it.pivotY = it.height / 2F
                                     }
                                 }
                                 ClockSize.SMALL -> {
diff --git a/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
index 6203e24..f138d6a 100644
--- a/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
@@ -37,7 +37,6 @@
         clockRegistry =
             (InjectorProvider.getInjector() as ThemePickerInjector).getClockRegistry(
                 requireContext(),
-                this
             )
         val listInUse = clockRegistry.getClocks().filter { "NOT_IN_USE" !in it.clockId }
 
diff --git a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
index d19b33c..e476d6a 100644
--- a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
@@ -123,7 +123,6 @@
                         context,
                         injector.getWallpaperColorsViewModel(),
                         injector.getClockViewFactory(activity),
-                        activity,
                     ),
                 )
                 .get(),
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
index c856112..56d4dea 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
@@ -48,8 +48,8 @@
     private lateinit var clockViewFactory: ClockViewFactory
     private var toCenterClockController: ClockController? = null
     private var offCenterClockController: ClockController? = null
-    private var toCenterClockView: View? = null
-    private var offCenterClockView: View? = null
+    private var toCenterClockScaleView: View? = null
+    private var offCenterClockScaleView: View? = null
     private var toCenterClockHostView: ClockHostView? = null
     private var offCenterClockHostView: ClockHostView? = null
     private var toCenterCardView: View? = null
@@ -125,8 +125,8 @@
                     val scalingUpClockId = adapter.clockIds[scalingUpIdx]
                     offCenterClockController = clockViewFactory.getController(scalingDownClockId)
                     toCenterClockController = clockViewFactory.getController(scalingUpClockId)
-                    offCenterClockView = motionLayout.findViewById(R.id.clock_scale_view_2)
-                    toCenterClockView =
+                    offCenterClockScaleView = motionLayout.findViewById(R.id.clock_scale_view_2)
+                    toCenterClockScaleView =
                         motionLayout.findViewById(
                             if (endId == R.id.next) R.id.clock_scale_view_3
                             else R.id.clock_scale_view_1
@@ -166,10 +166,10 @@
                         ?.onPickerCarouselSwiping(progress)
                     val scalingDownScale = getScalingDownScale(progress)
                     val scalingUpScale = getScalingUpScale(progress)
-                    offCenterClockView?.scaleX = scalingDownScale
-                    offCenterClockView?.scaleY = scalingDownScale
-                    toCenterClockView?.scaleX = scalingUpScale
-                    toCenterClockView?.scaleY = scalingUpScale
+                    offCenterClockScaleView?.scaleX = scalingDownScale
+                    offCenterClockScaleView?.scaleY = scalingDownScale
+                    toCenterClockScaleView?.scaleX = scalingUpScale
+                    toCenterClockScaleView?.scaleY = scalingUpScale
                 }
 
                 private fun onSmallClockViewTransition(progress: Float) {
@@ -339,6 +339,7 @@
                         isMiddleView,
                         clockScaleView,
                         clockId,
+                        clockHostView,
                     )
                 ClockSize.SMALL ->
                     initializeSmallClockView(
@@ -354,7 +355,12 @@
             isMiddleView: Boolean,
             clockScaleView: View,
             clockId: String,
+            clockHostView: ClockHostView,
         ) {
+            clockHostView.doOnPreDraw {
+                it.pivotX = it.width / 2F
+                it.pivotY = it.height / 2F
+            }
             if (isMiddleView) {
                 clockScaleView.scaleX = 1f
                 clockScaleView.scaleY = 1f
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt b/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
index f7c26da..e733866 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
@@ -53,16 +53,31 @@
             ?: initClockController(clockId).also { clockControllers[clockId] = it }
     }
 
+    /**
+     * Reset the large view to its initial state when getting the view. This is because some view
+     * configs, e.g. animation state, might change during the reuse of the clock view in the app.
+     */
     fun getLargeView(clockId: String): View {
-        return getController(clockId).largeClock.view
+        return getController(clockId).largeClock.let {
+            it.animations.onPickerCarouselSwiping(1F)
+            it.view
+        }
     }
 
+    /**
+     * Reset the small view to its initial state when getting the view. This is because some view
+     * configs, e.g. translation X, might change during the reuse of the clock view in the app.
+     */
     fun getSmallView(clockId: String): View {
-        return smallClockFrames[clockId]
-            ?: createSmallClockFrame().also {
-                it.addView(getController(clockId).smallClock.view)
-                smallClockFrames[clockId] = it
-            }
+        val smallClockFrame =
+            smallClockFrames[clockId]
+                ?: createSmallClockFrame().also {
+                    it.addView(getController(clockId).smallClock.view)
+                    smallClockFrames[clockId] = it
+                }
+        smallClockFrame.translationX = 0F
+        smallClockFrame.translationY = 0F
+        return smallClockFrame
     }
 
     private fun createSmallClockFrame(): FrameLayout {
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSectionViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSectionViewModel.kt
index 008a125..8a65522 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSectionViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSectionViewModel.kt
@@ -35,7 +35,7 @@
             (selectedColorId, selectedClockSize) ->
             val colorText =
                 clockColorMap[selectedColorId]?.colorName
-                    ?: context.getString(R.string.default_theme_title)
+                    ?: appContext.getString(R.string.default_theme_title)
             val sizeText =
                 when (selectedClockSize) {
                     ClockSize.SMALL -> appContext.getString(R.string.clock_size_small)
diff --git a/src/com/android/customization/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepository.kt b/src/com/android/customization/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepository.kt
index 9729661..b17af80 100644
--- a/src/com/android/customization/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepository.kt
+++ b/src/com/android/customization/picker/quickaffordance/data/repository/KeyguardQuickAffordancePickerRepository.kt
@@ -80,7 +80,7 @@
             name = name,
             iconResourceId = iconResourceId,
             isEnabled = isEnabled,
-            enablementInstructions = enablementInstructions ?: emptyList(),
+            enablementExplanation = enablementExplanation ?: "",
             enablementActionText = enablementActionText,
             enablementActionIntent = enablementActionIntent,
             configureIntent = configureIntent,
diff --git a/src/com/android/customization/picker/quickaffordance/shared/model/KeyguardQuickAffordancePickerAffordanceModel.kt b/src/com/android/customization/picker/quickaffordance/shared/model/KeyguardQuickAffordancePickerAffordanceModel.kt
index 5ca7d56..e53f790 100644
--- a/src/com/android/customization/picker/quickaffordance/shared/model/KeyguardQuickAffordancePickerAffordanceModel.kt
+++ b/src/com/android/customization/picker/quickaffordance/shared/model/KeyguardQuickAffordancePickerAffordanceModel.kt
@@ -31,8 +31,8 @@
     @DrawableRes val iconResourceId: Int,
     /** Whether this quick affordance is enabled. */
     val isEnabled: Boolean,
-    /** If not enabled, the list of user-visible steps to re-enable it. */
-    val enablementInstructions: List<String>,
+    /** If not enabled, the user-visible message explaining why. */
+    val enablementExplanation: String,
     /**
      * If not enabled, an optional label for a button that takes the user to a destination where
      * they can re-enable it.
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 08cb756..f832cde 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt
@@ -261,7 +261,7 @@
                                     showEnablementDialog(
                                         icon = affordanceIcon,
                                         name = affordance.name,
-                                        instructions = affordance.enablementInstructions,
+                                        explanation = affordance.enablementExplanation,
                                         actionText = affordance.enablementActionText,
                                         actionIntent = affordance.enablementActionIntent,
                                     )
@@ -346,7 +346,7 @@
     private fun showEnablementDialog(
         icon: Drawable,
         name: String,
-        instructions: List<String>,
+        explanation: String,
         actionText: String?,
         actionIntent: Intent?,
     ) {
@@ -358,39 +358,38 @@
                         contentDescription = null,
                     ),
                 headline = Text.Resource(R.string.keyguard_affordance_enablement_dialog_headline),
-                supportingText =
-                    Text.Loaded(
-                        applicationContext.getString(
-                            R.string.keyguard_affordance_enablement_dialog_title,
-                            name
-                        )
-                    ),
-                message =
-                    Text.Loaded(
-                        buildString {
-                            instructions.forEachIndexed { index, instruction ->
-                                if (index > 0) {
-                                    append('\n')
-                                }
-
-                                append(instruction)
-                            }
-                        }
-                    ),
+                message = Text.Loaded(explanation),
                 buttons =
-                    listOf(
-                        ButtonViewModel(
-                            text = actionText?.let { Text.Loaded(actionText) }
-                                    ?: Text.Resource(
-                                        R.string
-                                            .keyguard_affordance_enablement_dialog_dismiss_button,
+                    buildList {
+                        add(
+                            ButtonViewModel(
+                                text =
+                                    Text.Resource(
+                                        if (actionText != null) {
+                                            // This is not the only button on the dialog.
+                                            R.string.cancel
+                                        } else {
+                                            // This is the only button on the dialog.
+                                            R.string
+                                                .keyguard_affordance_enablement_dialog_dismiss_button
+                                        }
                                     ),
-                            style = ButtonStyle.Primary,
-                            onClicked = {
-                                actionIntent?.let { intent -> requestActivityStart(intent) }
-                            }
-                        ),
-                    ),
+                                style = ButtonStyle.Secondary,
+                            ),
+                        )
+
+                        if (actionText != null) {
+                            add(
+                                ButtonViewModel(
+                                    text = Text.Loaded(actionText),
+                                    style = ButtonStyle.Primary,
+                                    onClicked = {
+                                        actionIntent?.let { intent -> requestActivityStart(intent) }
+                                    }
+                                ),
+                            )
+                        }
+                    },
             )
     }
 
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 d51f411..3f10674 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
@@ -248,7 +248,7 @@
             val dialog = collectLastValue(underTest.dialog)
             val activityStartRequest = collectLastValue(underTest.activityStartRequests)
 
-            val enablementInstructions = listOf("instruction1", "instruction2")
+            val enablementExplanation = "enablementExplanation"
             val enablementActionText = "enablementActionText"
             val packageName = "packageName"
             val action = "action"
@@ -261,7 +261,7 @@
                         name = "disabled",
                         iconResourceId = 1,
                         isEnabled = false,
-                        enablementInstructions = enablementInstructions,
+                        enablementExplanation = enablementExplanation,
                         enablementActionText = enablementActionText,
                         enablementActionIntent = enablementActionIntent,
                     )
@@ -275,15 +275,14 @@
                 .isEqualTo(Icon.Loaded(FakeCustomizationProviderClient.ICON_1, null))
             assertThat(dialog()?.headline)
                 .isEqualTo(Text.Resource(R.string.keyguard_affordance_enablement_dialog_headline))
-            assertThat(dialog()?.message)
-                .isEqualTo(Text.Loaded(enablementInstructions.joinToString("\n")))
-            assertThat(dialog()?.buttons?.size).isEqualTo(1)
-            assertThat(dialog()?.buttons?.first()?.text)
-                .isEqualTo(Text.Loaded(enablementActionText))
+            assertThat(dialog()?.message).isEqualTo(Text.Loaded(enablementExplanation))
+            assertThat(dialog()?.buttons?.size).isEqualTo(2)
+            assertThat(dialog()?.buttons?.first()?.text).isEqualTo(Text.Resource(R.string.cancel))
+            assertThat(dialog()?.buttons?.get(1)?.text).isEqualTo(Text.Loaded(enablementActionText))
 
             // When the button is clicked, we expect an intent of the given enablement action
             // component name to be emitted.
-            dialog()?.buttons?.first()?.onClicked?.invoke()
+            dialog()?.buttons?.get(1)?.onClicked?.invoke()
             assertThat(activityStartRequest()?.`package`).isEqualTo(packageName)
             assertThat(activityStartRequest()?.action).isEqualTo(action)