1 /* <lambda>null2 * Copyright (C) 2023 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 */ 17 package com.android.customization.picker.color.data.repository 18 19 import android.util.Log 20 import com.android.customization.model.CustomizationManager 21 import com.android.customization.model.color.ColorCustomizationManager 22 import com.android.customization.model.color.ColorOption 23 import com.android.customization.model.color.ColorOptionImpl 24 import com.android.customization.picker.color.shared.model.ColorOptionModel 25 import com.android.customization.picker.color.shared.model.ColorType 26 import com.android.systemui.monet.Style 27 import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository 28 import com.android.wallpaper.picker.customization.shared.model.WallpaperColorsModel 29 import kotlinx.coroutines.flow.Flow 30 import kotlinx.coroutines.flow.MutableStateFlow 31 import kotlinx.coroutines.flow.StateFlow 32 import kotlinx.coroutines.flow.asStateFlow 33 import kotlinx.coroutines.flow.combine 34 import kotlinx.coroutines.flow.map 35 import kotlinx.coroutines.suspendCancellableCoroutine 36 37 // TODO (b/262924623): refactor to remove dependency on ColorCustomizationManager & ColorOption 38 // TODO (b/268203200): Create test for ColorPickerRepositoryImpl 39 class ColorPickerRepositoryImpl( 40 wallpaperColorsRepository: WallpaperColorsRepository, 41 private val colorManager: ColorCustomizationManager, 42 ) : ColorPickerRepository { 43 44 private val homeWallpaperColors: StateFlow<WallpaperColorsModel?> = 45 wallpaperColorsRepository.homeWallpaperColors 46 private val lockWallpaperColors: StateFlow<WallpaperColorsModel?> = 47 wallpaperColorsRepository.lockWallpaperColors 48 private var selectedColorOption: MutableStateFlow<ColorOptionModel> = 49 MutableStateFlow(getCurrentColorOption()) 50 51 private val _isApplyingSystemColor = MutableStateFlow(false) 52 override val isApplyingSystemColor = _isApplyingSystemColor.asStateFlow() 53 54 // TODO (b/299510645): update color options on selected option change after restart is disabled 55 override val colorOptions: Flow<Map<ColorType, List<ColorOptionModel>>> = 56 combine(homeWallpaperColors, lockWallpaperColors) { homeColors, lockColors -> 57 homeColors to lockColors 58 } 59 .map { (homeColors, lockColors) -> 60 suspendCancellableCoroutine { continuation -> 61 if ( 62 homeColors is WallpaperColorsModel.Loading || 63 lockColors is WallpaperColorsModel.Loading 64 ) { 65 continuation.resumeWith( 66 Result.success( 67 mapOf( 68 ColorType.WALLPAPER_COLOR to listOf(), 69 ColorType.PRESET_COLOR to listOf() 70 ) 71 ) 72 ) 73 return@suspendCancellableCoroutine 74 } 75 val homeColorsLoaded = homeColors as WallpaperColorsModel.Loaded 76 val lockColorsLoaded = lockColors as WallpaperColorsModel.Loaded 77 colorManager.setWallpaperColors( 78 homeColorsLoaded.colors, 79 lockColorsLoaded.colors 80 ) 81 colorManager.fetchOptions( 82 object : CustomizationManager.OptionsFetchedListener<ColorOption?> { 83 override fun onOptionsLoaded(options: MutableList<ColorOption?>?) { 84 val wallpaperColorOptions: MutableList<ColorOptionModel> = 85 mutableListOf() 86 val presetColorOptions: MutableList<ColorOptionModel> = 87 mutableListOf() 88 options?.forEach { option -> 89 when ((option as ColorOptionImpl).type) { 90 ColorType.WALLPAPER_COLOR -> 91 wallpaperColorOptions.add(option.toModel()) 92 ColorType.PRESET_COLOR -> 93 presetColorOptions.add(option.toModel()) 94 } 95 } 96 continuation.resumeWith( 97 Result.success( 98 mapOf( 99 ColorType.WALLPAPER_COLOR to wallpaperColorOptions, 100 ColorType.PRESET_COLOR to presetColorOptions 101 ) 102 ) 103 ) 104 } 105 106 override fun onError(throwable: Throwable?) { 107 Log.e(TAG, "Error loading theme bundles", throwable) 108 continuation.resumeWith( 109 Result.failure( 110 throwable ?: Throwable("Error loading theme bundles") 111 ) 112 ) 113 } 114 }, 115 /* reload= */ false 116 ) 117 } 118 } 119 120 override suspend fun select(colorOptionModel: ColorOptionModel) { 121 _isApplyingSystemColor.value = true 122 suspendCancellableCoroutine { continuation -> 123 colorManager.apply( 124 colorOptionModel.colorOption, 125 object : CustomizationManager.Callback { 126 override fun onSuccess() { 127 _isApplyingSystemColor.value = false 128 selectedColorOption.value = colorOptionModel 129 continuation.resumeWith(Result.success(Unit)) 130 } 131 132 override fun onError(throwable: Throwable?) { 133 Log.w(TAG, "Apply theme with error", throwable) 134 _isApplyingSystemColor.value = false 135 continuation.resumeWith( 136 Result.failure(throwable ?: Throwable("Error loading theme bundles")) 137 ) 138 } 139 } 140 ) 141 } 142 } 143 144 override fun getCurrentColorOption(): ColorOptionModel { 145 val overlays = colorManager.currentOverlays 146 val styleOrNull = colorManager.currentStyle 147 val style = styleOrNull?.let { Style.valueOf(it) } ?: Style.TONAL_SPOT 148 val source = colorManager.currentColorSource 149 val colorOptionBuilder = ColorOptionImpl.Builder() 150 colorOptionBuilder.source = source 151 colorOptionBuilder.style = style 152 for (overlay in overlays) { 153 colorOptionBuilder.addOverlayPackage(overlay.key, overlay.value) 154 } 155 val colorOption = colorOptionBuilder.build() 156 return ColorOptionModel( 157 key = "", 158 colorOption = colorOption, 159 isSelected = false, 160 ) 161 } 162 163 override fun getCurrentColorSource(): String? { 164 return colorManager.currentColorSource 165 } 166 167 private fun ColorOptionImpl.toModel(): ColorOptionModel { 168 return ColorOptionModel( 169 key = "${this.type}::${this.style}::${this.serializedPackages}", 170 colorOption = this, 171 isSelected = isActive(colorManager), 172 ) 173 } 174 175 companion object { 176 private const val TAG = "ColorPickerRepositoryImpl" 177 } 178 } 179