1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/token_theme/token_theme_storage.h"
17
18 #include <memory>
19
20 #include "base/utils/utils.h"
21 #include "base/utils/system_properties.h"
22 #include "core/pipeline_ng/pipeline_context.h"
23 #include "core/common/resource/resource_parse_utils.h"
24
25 namespace OHOS::Ace::NG {
26
GetInstance()27 TokenThemeStorage* TokenThemeStorage::GetInstance()
28 {
29 static TokenThemeStorage instance;
30 return &instance;
31 }
32
33 TokenThemeStorage::TokenThemeStorage() = default;
34
StoreThemeScope(TokenThemeScopeId themeScopeId,int32_t themeId)35 void TokenThemeStorage::StoreThemeScope(TokenThemeScopeId themeScopeId, int32_t themeId)
36 {
37 themeScopeMap_[themeScopeId] = themeId;
38 }
39
RemoveThemeScope(TokenThemeScopeId themeScopeId,bool removeToken)40 void TokenThemeStorage::RemoveThemeScope(TokenThemeScopeId themeScopeId, bool removeToken /* = false */)
41 {
42 if (removeToken) {
43 CacheRemove(themeScopeMap_[themeScopeId]);
44 }
45 themeScopeMap_.erase(themeScopeId);
46 }
47
GetTheme(TokenThemeScopeId themeScopeId)48 const RefPtr<TokenTheme>& TokenThemeStorage::GetTheme(TokenThemeScopeId themeScopeId)
49 {
50 if (themeScopeId == 0) {
51 return GetDefaultTheme();
52 }
53 auto themeId = themeScopeMap_[themeScopeId];
54 return CacheGet(themeId);
55 }
56
SetDefaultTheme(const RefPtr<TokenTheme> & theme,ColorMode colorMode)57 void TokenThemeStorage::SetDefaultTheme(const RefPtr<TokenTheme>& theme, ColorMode colorMode)
58 {
59 (colorMode == ColorMode::DARK ? defaultDarkTheme_ : defaultLightTheme_) = theme;
60 }
61
UpdateDefaultThemeBySystemTheme(ColorMode colorMode)62 void TokenThemeStorage::UpdateDefaultThemeBySystemTheme(ColorMode colorMode)
63 {
64 RefPtr<TokenTheme>& theme = colorMode == ColorMode::DARK ? defaultDarkTheme_ : defaultLightTheme_;
65 if (!theme) {
66 return;
67 }
68 auto sysTheme = ObtainSystemTheme();
69 if (!sysTheme) {
70 return;
71 }
72 auto& colorsAvailable = colorMode == ColorMode::DARK ? darkThemeColorsAvailable_ : lightThemeColorsAvailable_;
73 for (size_t i = 0; i < TokenColors::TOTAL_NUMBER; i++) {
74 if (!colorsAvailable[i]) {
75 auto color = sysTheme->Colors()->GetByIndex(i);
76 theme->Colors()->SetColor(i, color);
77 colorsAvailable[i] = true;
78 }
79 }
80 }
81
GetDefaultTheme()82 const RefPtr<TokenTheme>& TokenThemeStorage::GetDefaultTheme()
83 {
84 auto colorMode = CheckLocalAndSystemColorMode();
85 if (systemTokenThemeCreated_[static_cast<uint32_t>(colorMode)]) {
86 return colorMode == ColorMode::DARK ? defaultDarkTheme_ : defaultLightTheme_;
87 }
88
89 UpdateDefaultThemeBySystemTheme(colorMode);
90 return colorMode == ColorMode::DARK ? defaultDarkTheme_ : defaultLightTheme_;
91 }
92
CheckLocalAndSystemColorMode()93 ColorMode TokenThemeStorage::CheckLocalAndSystemColorMode()
94 {
95 auto sysColorMode = Container::CurrentColorMode();
96 auto pipelineContext = NG::PipelineContext::GetCurrentContext();
97 CHECK_NULL_RETURN(pipelineContext, sysColorMode);
98 auto colorMode = pipelineContext->GetLocalColorMode();
99 if (colorMode == ColorMode::COLOR_MODE_UNDEFINED) {
100 colorMode = sysColorMode;
101 }
102 return colorMode;
103 }
104
CacheClear()105 void TokenThemeStorage::CacheClear()
106 {
107 std::lock_guard<std::mutex> lock(themeCacheMutex_);
108 themeCache_.clear();
109 }
110
ResetThemeColor(int32_t themeId,RefPtr<TokenTheme> & theme,RefPtr<TokenTheme> & defaultTheme,ColorMode & colorMode)111 void TokenThemeStorage::ResetThemeColor(int32_t themeId, RefPtr<TokenTheme>& theme, RefPtr<TokenTheme>& defaultTheme,
112 ColorMode& colorMode)
113 {
114 auto resObjs = theme->GetResObjs();
115 if (resObjs.size() != TokenColors::TOTAL_NUMBER) {
116 return;
117 }
118 auto tokenColors = theme->Colors();
119 auto defaultColors = defaultTheme ? defaultTheme->Colors() : tokenColors;
120 auto userFlags = themeColorSetByUser_[themeId][(colorMode == ColorMode::DARK)];
121 for (int32_t i = 0; i < TokenColors::TOTAL_NUMBER; i++) {
122 if (!resObjs[i]) {
123 if (userFlags.size() == TokenColors::TOTAL_NUMBER && !userFlags[i]) {
124 tokenColors->SetColor(i, defaultColors->GetByIndex(i));
125 }
126 continue;
127 }
128 Color colorValue;
129 auto state = ResourceParseUtils::ParseResColor(resObjs[i], colorValue);
130 if (!state) {
131 continue;
132 }
133 tokenColors->SetColor(i, colorValue);
134 }
135 }
136
CacheResetColor()137 void TokenThemeStorage::CacheResetColor()
138 {
139 if (themeCache_.size() == 0) {
140 return;
141 }
142 auto colorMode = CheckLocalAndSystemColorMode();
143 auto defaultTheme = GetDefaultTheme();
144 if (!defaultTheme) {
145 defaultTheme = CreateSystemTokenTheme(colorMode);
146 SetDefaultTheme(defaultTheme, colorMode);
147 CacheSet(defaultTheme);
148 }
149 std::lock_guard<std::mutex> lock(themeCacheMutex_);
150 for (auto& [themeId, theme] : themeCache_) {
151 LOGD("Theme reset colors with id %{public}d", themeId);
152 if (!theme || (theme->GetColorMode() != ColorMode::COLOR_MODE_UNDEFINED)) {
153 continue;
154 }
155 ResetThemeColor(themeId, theme, defaultTheme, colorMode);
156 }
157 }
158
CacheSet(const RefPtr<TokenTheme> & theme)159 void TokenThemeStorage::CacheSet(const RefPtr<TokenTheme>& theme)
160 {
161 CHECK_NULL_VOID(theme);
162 std::lock_guard<std::mutex> lock(themeCacheMutex_);
163 themeCache_[theme->GetId()] = theme;
164 }
165
CacheGet(int32_t themeId)166 const RefPtr<TokenTheme>& TokenThemeStorage::CacheGet(int32_t themeId)
167 {
168 std::lock_guard<std::mutex> lock(themeCacheMutex_);
169 return themeCache_[themeId];
170 }
171
CacheRemove(int32_t themeId)172 void TokenThemeStorage::CacheRemove(int32_t themeId)
173 {
174 std::lock_guard<std::mutex> lock(themeCacheMutex_);
175 themeCache_.erase(themeId);
176 }
177
ObtainSystemTheme()178 RefPtr<TokenTheme> TokenThemeStorage::ObtainSystemTheme()
179 {
180 RefPtr<TokenTheme> theme = nullptr;
181 auto colorMode = CheckLocalAndSystemColorMode();
182 systemTokenThemeCreated_[static_cast<uint32_t>(colorMode)] = false;
183 if (colorMode == ColorMode::DARK) {
184 theme = CacheGet(TokenThemeStorage::SYSTEM_THEME_DARK_ID);
185 } else {
186 theme = CacheGet(TokenThemeStorage::SYSTEM_THEME_LIGHT_ID);
187 }
188 if (!theme) {
189 theme = CreateSystemTokenTheme(colorMode);
190 CacheSet(theme);
191 }
192 if (theme) {
193 systemTokenThemeCreated_[static_cast<uint32_t>(colorMode)] = true;
194 }
195 return theme;
196 }
197
CreateSystemTokenTheme(ColorMode colorMode)198 RefPtr<TokenTheme> TokenThemeStorage::CreateSystemTokenTheme(ColorMode colorMode)
199 {
200 auto container = Container::Current();
201 CHECK_NULL_RETURN(container, nullptr);
202 auto pipelineContext = container->GetPipelineContext();
203 CHECK_NULL_RETURN(pipelineContext, nullptr);
204 auto themeManager = pipelineContext->GetThemeManager();
205 CHECK_NULL_RETURN(themeManager, nullptr);
206 auto themeConstants = themeManager->GetThemeConstants();
207 CHECK_NULL_RETURN(themeConstants, nullptr);
208
209 auto themeId = colorMode == ColorMode::DARK ?
210 TokenThemeStorage::SYSTEM_THEME_DARK_ID : TokenThemeStorage::SYSTEM_THEME_LIGHT_ID;
211 auto tokenColors = AceType::MakeRefPtr<TokenColors>();
212 auto tokenDarkColors = AceType::MakeRefPtr<TokenColors>();
213 auto tokenTheme = AceType::MakeRefPtr<TokenTheme>(themeId);
214 tokenTheme->SetColors(tokenColors);
215 tokenTheme->SetDarkColors(tokenDarkColors);
216
217 std::vector<Color> colors;
218 std::vector<Color> darkColors;
219 colors.reserve(TokenColors::TOTAL_NUMBER);
220 darkColors.reserve(TokenColors::TOTAL_NUMBER);
221 for (size_t resId = 0; resId < TokenColors::TOTAL_NUMBER; ++resId) {
222 colors.push_back(themeConstants->GetColor(TokenColors::GetSystemColorResIdByIndex(resId)));
223 darkColors.push_back(themeConstants->GetColor(TokenColors::GetSystemColorResIdByIndex(resId)));
224 }
225 tokenColors->SetColors(std::move(colors));
226 tokenDarkColors->SetColors(std::move(darkColors));
227 return tokenTheme;
228 }
229
SetIsThemeColorAvailable(bool isDark,int32_t index,bool isColorAvailable)230 void TokenThemeStorage::SetIsThemeColorAvailable(bool isDark, int32_t index, bool isColorAvailable)
231 {
232 if (index >= 0 && index < TokenColors::TOTAL_NUMBER) {
233 auto& colorsAvailable = isDark ? darkThemeColorsAvailable_ : lightThemeColorsAvailable_;
234 colorsAvailable[index] = isColorAvailable;
235 }
236 }
237
SetIsThemeColorSetByUser(int32_t themeId,bool isDark,int32_t index,bool isColorSetByUser)238 void TokenThemeStorage::SetIsThemeColorSetByUser(int32_t themeId, bool isDark, int32_t index, bool isColorSetByUser)
239 {
240 if (index < 0 || index >= TokenColors::TOTAL_NUMBER) {
241 return;
242 }
243 auto& themeIdMap = themeColorSetByUser_[themeId];
244 if (themeIdMap.find(isDark) == themeIdMap.end()) {
245 themeIdMap[isDark] = std::vector<bool> (TokenColors::TOTAL_NUMBER, false);
246 }
247 themeIdMap[isDark][index] = isColorSetByUser;
248 }
249 } // namespace OHOS::Ace::NG
250