1 /* 2 * Copyright (C) 2024 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.picker.color.data.util 17 18 import android.app.WallpaperColors 19 import android.content.Context 20 import android.content.res.Configuration 21 import android.provider.Settings 22 import android.util.Log 23 import android.util.SparseIntArray 24 import com.android.customization.model.ResourceConstants 25 import com.android.systemui.monet.ColorScheme 26 import com.android.systemui.monet.Style 27 import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository 28 import dagger.hilt.android.qualifiers.ApplicationContext 29 import javax.inject.Inject 30 import javax.inject.Singleton 31 import org.json.JSONException 32 import org.json.JSONObject 33 34 /** 35 * Extract material next colors from wallpaper colors. Based on Nexus Launcher's 36 * MaterialColorsGenerator, nexuslauncher/widget/MaterialColorsGenerator.java 37 */ 38 @Singleton 39 class MaterialColorsGenerator 40 @Inject 41 constructor( 42 @ApplicationContext private val applicationContext: Context, 43 private val secureSettingsRepository: SecureSettingsRepository, 44 ) { addShadesnull45 private fun addShades(shades: List<Int>, resources: IntArray, output: SparseIntArray) { 46 if (shades.size != resources.size) { 47 Log.e(TAG, "The number of shades computed doesn't match the number of resources.") 48 return 49 } 50 for (i in resources.indices) { 51 output.put(resources[i], 0xff000000.toInt() or shades[i]) 52 } 53 } 54 55 /** 56 * Generates the mapping from system color resources to values from wallpaper colors. 57 * 58 * @return a list of color resource IDs and a corresponding list of their color values 59 */ generatenull60 suspend fun generate(colors: WallpaperColors): Pair<IntArray, IntArray> { 61 val isDarkMode = 62 (applicationContext.resources.configuration.uiMode and 63 Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES 64 val colorScheme = ColorScheme(colors, isDarkMode, fetchThemeStyleFromSetting()) 65 return generate(colorScheme) 66 } 67 68 /** 69 * Generates the mapping from system color resources to values from color seed and style. 70 * 71 * @return a list of color resource IDs and a corresponding list of their color values 72 */ generatenull73 fun generate(colorSeed: Int, @Style.Type style: Int): Pair<IntArray, IntArray> { 74 val isDarkMode = 75 (applicationContext.resources.configuration.uiMode and 76 Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES 77 val colorScheme = ColorScheme(colorSeed, isDarkMode, style) 78 return generate(colorScheme) 79 } 80 generatenull81 private fun generate(colorScheme: ColorScheme): Pair<IntArray, IntArray> { 82 val allNeutralColors: MutableList<Int> = ArrayList() 83 allNeutralColors.addAll(colorScheme.neutral1.allShades) 84 allNeutralColors.addAll(colorScheme.neutral2.allShades) 85 86 val allAccentColors: MutableList<Int> = ArrayList() 87 allAccentColors.addAll(colorScheme.accent1.allShades) 88 allAccentColors.addAll(colorScheme.accent2.allShades) 89 allAccentColors.addAll(colorScheme.accent3.allShades) 90 91 return Pair( 92 NEUTRAL_RESOURCES + ACCENT_RESOURCES, 93 (allNeutralColors + allAccentColors).toIntArray(), 94 ) 95 } 96 97 @Style.Type fetchThemeStyleFromSettingnull98 private suspend fun fetchThemeStyleFromSetting(): Int { 99 val overlayPackageJson = 100 secureSettingsRepository.getString(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES) 101 return if (!overlayPackageJson.isNullOrEmpty()) { 102 try { 103 val jsonObject = JSONObject(overlayPackageJson) 104 Style.valueOf(jsonObject.getString(ResourceConstants.OVERLAY_CATEGORY_THEME_STYLE)) 105 } catch (e: (JSONException)) { 106 Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e) 107 Style.TONAL_SPOT 108 } catch (e: IllegalArgumentException) { 109 Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e) 110 Style.TONAL_SPOT 111 } 112 } else { 113 Style.TONAL_SPOT 114 } 115 } 116 117 companion object { 118 private const val TAG = "MaterialColorsGenerator" 119 120 private val ACCENT_RESOURCES = 121 intArrayOf( 122 android.R.color.system_accent1_0, 123 android.R.color.system_accent1_10, 124 android.R.color.system_accent1_50, 125 android.R.color.system_accent1_100, 126 android.R.color.system_accent1_200, 127 android.R.color.system_accent1_300, 128 android.R.color.system_accent1_400, 129 android.R.color.system_accent1_500, 130 android.R.color.system_accent1_600, 131 android.R.color.system_accent1_700, 132 android.R.color.system_accent1_800, 133 android.R.color.system_accent1_900, 134 android.R.color.system_accent1_1000, 135 android.R.color.system_accent2_0, 136 android.R.color.system_accent2_10, 137 android.R.color.system_accent2_50, 138 android.R.color.system_accent2_100, 139 android.R.color.system_accent2_200, 140 android.R.color.system_accent2_300, 141 android.R.color.system_accent2_400, 142 android.R.color.system_accent2_500, 143 android.R.color.system_accent2_600, 144 android.R.color.system_accent2_700, 145 android.R.color.system_accent2_800, 146 android.R.color.system_accent2_900, 147 android.R.color.system_accent2_1000, 148 android.R.color.system_accent3_0, 149 android.R.color.system_accent3_10, 150 android.R.color.system_accent3_50, 151 android.R.color.system_accent3_100, 152 android.R.color.system_accent3_200, 153 android.R.color.system_accent3_300, 154 android.R.color.system_accent3_400, 155 android.R.color.system_accent3_500, 156 android.R.color.system_accent3_600, 157 android.R.color.system_accent3_700, 158 android.R.color.system_accent3_800, 159 android.R.color.system_accent3_900, 160 android.R.color.system_accent3_1000, 161 ) 162 private val NEUTRAL_RESOURCES = 163 intArrayOf( 164 android.R.color.system_neutral1_0, 165 android.R.color.system_neutral1_10, 166 android.R.color.system_neutral1_50, 167 android.R.color.system_neutral1_100, 168 android.R.color.system_neutral1_200, 169 android.R.color.system_neutral1_300, 170 android.R.color.system_neutral1_400, 171 android.R.color.system_neutral1_500, 172 android.R.color.system_neutral1_600, 173 android.R.color.system_neutral1_700, 174 android.R.color.system_neutral1_800, 175 android.R.color.system_neutral1_900, 176 android.R.color.system_neutral1_1000, 177 android.R.color.system_neutral2_0, 178 android.R.color.system_neutral2_10, 179 android.R.color.system_neutral2_50, 180 android.R.color.system_neutral2_100, 181 android.R.color.system_neutral2_200, 182 android.R.color.system_neutral2_300, 183 android.R.color.system_neutral2_400, 184 android.R.color.system_neutral2_500, 185 android.R.color.system_neutral2_600, 186 android.R.color.system_neutral2_700, 187 android.R.color.system_neutral2_800, 188 android.R.color.system_neutral2_900, 189 android.R.color.system_neutral2_1000, 190 ) 191 } 192 } 193