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 androidx.activity.ComponentActivity 26 import androidx.lifecycle.DefaultLifecycleObserver 27 import androidx.lifecycle.LifecycleOwner 28 import androidx.lifecycle.ViewModelProvider 29 import com.android.customization.model.color.ColorCustomizationManager 30 import com.android.customization.model.color.ColorOptionsProvider.COLOR_SOURCE_PRESET 31 import com.android.customization.model.color.ThemedWallpaperColorResources 32 import com.android.customization.model.color.WallpaperColorResources 33 import com.android.customization.model.grid.GridOptionsManager 34 import com.android.customization.model.mode.DarkModeSnapshotRestorer 35 import com.android.customization.model.theme.OverlayManagerCompat 36 import com.android.customization.model.themedicon.ThemedIconSwitchProvider 37 import com.android.customization.model.themedicon.data.repository.ThemeIconRepository 38 import com.android.customization.model.themedicon.domain.interactor.ThemedIconInteractor 39 import com.android.customization.model.themedicon.domain.interactor.ThemedIconSnapshotRestorer 40 import com.android.customization.module.logging.ThemesUserEventLogger 41 import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor 42 import com.android.customization.picker.clock.domain.interactor.ClockPickerSnapshotRestorer 43 import com.android.customization.picker.clock.ui.view.ClockViewFactory 44 import com.android.customization.picker.clock.ui.view.ThemePickerClockViewFactory 45 import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel 46 import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel 47 import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor 48 import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer 49 import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel 50 import com.android.customization.picker.grid.data.repository.GridRepositoryImpl 51 import com.android.customization.picker.grid.domain.interactor.GridInteractor 52 import com.android.customization.picker.grid.domain.interactor.GridSnapshotRestorer 53 import com.android.customization.picker.grid.ui.viewmodel.GridScreenViewModel 54 import com.android.customization.picker.notifications.domain.interactor.NotificationsSnapshotRestorer 55 import com.android.customization.picker.notifications.ui.viewmodel.NotificationSectionViewModel 56 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor 57 import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordanceSnapshotRestorer 58 import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordancePickerViewModel 59 import com.android.customization.picker.settings.ui.viewmodel.ColorContrastSectionViewModel 60 import com.android.systemui.shared.clocks.ClockRegistry 61 import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository 62 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor 63 import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository 64 import com.android.systemui.shared.settings.data.repository.SystemSettingsRepository 65 import com.android.wallpaper.config.BaseFlags 66 import com.android.wallpaper.module.CustomizationSections 67 import com.android.wallpaper.module.FragmentFactory 68 import com.android.wallpaper.module.NetworkStatusNotifier 69 import com.android.wallpaper.module.PackageStatusNotifier 70 import com.android.wallpaper.module.PartnerProvider 71 import com.android.wallpaper.module.WallpaperPicker2Injector 72 import com.android.wallpaper.module.WallpaperPreferences 73 import com.android.wallpaper.module.WallpaperRefresher 74 import com.android.wallpaper.module.logging.UserEventLogger 75 import com.android.wallpaper.network.Requester 76 import com.android.wallpaper.picker.CustomizationPickerActivity 77 import com.android.wallpaper.picker.category.wrapper.WallpaperCategoryWrapper 78 import com.android.wallpaper.picker.customization.data.content.WallpaperClient 79 import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository 80 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor 81 import com.android.wallpaper.picker.di.modules.BackgroundDispatcher 82 import com.android.wallpaper.picker.di.modules.MainDispatcher 83 import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer 84 import com.android.wallpaper.system.UiModeManagerWrapper 85 import com.android.wallpaper.util.DisplayUtils 86 import dagger.Lazy 87 import javax.inject.Inject 88 import javax.inject.Singleton 89 import kotlinx.coroutines.CoroutineDispatcher 90 import kotlinx.coroutines.CoroutineScope 91 92 @Singleton 93 open class ThemePickerInjector 94 @Inject 95 constructor( 96 @MainDispatcher private val mainScope: CoroutineScope, 97 @BackgroundDispatcher private val bgScope: CoroutineScope, 98 @BackgroundDispatcher private val bgDispatcher: CoroutineDispatcher, 99 private val colorContrastSectionViewModelFactory: Lazy<ColorContrastSectionViewModel.Factory>, 100 private val keyguardQuickAffordancePickerInteractor: 101 Lazy<KeyguardQuickAffordancePickerInteractor>, 102 private val keyguardQuickAffordanceSnapshotRestorer: 103 Lazy<KeyguardQuickAffordanceSnapshotRestorer>, 104 private val themesUserEventLogger: Lazy<ThemesUserEventLogger>, 105 private val colorPickerInteractor: Lazy<ColorPickerInteractor>, 106 private val colorPickerSnapshotRestorer: Lazy<ColorPickerSnapshotRestorer>, 107 private val clockRegistry: Lazy<ClockRegistry>, 108 private val secureSettingsRepository: Lazy<SecureSettingsRepository>, 109 private val systemSettingsRepository: Lazy<SystemSettingsRepository>, 110 private val clockPickerInteractor: Lazy<ClockPickerInteractor>, 111 private val clockPickerSnapshotRestorer: Lazy<ClockPickerSnapshotRestorer>, 112 displayUtils: Lazy<DisplayUtils>, 113 requester: Lazy<Requester>, 114 networkStatusNotifier: Lazy<NetworkStatusNotifier>, 115 partnerProvider: Lazy<PartnerProvider>, 116 val uiModeManager: Lazy<UiModeManagerWrapper>, 117 userEventLogger: Lazy<UserEventLogger>, 118 injectedWallpaperClient: Lazy<WallpaperClient>, 119 private val injectedWallpaperInteractor: Lazy<WallpaperInteractor>, 120 prefs: Lazy<WallpaperPreferences>, 121 wallpaperColorsRepository: Lazy<WallpaperColorsRepository>, 122 defaultWallpaperCategoryWrapper: Lazy<WallpaperCategoryWrapper>, 123 packageNotifier: Lazy<PackageStatusNotifier>, 124 wallpaperRefresher: Lazy<WallpaperRefresher>, 125 ) : 126 WallpaperPicker2Injector( 127 mainScope, 128 displayUtils, 129 requester, 130 networkStatusNotifier, 131 partnerProvider, 132 uiModeManager, 133 userEventLogger, 134 injectedWallpaperClient, 135 injectedWallpaperInteractor, 136 prefs, 137 wallpaperColorsRepository, 138 defaultWallpaperCategoryWrapper, 139 packageNotifier, 140 wallpaperRefresher, 141 ), 142 CustomizationInjector { 143 private var customizationSections: CustomizationSections? = null 144 private var keyguardQuickAffordancePickerViewModelFactory: 145 KeyguardQuickAffordancePickerViewModel.Factory? = 146 null 147 private var fragmentFactory: FragmentFactory? = null 148 private var notificationsSnapshotRestorer: NotificationsSnapshotRestorer? = null 149 private var clockCarouselViewModelFactory: ClockCarouselViewModel.Factory? = null 150 private var clockViewFactory: ClockViewFactory? = null 151 private var notificationSettingsInteractor: NotificationSettingsInteractor? = null 152 private var notificationSectionViewModelFactory: NotificationSectionViewModel.Factory? = null 153 private var colorPickerViewModelFactory: ColorPickerViewModel.Factory? = null 154 private var colorCustomizationManager: ColorCustomizationManager? = null 155 private var darkModeSnapshotRestorer: DarkModeSnapshotRestorer? = null 156 private var themedIconSnapshotRestorer: ThemedIconSnapshotRestorer? = null 157 private var themedIconInteractor: ThemedIconInteractor? = null 158 private var clockSettingsViewModelFactory: ClockSettingsViewModel.Factory? = null 159 private var gridInteractor: GridInteractor? = null 160 private var gridSnapshotRestorer: GridSnapshotRestorer? = null 161 private var gridScreenViewModelFactory: GridScreenViewModel.Factory? = null 162 163 override fun getCustomizationSections(activity: ComponentActivity): CustomizationSections { 164 val appContext = activity.applicationContext 165 val clockViewFactory = getClockViewFactory(activity) 166 val resources = activity.resources 167 return customizationSections 168 ?: DefaultCustomizationSections( 169 getColorPickerViewModelFactory(appContext), 170 getKeyguardQuickAffordancePickerViewModelFactory(appContext), 171 colorContrastSectionViewModelFactory.get(), 172 getNotificationSectionViewModelFactory(appContext), 173 getFlags(), 174 getClockCarouselViewModelFactory( 175 interactor = clockPickerInteractor.get(), 176 clockViewFactory = clockViewFactory, 177 resources = resources, 178 ), 179 clockViewFactory, 180 getThemedIconSnapshotRestorer(appContext), 181 getThemedIconInteractor(), 182 getGridInteractor(appContext), 183 colorPickerInteractor.get(), 184 getUserEventLogger(), 185 ) 186 .also { customizationSections = it } 187 } 188 189 override fun getDeepLinkRedirectIntent(context: Context, uri: Uri): Intent { 190 val intent = Intent() 191 intent.setClass(context, CustomizationPickerActivity::class.java) 192 intent.data = uri 193 intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK 194 return intent 195 } 196 197 override fun getDownloadableIntentAction(): String? { 198 return null 199 } 200 201 @Synchronized 202 override fun getUserEventLogger(): ThemesUserEventLogger { 203 return themesUserEventLogger.get() 204 } 205 206 override fun getFragmentFactory(): FragmentFactory? { 207 return fragmentFactory ?: ThemePickerFragmentFactory().also { fragmentFactory } 208 } 209 210 override fun getSnapshotRestorers(context: Context): Map<Int, SnapshotRestorer> { 211 return super<WallpaperPicker2Injector>.getSnapshotRestorers(context).toMutableMap().apply { 212 this[KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER] = 213 keyguardQuickAffordanceSnapshotRestorer.get() 214 // TODO(b/285047815): Enable after adding wallpaper id for default static wallpaper 215 if (getFlags().isWallpaperRestorerEnabled()) { 216 this[KEY_WALLPAPER_SNAPSHOT_RESTORER] = getWallpaperSnapshotRestorer(context) 217 } 218 this[KEY_NOTIFICATIONS_SNAPSHOT_RESTORER] = getNotificationsSnapshotRestorer(context) 219 this[KEY_DARK_MODE_SNAPSHOT_RESTORER] = getDarkModeSnapshotRestorer(context) 220 this[KEY_THEMED_ICON_SNAPSHOT_RESTORER] = getThemedIconSnapshotRestorer(context) 221 this[KEY_APP_GRID_SNAPSHOT_RESTORER] = getGridSnapshotRestorer(context) 222 this[KEY_COLOR_PICKER_SNAPSHOT_RESTORER] = colorPickerSnapshotRestorer.get() 223 this[KEY_CLOCKS_SNAPSHOT_RESTORER] = clockPickerSnapshotRestorer.get() 224 } 225 } 226 227 override fun getCustomizationPreferences(context: Context): CustomizationPreferences { 228 return getPreferences(context) as CustomizationPreferences 229 } 230 231 override fun getWallpaperInteractor(context: Context): WallpaperInteractor { 232 return injectedWallpaperInteractor.get() 233 } 234 235 override fun getKeyguardQuickAffordancePickerInteractor( 236 context: Context 237 ): KeyguardQuickAffordancePickerInteractor { 238 return keyguardQuickAffordancePickerInteractor.get() 239 } 240 241 fun getKeyguardQuickAffordancePickerViewModelFactory( 242 context: Context 243 ): KeyguardQuickAffordancePickerViewModel.Factory { 244 return keyguardQuickAffordancePickerViewModelFactory 245 ?: KeyguardQuickAffordancePickerViewModel.Factory( 246 context.applicationContext, 247 getKeyguardQuickAffordancePickerInteractor(context), 248 getWallpaperInteractor(context), 249 getCurrentWallpaperInfoFactory(context), 250 getUserEventLogger(), 251 ) 252 .also { keyguardQuickAffordancePickerViewModelFactory = it } 253 } 254 255 fun getNotificationSectionViewModelFactory( 256 context: Context 257 ): NotificationSectionViewModel.Factory { 258 return notificationSectionViewModelFactory 259 ?: NotificationSectionViewModel.Factory( 260 interactor = getNotificationsInteractor(context), 261 logger = getUserEventLogger(), 262 ) 263 .also { notificationSectionViewModelFactory = it } 264 } 265 266 private fun getNotificationsInteractor(context: Context): NotificationSettingsInteractor { 267 return notificationSettingsInteractor 268 ?: NotificationSettingsInteractor( 269 repository = 270 NotificationSettingsRepository( 271 backgroundScope = bgScope, 272 backgroundDispatcher = bgDispatcher, 273 secureSettingsRepository = secureSettingsRepository.get(), 274 systemSettingsRepository = systemSettingsRepository.get(), 275 ) 276 ) 277 .also { notificationSettingsInteractor = it } 278 } 279 280 private fun getNotificationsSnapshotRestorer(context: Context): NotificationsSnapshotRestorer { 281 return notificationsSnapshotRestorer 282 ?: NotificationsSnapshotRestorer( 283 interactor = getNotificationsInteractor(context = context), 284 backgroundScope = bgScope, 285 ) 286 .also { notificationsSnapshotRestorer = it } 287 } 288 289 override fun getClockCarouselViewModelFactory( 290 interactor: ClockPickerInteractor, 291 clockViewFactory: ClockViewFactory, 292 resources: Resources, 293 ): ClockCarouselViewModel.Factory { 294 return clockCarouselViewModelFactory 295 ?: ClockCarouselViewModel.Factory( 296 interactor, 297 bgDispatcher, 298 clockViewFactory, 299 resources, 300 getUserEventLogger(), 301 ) 302 .also { clockCarouselViewModelFactory = it } 303 } 304 305 override fun getClockViewFactory(activity: ComponentActivity): ClockViewFactory { 306 return clockViewFactory 307 ?: ThemePickerClockViewFactory( 308 activity, 309 WallpaperManager.getInstance(activity.applicationContext), 310 clockRegistry.get(), 311 ) 312 .also { 313 clockViewFactory = it 314 activity.lifecycle.addObserver( 315 object : DefaultLifecycleObserver { 316 override fun onDestroy(owner: LifecycleOwner) { 317 super.onDestroy(owner) 318 if ((owner as Activity).isChangingConfigurations()) return 319 clockViewFactory?.onDestroy() 320 } 321 } 322 ) 323 } 324 } 325 326 override fun getWallpaperColorResources( 327 wallpaperColors: WallpaperColors, 328 context: Context, 329 ): WallpaperColorResources { 330 return ThemedWallpaperColorResources(wallpaperColors, secureSettingsRepository.get()) 331 } 332 333 override fun getColorPickerViewModelFactory(context: Context): ColorPickerViewModel.Factory { 334 return colorPickerViewModelFactory 335 ?: ColorPickerViewModel.Factory( 336 context.applicationContext, 337 colorPickerInteractor.get(), 338 getUserEventLogger(), 339 ) 340 .also { colorPickerViewModelFactory = it } 341 } 342 343 private fun getColorCustomizationManager(context: Context): ColorCustomizationManager { 344 return colorCustomizationManager 345 ?: ColorCustomizationManager.getInstance(context, OverlayManagerCompat(context)).also { 346 colorCustomizationManager = it 347 } 348 } 349 350 fun getDarkModeSnapshotRestorer(context: Context): DarkModeSnapshotRestorer { 351 val appContext = context.applicationContext 352 return darkModeSnapshotRestorer 353 ?: DarkModeSnapshotRestorer( 354 context = appContext, 355 manager = uiModeManager.get(), 356 backgroundDispatcher = bgDispatcher, 357 ) 358 .also { darkModeSnapshotRestorer = it } 359 } 360 361 protected fun getThemedIconSnapshotRestorer(context: Context): ThemedIconSnapshotRestorer { 362 val optionProvider = ThemedIconSwitchProvider.getInstance(context) 363 return themedIconSnapshotRestorer 364 ?: ThemedIconSnapshotRestorer( 365 isActivated = { optionProvider.isThemedIconEnabled }, 366 setActivated = { isActivated -> 367 optionProvider.isThemedIconEnabled = isActivated 368 }, 369 interactor = getThemedIconInteractor(), 370 ) 371 .also { themedIconSnapshotRestorer = it } 372 } 373 374 protected fun getThemedIconInteractor(): ThemedIconInteractor { 375 return themedIconInteractor 376 ?: ThemedIconInteractor(repository = ThemeIconRepository()).also { 377 themedIconInteractor = it 378 } 379 } 380 381 override fun getClockSettingsViewModelFactory( 382 context: Context, 383 wallpaperColorsRepository: WallpaperColorsRepository, 384 ): ClockSettingsViewModel.Factory { 385 return clockSettingsViewModelFactory 386 ?: ClockSettingsViewModel.Factory( 387 context.applicationContext, 388 clockPickerInteractor.get(), 389 colorPickerInteractor.get(), 390 getUserEventLogger(), 391 ) { clockId -> 392 clockId?.let { clockPickerInteractor.get().isReactiveToTone(it) } ?: false 393 } 394 .also { clockSettingsViewModelFactory = it } 395 } 396 397 fun getGridScreenViewModelFactory(context: Context): ViewModelProvider.Factory { 398 return gridScreenViewModelFactory 399 ?: GridScreenViewModel.Factory( 400 context = context, 401 interactor = getGridInteractor(context), 402 ) 403 .also { gridScreenViewModelFactory = it } 404 } 405 406 fun getGridInteractor(context: Context): GridInteractor { 407 val appContext = context.applicationContext 408 return gridInteractor 409 ?: GridInteractor( 410 applicationScope = getApplicationCoroutineScope(), 411 repository = 412 GridRepositoryImpl( 413 applicationScope = getApplicationCoroutineScope(), 414 manager = GridOptionsManager.getInstance(context), 415 backgroundDispatcher = bgDispatcher, 416 isGridApplyButtonEnabled = 417 BaseFlags.get().isGridApplyButtonEnabled(appContext), 418 ), 419 snapshotRestorer = { getGridSnapshotRestorer(appContext) }, 420 ) 421 .also { gridInteractor = it } 422 } 423 424 private fun getGridSnapshotRestorer(context: Context): GridSnapshotRestorer { 425 return gridSnapshotRestorer 426 ?: GridSnapshotRestorer(interactor = getGridInteractor(context)).also { 427 gridSnapshotRestorer = it 428 } 429 } 430 431 override fun isCurrentSelectedColorPreset(context: Context): Boolean { 432 val colorManager = 433 ColorCustomizationManager.getInstance(context, OverlayManagerCompat(context)) 434 return COLOR_SOURCE_PRESET == colorManager.currentColorSource 435 } 436 437 companion object { 438 @JvmStatic 439 private val KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER = 440 WallpaperPicker2Injector.MIN_SNAPSHOT_RESTORER_KEY 441 @JvmStatic 442 private val KEY_WALLPAPER_SNAPSHOT_RESTORER = KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER + 1 443 @JvmStatic 444 private val KEY_NOTIFICATIONS_SNAPSHOT_RESTORER = KEY_WALLPAPER_SNAPSHOT_RESTORER + 1 445 @JvmStatic 446 private val KEY_DARK_MODE_SNAPSHOT_RESTORER = KEY_NOTIFICATIONS_SNAPSHOT_RESTORER + 1 447 @JvmStatic 448 private val KEY_THEMED_ICON_SNAPSHOT_RESTORER = KEY_DARK_MODE_SNAPSHOT_RESTORER + 1 449 @JvmStatic 450 private val KEY_APP_GRID_SNAPSHOT_RESTORER = KEY_THEMED_ICON_SNAPSHOT_RESTORER + 1 451 @JvmStatic 452 private val KEY_COLOR_PICKER_SNAPSHOT_RESTORER = KEY_APP_GRID_SNAPSHOT_RESTORER + 1 453 @JvmStatic private val KEY_CLOCKS_SNAPSHOT_RESTORER = KEY_COLOR_PICKER_SNAPSHOT_RESTORER + 1 454 455 /** 456 * When this injector is overridden, this is the minimal value that should be used by 457 * restorers returns in [getSnapshotRestorers]. 458 * 459 * It should always be greater than the biggest restorer key. 460 */ 461 @JvmStatic protected val MIN_SNAPSHOT_RESTORER_KEY = KEY_CLOCKS_SNAPSHOT_RESTORER + 1 462 } 463 } 464