1 /*
<lambda>null2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.customization.module
17 
18 import android.app.Activity
19 import android.app.WallpaperColors
20 import android.app.WallpaperManager
21 import android.content.Context
22 import android.content.Intent
23 import android.content.res.Resources
24 import android.net.Uri
25 import android.text.TextUtils
26 import androidx.activity.ComponentActivity
27 import androidx.lifecycle.DefaultLifecycleObserver
28 import androidx.lifecycle.LifecycleOwner
29 import androidx.lifecycle.ViewModelProvider
30 import com.android.customization.model.color.ColorCustomizationManager
31 import com.android.customization.model.color.ColorOptionsProvider.COLOR_SOURCE_PRESET
32 import com.android.customization.model.color.ThemedWallpaperColorResources
33 import com.android.customization.model.color.WallpaperColorResources
34 import com.android.customization.model.grid.GridOptionsManager
35 import com.android.customization.model.mode.DarkModeSnapshotRestorer
36 import com.android.customization.model.theme.OverlayManagerCompat
37 import com.android.customization.model.themedicon.ThemedIconSwitchProvider
38 import com.android.customization.model.themedicon.data.repository.ThemeIconRepository
39 import com.android.customization.model.themedicon.domain.interactor.ThemedIconInteractor
40 import com.android.customization.model.themedicon.domain.interactor.ThemedIconSnapshotRestorer
41 import com.android.customization.module.logging.ThemesUserEventLogger
42 import com.android.customization.picker.clock.data.repository.ClockPickerRepositoryImpl
43 import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
44 import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
45 import com.android.customization.picker.clock.domain.interactor.ClockPickerSnapshotRestorer
46 import com.android.customization.picker.clock.ui.view.ClockViewFactory
47 import com.android.customization.picker.clock.ui.view.ClockViewFactoryImpl
48 import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
49 import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
50 import com.android.customization.picker.color.data.repository.ColorPickerRepositoryImpl
51 import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
52 import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer
53 import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel
54 import com.android.customization.picker.grid.data.repository.GridRepositoryImpl
55 import com.android.customization.picker.grid.domain.interactor.GridInteractor
56 import com.android.customization.picker.grid.domain.interactor.GridSnapshotRestorer
57 import com.android.customization.picker.grid.ui.viewmodel.GridScreenViewModel
58 import com.android.customization.picker.notifications.domain.interactor.NotificationsSnapshotRestorer
59 import com.android.customization.picker.notifications.ui.viewmodel.NotificationSectionViewModel
60 import com.android.customization.picker.quickaffordance.data.repository.KeyguardQuickAffordancePickerRepository
61 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
62 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordanceSnapshotRestorer
63 import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordancePickerViewModel
64 import com.android.customization.picker.settings.ui.viewmodel.ColorContrastSectionViewModel
65 import com.android.systemui.shared.clocks.ClockRegistry
66 import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
67 import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
68 import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
69 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
70 import com.android.wallpaper.config.BaseFlags
71 import com.android.wallpaper.module.CustomizationSections
72 import com.android.wallpaper.module.FragmentFactory
73 import com.android.wallpaper.module.WallpaperPicker2Injector
74 import com.android.wallpaper.picker.CustomizationPickerActivity
75 import com.android.wallpaper.picker.customization.data.content.WallpaperClientImpl
76 import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository
77 import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository
78 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor
79 import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
80 import com.android.wallpaper.picker.di.modules.MainDispatcher
81 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
82 import com.android.wallpaper.util.ScreenSizeCalculator
83 import dagger.Lazy
84 import javax.inject.Inject
85 import javax.inject.Singleton
86 import kotlinx.coroutines.CoroutineDispatcher
87 import kotlinx.coroutines.CoroutineScope
88 
89 @Singleton
90 open class ThemePickerInjector
91 @Inject
92 constructor(
93     @MainDispatcher private val mainScope: CoroutineScope,
94     @MainDispatcher private val mainDispatcher: CoroutineDispatcher,
95     @BackgroundDispatcher private val bgScope: CoroutineScope,
96     @BackgroundDispatcher private val bgDispatcher: CoroutineDispatcher,
97 ) : WallpaperPicker2Injector(mainScope, bgDispatcher), CustomizationInjector {
98     private var customizationSections: CustomizationSections? = null
99     private var wallpaperInteractor: WallpaperInteractor? = null
100     private var keyguardQuickAffordancePickerInteractor: KeyguardQuickAffordancePickerInteractor? =
101         null
102     private var keyguardQuickAffordancePickerViewModelFactory:
103         KeyguardQuickAffordancePickerViewModel.Factory? =
104         null
105     private var customizationProviderClient: CustomizationProviderClient? = null
106     private var fragmentFactory: FragmentFactory? = null
107     private var keyguardQuickAffordanceSnapshotRestorer: KeyguardQuickAffordanceSnapshotRestorer? =
108         null
109     private var notificationsSnapshotRestorer: NotificationsSnapshotRestorer? = null
110     private var clockPickerInteractor: ClockPickerInteractor? = null
111     private var clockCarouselViewModelFactory: ClockCarouselViewModel.Factory? = null
112     private var clockViewFactory: ClockViewFactory? = null
113     private var clockPickerSnapshotRestorer: ClockPickerSnapshotRestorer? = null
114     private var notificationSettingsInteractor: NotificationSettingsInteractor? = null
115     private var notificationSectionViewModelFactory: NotificationSectionViewModel.Factory? = null
116     private var colorPickerInteractor: ColorPickerInteractor? = null
117     private var colorPickerViewModelFactory: ColorPickerViewModel.Factory? = null
118     private var colorPickerSnapshotRestorer: ColorPickerSnapshotRestorer? = null
119     private var colorCustomizationManager: ColorCustomizationManager? = null
120     private var darkModeSnapshotRestorer: DarkModeSnapshotRestorer? = null
121     private var themedIconSnapshotRestorer: ThemedIconSnapshotRestorer? = null
122     private var themedIconInteractor: ThemedIconInteractor? = null
123     private var clockSettingsViewModelFactory: ClockSettingsViewModel.Factory? = null
124     private var gridInteractor: GridInteractor? = null
125     private var gridSnapshotRestorer: GridSnapshotRestorer? = null
126     private var gridScreenViewModelFactory: GridScreenViewModel.Factory? = null
127     private var clockRegistryProvider: ClockRegistryProvider? = null
128 
129     // Injected objects, sorted by type
130     @Inject
131     lateinit var colorContrastSectionViewModelFactory: Lazy<ColorContrastSectionViewModel.Factory>
132     @Inject lateinit var themesUserEventLogger: Lazy<ThemesUserEventLogger>
133 
134     override fun getCustomizationSections(activity: ComponentActivity): CustomizationSections {
135         val appContext = activity.applicationContext
136         val clockViewFactory = getClockViewFactory(activity)
137         val resources = activity.resources
138         return customizationSections
139             ?: DefaultCustomizationSections(
140                     getColorPickerViewModelFactory(
141                         context = appContext,
142                         wallpaperColorsRepository = getWallpaperColorsRepository(),
143                     ),
144                     getKeyguardQuickAffordancePickerViewModelFactory(appContext),
145                     colorContrastSectionViewModelFactory.get(),
146                     getNotificationSectionViewModelFactory(appContext),
147                     getFlags(),
148                     getClockCarouselViewModelFactory(
149                         interactor = getClockPickerInteractor(appContext),
150                         clockViewFactory = clockViewFactory,
151                         resources = resources,
152                     ),
153                     clockViewFactory,
154                     getThemedIconSnapshotRestorer(appContext),
155                     getThemedIconInteractor(),
156                     getColorPickerInteractor(appContext, getWallpaperColorsRepository()),
157                     getUserEventLogger(),
158                 )
159                 .also { customizationSections = it }
160     }
161 
162     override fun getDeepLinkRedirectIntent(context: Context, uri: Uri): Intent {
163         val intent = Intent()
164         intent.setClass(context, CustomizationPickerActivity::class.java)
165         intent.data = uri
166         intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
167         return intent
168     }
169 
170     override fun getDownloadableIntentAction(): String? {
171         return null
172     }
173 
174     @Synchronized
175     override fun getUserEventLogger(): ThemesUserEventLogger {
176         return themesUserEventLogger.get()
177     }
178 
179     override fun getFragmentFactory(): FragmentFactory? {
180         return fragmentFactory ?: ThemePickerFragmentFactory().also { fragmentFactory }
181     }
182 
183     override fun getSnapshotRestorers(
184         context: Context,
185     ): Map<Int, SnapshotRestorer> {
186         return super<WallpaperPicker2Injector>.getSnapshotRestorers(context).toMutableMap().apply {
187             this[KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER] =
188                 getKeyguardQuickAffordanceSnapshotRestorer(context)
189             // TODO(b/285047815): Enable after adding wallpaper id for default static wallpaper
190             if (getFlags().isWallpaperRestorerEnabled()) {
191                 this[KEY_WALLPAPER_SNAPSHOT_RESTORER] = getWallpaperSnapshotRestorer(context)
192             }
193             this[KEY_NOTIFICATIONS_SNAPSHOT_RESTORER] = getNotificationsSnapshotRestorer(context)
194             this[KEY_DARK_MODE_SNAPSHOT_RESTORER] = getDarkModeSnapshotRestorer(context)
195             this[KEY_THEMED_ICON_SNAPSHOT_RESTORER] = getThemedIconSnapshotRestorer(context)
196             this[KEY_APP_GRID_SNAPSHOT_RESTORER] = getGridSnapshotRestorer(context)
197             this[KEY_COLOR_PICKER_SNAPSHOT_RESTORER] =
198                 getColorPickerSnapshotRestorer(context, getWallpaperColorsRepository())
199             this[KEY_CLOCKS_SNAPSHOT_RESTORER] = getClockPickerSnapshotRestorer(context)
200         }
201     }
202 
203     override fun getCustomizationPreferences(context: Context): CustomizationPreferences {
204         return getPreferences(context) as CustomizationPreferences
205     }
206 
207     override fun getWallpaperInteractor(context: Context): WallpaperInteractor {
208         if (getFlags().isMultiCropEnabled()) {
209             return injectedWallpaperInteractor.get()
210         }
211 
212         val appContext = context.applicationContext
213         return wallpaperInteractor
214             ?: WallpaperInteractor(
215                     repository =
216                         WallpaperRepository(
217                             scope = getApplicationCoroutineScope(),
218                             client =
219                                 WallpaperClientImpl(
220                                     context = appContext,
221                                     wallpaperManager = WallpaperManager.getInstance(appContext),
222                                     wallpaperPreferences = getPreferences(appContext),
223                                 ),
224                             wallpaperPreferences = getPreferences(context = appContext),
225                             backgroundDispatcher = bgDispatcher,
226                         ),
227                     shouldHandleReload = {
228                         TextUtils.equals(
229                             getColorCustomizationManager(appContext).currentColorSource,
230                             COLOR_SOURCE_PRESET,
231                         )
232                     }
233                 )
234                 .also { wallpaperInteractor = it }
235     }
236 
237     override fun getKeyguardQuickAffordancePickerInteractor(
238         context: Context
239     ): KeyguardQuickAffordancePickerInteractor {
240         return keyguardQuickAffordancePickerInteractor
241             ?: getKeyguardQuickAffordancePickerInteractorImpl(context).also {
242                 keyguardQuickAffordancePickerInteractor = it
243             }
244     }
245 
246     fun getKeyguardQuickAffordancePickerViewModelFactory(
247         context: Context
248     ): KeyguardQuickAffordancePickerViewModel.Factory {
249         return keyguardQuickAffordancePickerViewModelFactory
250             ?: KeyguardQuickAffordancePickerViewModel.Factory(
251                     context.applicationContext,
252                     getKeyguardQuickAffordancePickerInteractor(context),
253                     getWallpaperInteractor(context),
254                     getCurrentWallpaperInfoFactory(context),
255                     getUserEventLogger(),
256                 )
257                 .also { keyguardQuickAffordancePickerViewModelFactory = it }
258     }
259 
260     private fun getKeyguardQuickAffordancePickerInteractorImpl(
261         context: Context
262     ): KeyguardQuickAffordancePickerInteractor {
263         val client = getKeyguardQuickAffordancePickerProviderClient(context)
264         val appContext = context.applicationContext
265         return KeyguardQuickAffordancePickerInteractor(
266             KeyguardQuickAffordancePickerRepository(client, getApplicationCoroutineScope()),
267             client
268         ) {
269             getKeyguardQuickAffordanceSnapshotRestorer(appContext)
270         }
271     }
272 
273     private fun getKeyguardQuickAffordancePickerProviderClient(
274         context: Context
275     ): CustomizationProviderClient {
276         return customizationProviderClient
277             ?: CustomizationProviderClientImpl(context.applicationContext, bgDispatcher).also {
278                 customizationProviderClient = it
279             }
280     }
281 
282     private fun getKeyguardQuickAffordanceSnapshotRestorer(
283         context: Context
284     ): KeyguardQuickAffordanceSnapshotRestorer {
285         return keyguardQuickAffordanceSnapshotRestorer
286             ?: KeyguardQuickAffordanceSnapshotRestorer(
287                     getKeyguardQuickAffordancePickerInteractor(context),
288                     getKeyguardQuickAffordancePickerProviderClient(context)
289                 )
290                 .also { keyguardQuickAffordanceSnapshotRestorer = it }
291     }
292 
293     fun getNotificationSectionViewModelFactory(
294         context: Context,
295     ): NotificationSectionViewModel.Factory {
296         return notificationSectionViewModelFactory
297             ?: NotificationSectionViewModel.Factory(
298                     interactor = getNotificationsInteractor(context),
299                     logger = getUserEventLogger(),
300                 )
301                 .also { notificationSectionViewModelFactory = it }
302     }
303 
304     private fun getNotificationsInteractor(
305         context: Context,
306     ): NotificationSettingsInteractor {
307         return notificationSettingsInteractor
308             ?: NotificationSettingsInteractor(
309                     repository =
310                         NotificationSettingsRepository(
311                             scope = getApplicationCoroutineScope(),
312                             backgroundDispatcher = bgDispatcher,
313                             secureSettingsRepository = getSecureSettingsRepository(context),
314                         ),
315                 )
316                 .also { notificationSettingsInteractor = it }
317     }
318 
319     private fun getNotificationsSnapshotRestorer(context: Context): NotificationsSnapshotRestorer {
320         return notificationsSnapshotRestorer
321             ?: NotificationsSnapshotRestorer(
322                     interactor =
323                         getNotificationsInteractor(
324                             context = context,
325                         ),
326                     backgroundScope = bgScope,
327                 )
328                 .also { notificationsSnapshotRestorer = it }
329     }
330 
331     override fun getClockRegistry(context: Context): ClockRegistry {
332         return (clockRegistryProvider
333                 ?: ClockRegistryProvider(
334                         context = context.applicationContext,
335                         coroutineScope = getApplicationCoroutineScope(),
336                         mainDispatcher = mainDispatcher,
337                         backgroundDispatcher = bgDispatcher,
338                     )
339                     .also { clockRegistryProvider = it })
340             .get()
341     }
342 
343     override fun getClockPickerInteractor(
344         context: Context,
345     ): ClockPickerInteractor {
346         val appContext = context.applicationContext
347         return clockPickerInteractor
348             ?: ClockPickerInteractor(
349                     repository =
350                         ClockPickerRepositoryImpl(
351                             secureSettingsRepository = getSecureSettingsRepository(appContext),
352                             registry = getClockRegistry(appContext),
353                             scope = getApplicationCoroutineScope(),
354                             mainDispatcher = mainDispatcher,
355                         ),
356                     snapshotRestorer = { getClockPickerSnapshotRestorer(appContext) },
357                 )
358                 .also { clockPickerInteractor = it }
359     }
360 
361     override fun getClockCarouselViewModelFactory(
362         interactor: ClockPickerInteractor,
363         clockViewFactory: ClockViewFactory,
364         resources: Resources,
365     ): ClockCarouselViewModel.Factory {
366         return clockCarouselViewModelFactory
367             ?: ClockCarouselViewModel.Factory(
368                     interactor,
369                     bgDispatcher,
370                     clockViewFactory,
371                     resources,
372                     getUserEventLogger(),
373                 )
374                 .also { clockCarouselViewModelFactory = it }
375     }
376 
377     override fun getClockViewFactory(activity: ComponentActivity): ClockViewFactory {
378         return clockViewFactory
379             ?: ClockViewFactoryImpl(
380                     activity.applicationContext,
381                     ScreenSizeCalculator.getInstance()
382                         .getScreenSize(activity.windowManager.defaultDisplay),
383                     WallpaperManager.getInstance(activity.applicationContext),
384                     getClockRegistry(activity.applicationContext),
385                 )
386                 .also {
387                     clockViewFactory = it
388                     activity.lifecycle.addObserver(
389                         object : DefaultLifecycleObserver {
390                             override fun onDestroy(owner: LifecycleOwner) {
391                                 super.onDestroy(owner)
392                                 if ((owner as Activity).isChangingConfigurations()) return
393                                 clockViewFactory?.onDestroy()
394                             }
395                         }
396                     )
397                 }
398     }
399 
400     private fun getClockPickerSnapshotRestorer(
401         context: Context,
402     ): ClockPickerSnapshotRestorer {
403         return clockPickerSnapshotRestorer
404             ?: ClockPickerSnapshotRestorer(getClockPickerInteractor(context)).also {
405                 clockPickerSnapshotRestorer = it
406             }
407     }
408 
409     override fun getWallpaperColorResources(
410         wallpaperColors: WallpaperColors,
411         context: Context
412     ): WallpaperColorResources {
413         return ThemedWallpaperColorResources(wallpaperColors, getSecureSettingsRepository(context))
414     }
415 
416     override fun getColorPickerInteractor(
417         context: Context,
418         wallpaperColorsRepository: WallpaperColorsRepository,
419     ): ColorPickerInteractor {
420         val appContext = context.applicationContext
421         return colorPickerInteractor
422             ?: ColorPickerInteractor(
423                     repository =
424                         ColorPickerRepositoryImpl(
425                             wallpaperColorsRepository,
426                             getColorCustomizationManager(appContext)
427                         ),
428                     snapshotRestorer = {
429                         getColorPickerSnapshotRestorer(appContext, wallpaperColorsRepository)
430                     }
431                 )
432                 .also { colorPickerInteractor = it }
433     }
434 
435     override fun getColorPickerViewModelFactory(
436         context: Context,
437         wallpaperColorsRepository: WallpaperColorsRepository,
438     ): ColorPickerViewModel.Factory {
439         return colorPickerViewModelFactory
440             ?: ColorPickerViewModel.Factory(
441                     context.applicationContext,
442                     getColorPickerInteractor(context, wallpaperColorsRepository),
443                     getUserEventLogger(),
444                 )
445                 .also { colorPickerViewModelFactory = it }
446     }
447 
448     private fun getColorPickerSnapshotRestorer(
449         context: Context,
450         wallpaperColorsRepository: WallpaperColorsRepository,
451     ): ColorPickerSnapshotRestorer {
452         return colorPickerSnapshotRestorer
453             ?: ColorPickerSnapshotRestorer(
454                     getColorPickerInteractor(context, wallpaperColorsRepository)
455                 )
456                 .also { colorPickerSnapshotRestorer = it }
457     }
458 
459     private fun getColorCustomizationManager(context: Context): ColorCustomizationManager {
460         return colorCustomizationManager
461             ?: ColorCustomizationManager.getInstance(context, OverlayManagerCompat(context)).also {
462                 colorCustomizationManager = it
463             }
464     }
465 
466     fun getDarkModeSnapshotRestorer(
467         context: Context,
468     ): DarkModeSnapshotRestorer {
469         val appContext = context.applicationContext
470         return darkModeSnapshotRestorer
471             ?: DarkModeSnapshotRestorer(
472                     context = appContext,
473                     manager = uiModeManager.get(),
474                     backgroundDispatcher = bgDispatcher,
475                 )
476                 .also { darkModeSnapshotRestorer = it }
477     }
478 
479     protected fun getThemedIconSnapshotRestorer(
480         context: Context,
481     ): ThemedIconSnapshotRestorer {
482         val optionProvider = ThemedIconSwitchProvider.getInstance(context)
483         return themedIconSnapshotRestorer
484             ?: ThemedIconSnapshotRestorer(
485                     isActivated = { optionProvider.isThemedIconEnabled },
486                     setActivated = { isActivated ->
487                         optionProvider.isThemedIconEnabled = isActivated
488                     },
489                     interactor = getThemedIconInteractor(),
490                 )
491                 .also { themedIconSnapshotRestorer = it }
492     }
493 
494     protected fun getThemedIconInteractor(): ThemedIconInteractor {
495         return themedIconInteractor
496             ?: ThemedIconInteractor(
497                     repository = ThemeIconRepository(),
498                 )
499                 .also { themedIconInteractor = it }
500     }
501 
502     override fun getClockSettingsViewModelFactory(
503         context: Context,
504         wallpaperColorsRepository: WallpaperColorsRepository,
505         clockViewFactory: ClockViewFactory,
506     ): ClockSettingsViewModel.Factory {
507         return clockSettingsViewModelFactory
508             ?: ClockSettingsViewModel.Factory(
509                     context.applicationContext,
510                     getClockPickerInteractor(context),
511                     getColorPickerInteractor(
512                         context,
513                         wallpaperColorsRepository,
514                     ),
515                     getUserEventLogger(),
516                 ) { clockId ->
517                     clockId?.let { clockViewFactory.getController(clockId).config.isReactiveToTone }
518                         ?: false
519                 }
520                 .also { clockSettingsViewModelFactory = it }
521     }
522 
523     fun getGridScreenViewModelFactory(
524         context: Context,
525     ): ViewModelProvider.Factory {
526         return gridScreenViewModelFactory
527             ?: GridScreenViewModel.Factory(
528                     context = context,
529                     interactor = getGridInteractor(context),
530                 )
531                 .also { gridScreenViewModelFactory = it }
532     }
533 
534     fun getGridInteractor(context: Context): GridInteractor {
535         val appContext = context.applicationContext
536         return gridInteractor
537             ?: GridInteractor(
538                     applicationScope = getApplicationCoroutineScope(),
539                     repository =
540                         GridRepositoryImpl(
541                             applicationScope = getApplicationCoroutineScope(),
542                             manager = GridOptionsManager.getInstance(context),
543                             backgroundDispatcher = bgDispatcher,
544                             isGridApplyButtonEnabled =
545                                 BaseFlags.get().isGridApplyButtonEnabled(appContext),
546                         ),
547                     snapshotRestorer = { getGridSnapshotRestorer(appContext) },
548                 )
549                 .also { gridInteractor = it }
550     }
551 
552     private fun getGridSnapshotRestorer(
553         context: Context,
554     ): GridSnapshotRestorer {
555         return gridSnapshotRestorer
556             ?: GridSnapshotRestorer(
557                     interactor = getGridInteractor(context),
558                 )
559                 .also { gridSnapshotRestorer = it }
560     }
561 
562     override fun isCurrentSelectedColorPreset(context: Context): Boolean {
563         val colorManager =
564             ColorCustomizationManager.getInstance(context, OverlayManagerCompat(context))
565         return COLOR_SOURCE_PRESET == colorManager.currentColorSource
566     }
567 
568     companion object {
569         @JvmStatic
570         private val KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER =
571             WallpaperPicker2Injector.MIN_SNAPSHOT_RESTORER_KEY
572         @JvmStatic
573         private val KEY_WALLPAPER_SNAPSHOT_RESTORER = KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER + 1
574         @JvmStatic
575         private val KEY_NOTIFICATIONS_SNAPSHOT_RESTORER = KEY_WALLPAPER_SNAPSHOT_RESTORER + 1
576         @JvmStatic
577         private val KEY_DARK_MODE_SNAPSHOT_RESTORER = KEY_NOTIFICATIONS_SNAPSHOT_RESTORER + 1
578         @JvmStatic
579         private val KEY_THEMED_ICON_SNAPSHOT_RESTORER = KEY_DARK_MODE_SNAPSHOT_RESTORER + 1
580         @JvmStatic
581         private val KEY_APP_GRID_SNAPSHOT_RESTORER = KEY_THEMED_ICON_SNAPSHOT_RESTORER + 1
582         @JvmStatic
583         private val KEY_COLOR_PICKER_SNAPSHOT_RESTORER = KEY_APP_GRID_SNAPSHOT_RESTORER + 1
584         @JvmStatic private val KEY_CLOCKS_SNAPSHOT_RESTORER = KEY_COLOR_PICKER_SNAPSHOT_RESTORER + 1
585 
586         /**
587          * When this injector is overridden, this is the minimal value that should be used by
588          * restorers returns in [getSnapshotRestorers].
589          *
590          * It should always be greater than the biggest restorer key.
591          */
592         @JvmStatic protected val MIN_SNAPSHOT_RESTORER_KEY = KEY_CLOCKS_SNAPSHOT_RESTORER + 1
593     }
594 }
595