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 "dark_mode_manager.h"
17
18 #include "setting_data_manager.h"
19 #include "ui_appearance_log.h"
20
21 namespace OHOS::ArkUi::UiAppearance {
22 namespace {
23 const std::string SETTING_DARK_MODE_MODE = "settings.uiappearance.darkmode_mode";
24 const std::string SETTING_DARK_MODE_START_TIME = "settings.uiappearance.darkmode_starttime";
25 const std::string SETTING_DARK_MODE_END_TIME = "settings.uiappearance.darkmode_endtime";
26 const static int32_t USER100 = 100;
27 }
28
GetInstance()29 DarkModeManager &DarkModeManager::GetInstance()
30 {
31 static DarkModeManager instance;
32 return instance;
33 }
34
Initialize(const std::function<void (bool,int32_t)> & updateCallback)35 ErrCode DarkModeManager::Initialize(const std::function<void(bool, int32_t)>& updateCallback)
36 {
37 LoadSettingDataObserversCallback();
38 updateCallback_ = updateCallback;
39 return ERR_OK;
40 }
41
LoadUserSettingData(const int32_t userId,const bool needUpdateCallback,bool & isDarkMode)42 ErrCode DarkModeManager::LoadUserSettingData(const int32_t userId, const bool needUpdateCallback, bool &isDarkMode)
43 {
44 SettingDataManager& manager = SettingDataManager::GetInstance();
45 int32_t darkMode = DARK_MODE_INVALID;
46 manager.GetInt32ValueStrictly(SETTING_DARK_MODE_MODE, darkMode, userId);
47 if (darkMode < DARK_MODE_INVALID || darkMode >= DARK_MODE_SIZE) {
48 LOGE("dark mode out of range: %{public}d, userId: %{public}d", darkMode, userId);
49 darkMode = DARK_MODE_INVALID;
50 }
51 int32_t startTime = -1;
52 manager.GetInt32ValueStrictly(SETTING_DARK_MODE_START_TIME, startTime, userId);
53 int32_t endTime = -1;
54 manager.GetInt32ValueStrictly(SETTING_DARK_MODE_END_TIME, endTime, userId);
55
56 std::lock_guard lock(darkModeStatesMutex_);
57 DarkModeState& state = darkModeStates_[userId];
58 state.settingMode = static_cast<DarkModeMode>(darkMode);
59 state.settingStartTime = startTime;
60 state.settingEndTime = endTime;
61 LOGI("load user setting data, userId: %{public}d, mode: %{public}d, start: %{public}d, end : %{public}d",
62 userId, darkMode, startTime, endTime);
63 temporaryColorModeMgr_.InitData(userId);
64 if (temporaryColorModeMgr_.IsColorModeTemporary(userId) &&
65 temporaryColorModeMgr_.CheckTemporaryStateEffective(userId) == false) {
66 temporaryColorModeMgr_.SetColorModeNormal(userId);
67 }
68 screenSwitchOperatorMgr_.ResetScreenOffOperateInfo();
69 return OnStateChangeLocked(userId, needUpdateCallback, isDarkMode, false);
70 }
71
NotifyDarkModeUpdate(const int32_t userId,const bool isDarkMode)72 void DarkModeManager::NotifyDarkModeUpdate(const int32_t userId, const bool isDarkMode)
73 {
74 SettingDataManager& manager = SettingDataManager::GetInstance();
75 std::lock_guard lock(darkModeStatesMutex_);
76 const DarkModeState& state = darkModeStates_[userId];
77 if (isDarkMode) {
78 if (state.settingMode == DARK_MODE_ALWAYS_LIGHT || state.settingMode == DARK_MODE_INVALID) {
79 LOGI("notify change to always dark, userId: %{public}d", userId);
80 manager.SetStringValue(SETTING_DARK_MODE_MODE, std::to_string(DARK_MODE_ALWAYS_DARK), userId);
81 } // else no need to change
82 } else {
83 if (state.settingMode == DARK_MODE_ALWAYS_DARK || state.settingMode == DARK_MODE_INVALID) {
84 LOGI("notify change to always light, userId: %{public}d", userId);
85 manager.SetStringValue(SETTING_DARK_MODE_MODE, std::to_string(DARK_MODE_ALWAYS_LIGHT), userId);
86 } // else no need to change
87 }
88 }
89
ScreenOnCallback()90 void DarkModeManager::ScreenOnCallback()
91 {
92 screenSwitchOperatorMgr_.SetScreenOn();
93 }
94
ScreenOffCallback()95 void DarkModeManager::ScreenOffCallback()
96 {
97 screenSwitchOperatorMgr_.SetScreenOff();
98 if (screenSwitchOperatorMgr_.HaveScreenOffOperate()) {
99 bool switchToDark = false;
100 int32_t userId = USER100;
101 screenSwitchOperatorMgr_.GetScreenOffOperateInfo(switchToDark, userId);
102 OnChangeDarkMode(
103 switchToDark == true ? DarkModeMode::DARK_MODE_ALWAYS_DARK : DarkModeMode::DARK_MODE_ALWAYS_LIGHT,
104 userId);
105 screenSwitchOperatorMgr_.ResetScreenOffOperateInfo();
106 }
107 }
108
OnSwitchUser(const int32_t userId)109 ErrCode DarkModeManager::OnSwitchUser(const int32_t userId)
110 {
111 SettingDataManager& manager = SettingDataManager::GetInstance();
112 if (!manager.IsInitialized()) {
113 ErrCode code = manager.Initialize();
114 if (code != ERR_OK || manager.IsInitialized() == false) {
115 LOGE("setting data manager is not initialized");
116 return ERR_NO_INIT;
117 }
118 }
119
120 if (userId <= INVALID_USER_ID) {
121 LOGE("invalid userId: %{public}d", userId);
122 return ERR_INVALID_OPERATION;
123 }
124
125 std::lock_guard lock(settingDataObserversMutex_);
126 if (settingDataObserversUserId_ != INVALID_USER_ID) {
127 LOGI("clear timers and unregister observers for userId: %{public}d", settingDataObserversUserId_);
128 alarmTimerManager_.ClearTimerByUserId(settingDataObserversUserId_);
129 UnregisterSettingDataObserversLocked(settingDataObserversUserId_);
130 settingDataObserversUserId_ = INVALID_USER_ID;
131 }
132
133 ErrCode code = RegisterSettingDataObserversLocked(userId);
134 settingDataObserversUserId_ = userId;
135 return code;
136 }
137
DoSwitchTemporaryColorMode(const int32_t userId,bool isDarkMode)138 void DarkModeManager::DoSwitchTemporaryColorMode(const int32_t userId, bool isDarkMode)
139 {
140 if (IsDarkModeCustomAuto(userId)) {
141 screenSwitchOperatorMgr_.ResetScreenOffOperateInfo();
142 int32_t settingStartTime = 0;
143 int32_t settingEndTime = 0;
144 auto res = GetSettingTime(userId, settingStartTime, settingEndTime);
145 if (res == false) {
146 LOGE("GetSettingTime faild userId: %{public}d", userId);
147 return;
148 }
149 if ((AlarmTimerManager::IsWithinTimeInterval(settingStartTime, settingEndTime) && isDarkMode == true) ||
150 (!AlarmTimerManager::IsWithinTimeInterval(settingStartTime, settingEndTime) && isDarkMode == false)) {
151 temporaryColorModeMgr_.SetColorModeNormal(userId);
152 } else {
153 temporaryColorModeMgr_.SetColorModeTemporary(userId);
154 }
155 }
156 }
157
UpdateDarkModeSchedule(const DarkModeMode mode,const int32_t userId,const bool resetTempColorModeFlag)158 void DarkModeManager::UpdateDarkModeSchedule(
159 const DarkModeMode mode, const int32_t userId, const bool resetTempColorModeFlag)
160 {
161 screenSwitchOperatorMgr_.ResetScreenOffOperateInfo();
162 if (resetTempColorModeFlag == true) {
163 OnChangeDarkMode(mode, userId);
164 return;
165 }
166
167 if (screenSwitchOperatorMgr_.IsScreenOff()) {
168 if (temporaryColorModeMgr_.IsColorModeNormal(userId) ||
169 temporaryColorModeMgr_.CheckTemporaryStateEffective(userId) == false) {
170 OnChangeDarkMode(mode, userId);
171 }
172 return;
173 }
174
175 if (temporaryColorModeMgr_.IsColorModeNormal(userId) ||
176 temporaryColorModeMgr_.CheckTemporaryStateEffective(userId) == false) {
177 screenSwitchOperatorMgr_.SetScreenOffOperateInfo(mode == DARK_MODE_ALWAYS_DARK, userId);
178 LOGI("SetScreenOffOperateInfo userId:%{public}d operate:%{public}d", userId, static_cast<int32_t>(mode));
179 }
180 }
181
RestartTimer()182 ErrCode DarkModeManager::RestartTimer()
183 {
184 std::lock_guard lock(darkModeStatesMutex_);
185 DarkModeMode mode = darkModeStates_[settingDataObserversUserId_].settingMode;
186 if (mode != DARK_MODE_CUSTOM_AUTO) {
187 LOGD("no need to restart timer.");
188 return ERR_OK;
189 }
190
191 int32_t startTime = darkModeStates_[settingDataObserversUserId_].settingStartTime;
192 int32_t endTime = darkModeStates_[settingDataObserversUserId_].settingEndTime;
193 if (AlarmTimerManager::IsWithinTimeInterval(startTime, endTime)) {
194 UpdateDarkModeSchedule(DARK_MODE_ALWAYS_DARK, settingDataObserversUserId_, false);
195 } else {
196 UpdateDarkModeSchedule(DARK_MODE_ALWAYS_LIGHT, settingDataObserversUserId_, false);
197 }
198 return alarmTimerManager_.RestartAllTimer();
199 }
200
IsDarkModeCustomAuto(const int32_t userId)201 bool DarkModeManager::IsDarkModeCustomAuto(const int32_t userId)
202 {
203 std::lock_guard lock(darkModeStatesMutex_);
204 return darkModeStates_[userId].settingMode == DARK_MODE_CUSTOM_AUTO;
205 }
206
GetSettingTime(const int32_t userId,int32_t & settingStartTime,int32_t & settingEndTime)207 bool DarkModeManager::GetSettingTime(const int32_t userId, int32_t& settingStartTime, int32_t& settingEndTime)
208 {
209 std::lock_guard lock(darkModeStatesMutex_);
210 auto it = darkModeStates_.find(userId);
211 if (it != darkModeStates_.end()) {
212 settingStartTime = it->second.settingStartTime;
213 settingEndTime = it->second.settingEndTime;
214 return true;
215 }
216 return false;
217 }
218
IsColorModeNormal(const int32_t userId)219 bool DarkModeManager::IsColorModeNormal(const int32_t userId)
220 {
221 return temporaryColorModeMgr_.IsColorModeNormal(userId);
222 }
223
Dump()224 void DarkModeManager::Dump()
225 {
226 {
227 std::lock_guard observersGuard(settingDataObserversMutex_);
228 LOGD("settingData observers size: %{public}zu, userId: %{public}d",
229 settingDataObservers_.size(), settingDataObserversUserId_);
230 }
231
232 std::lock_guard stateGuard(darkModeStatesMutex_);
233 LOGD("darkModeStates size: %{public}zu", darkModeStates_.size());
234 for (const auto& state : darkModeStates_) {
235 LOGD("userId: %{public}d, mode: %{public}d, start: %{public}d, end: %{public}d",
236 state.first, state.second.settingMode, state.second.settingStartTime, state.second.settingEndTime);
237 }
238
239 alarmTimerManager_.Dump();
240 }
241
LoadSettingDataObserversCallback()242 void DarkModeManager::LoadSettingDataObserversCallback()
243 {
244 std::lock_guard lock(settingDataObserversMutex_);
245 settingDataObservers_.clear();
246 settingDataObservers_.emplace_back(SETTING_DARK_MODE_MODE, [&](const std::string& key, int32_t userId) {
247 SettingDataDarkModeModeUpdateFunc(key, userId);
248 });
249 settingDataObservers_.emplace_back(SETTING_DARK_MODE_START_TIME, [&](const std::string& key, int32_t userId) {
250 SettingDataDarkModeStartTimeUpdateFunc(key, userId);
251 });
252 settingDataObservers_.emplace_back(SETTING_DARK_MODE_END_TIME, [&](const std::string& key, int32_t userId) {
253 SettingDataDarkModeEndTimeUpdateFunc(key, userId);
254 });
255 }
256
RegisterSettingDataObserversLocked(const int32_t userId) const257 ErrCode DarkModeManager::RegisterSettingDataObserversLocked(const int32_t userId) const
258 {
259 SettingDataManager& manager = SettingDataManager::GetInstance();
260 size_t count = 0;
261 for (const auto& observer : settingDataObservers_) {
262 if (manager.RegisterObserver(observer.first, observer.second, userId) != ERR_OK) {
263 count++;
264 }
265 }
266 if (count != 0) {
267 LOGE("setting data observers are not all initialized");
268 return ERR_NO_INIT;
269 }
270 LOGD("setting data observers are all initialized");
271 return ERR_OK;
272 }
273
UnregisterSettingDataObserversLocked(const int32_t userId) const274 void DarkModeManager::UnregisterSettingDataObserversLocked(const int32_t userId) const
275 {
276 SettingDataManager& manager = SettingDataManager::GetInstance();
277 for (const auto& observer : settingDataObservers_) {
278 manager.UnregisterObserver(observer.first, userId);
279 }
280 }
281
SettingDataDarkModeModeUpdateFunc(const std::string & key,const int32_t userId)282 void DarkModeManager::SettingDataDarkModeModeUpdateFunc(const std::string& key, const int32_t userId)
283 {
284 SettingDataManager& manager = SettingDataManager::GetInstance();
285 int32_t value = DARK_MODE_INVALID;
286 ErrCode code = manager.GetInt32ValueStrictly(key, value, userId);
287 if (code != ERR_OK) {
288 LOGE("get dark mode value failed, key: %{public}s, userId: %{public}d, code: %{public}d, set to default",
289 key.c_str(), userId, code);
290 value = DARK_MODE_INVALID;
291 }
292 if (value < DARK_MODE_INVALID || value >= DARK_MODE_SIZE) {
293 LOGE("dark mode value is invalid, key: %{public}s, userId: %{public}d, value: %{public}d, set to default",
294 key.c_str(), userId, value);
295 value = DARK_MODE_INVALID;
296 }
297
298 auto mode = static_cast<DarkModeMode>(value);
299 std::lock_guard lock(darkModeStatesMutex_);
300 LOGI("dark mode change, key: %{public}s, userId: %{public}d, from %{public}d to %{public}d",
301 key.c_str(), userId, darkModeStates_[userId].settingMode, value);
302 darkModeStates_[userId].settingMode = mode;
303 bool isDarkMode = false;
304 OnStateChangeLocked(userId, true, isDarkMode, true);
305 }
306
SettingDataDarkModeStartTimeUpdateFunc(const std::string & key,const int32_t userId)307 void DarkModeManager::SettingDataDarkModeStartTimeUpdateFunc(const std::string& key, const int32_t userId)
308 {
309 SettingDataManager& manager = SettingDataManager::GetInstance();
310 int32_t value = -1;
311 manager.GetInt32ValueStrictly(key, value, userId);
312 std::lock_guard lock(darkModeStatesMutex_);
313 LOGI("dark mode start time change, key: %{public}s, userId: %{public}d, from %{public}d to %{public}d",
314 key.c_str(), userId, darkModeStates_[userId].settingStartTime, value);
315 darkModeStates_[userId].settingStartTime = value;
316 bool isDarkMode = false;
317 OnStateChangeLocked(userId, true, isDarkMode, true);
318 }
319
SettingDataDarkModeEndTimeUpdateFunc(const std::string & key,const int32_t userId)320 void DarkModeManager::SettingDataDarkModeEndTimeUpdateFunc(const std::string& key, const int32_t userId)
321 {
322 SettingDataManager& manager = SettingDataManager::GetInstance();
323 int32_t value = -1;
324 manager.GetInt32ValueStrictly(key, value, userId);
325 std::lock_guard lock(darkModeStatesMutex_);
326 LOGI("dark mode end time change, key: %{public}s, userId: %{public}d, from %{public}d to %{public}d",
327 key.c_str(), userId, darkModeStates_[userId].settingEndTime, value);
328 darkModeStates_[userId].settingEndTime = value;
329 bool isDarkMode = false;
330 OnStateChangeLocked(userId, true, isDarkMode, true);
331 }
332
OnStateChangeLocked(const int32_t userId,const bool needUpdateCallback,bool & isDarkMode,const bool resetTempColorModeFlag)333 ErrCode DarkModeManager::OnStateChangeLocked(
334 const int32_t userId, const bool needUpdateCallback, bool& isDarkMode, const bool resetTempColorModeFlag)
335 {
336 ErrCode code = ERR_OK;
337 DarkModeState& state = darkModeStates_[userId];
338 switch (state.settingMode) {
339 case DARK_MODE_ALWAYS_LIGHT:
340 case DARK_MODE_ALWAYS_DARK:
341 code = OnStateChangeToAllDayMode(
342 userId, state.settingMode, needUpdateCallback, isDarkMode, resetTempColorModeFlag);
343 break;
344 case DARK_MODE_CUSTOM_AUTO:
345 code = OnStateChangeToCustomAutoMode(userId, state, needUpdateCallback, isDarkMode, resetTempColorModeFlag);
346 break;
347 default:
348 // do nothing
349 code = ERR_INVALID_OPERATION;
350 break;
351 }
352 return code;
353 }
354
OnStateChangeToAllDayMode(const int32_t userId,const DarkModeMode darkMode,const bool needUpdateCallback,bool & isDarkMode,const bool resetTempColorModeFlag)355 ErrCode DarkModeManager::OnStateChangeToAllDayMode(const int32_t userId, const DarkModeMode darkMode,
356 const bool needUpdateCallback, bool& isDarkMode, const bool resetTempColorModeFlag)
357 {
358 alarmTimerManager_.ClearTimerByUserId(userId);
359 isDarkMode = darkMode == DARK_MODE_ALWAYS_DARK;
360 if (needUpdateCallback) {
361 UpdateDarkModeSchedule(darkMode, userId, resetTempColorModeFlag);
362 }
363 return ERR_OK;
364 }
365
OnStateChangeToCustomAutoMode(const int32_t userId,const DarkModeState & state,const bool needUpdateCallback,bool & isDarkMode,const bool resetTempColorModeFlag)366 ErrCode DarkModeManager::OnStateChangeToCustomAutoMode(const int32_t userId, const DarkModeState& state,
367 const bool needUpdateCallback, bool& isDarkMode, const bool resetTempColorModeFlag)
368 {
369 ErrCode code = CreateOrUpdateTimers(state.settingStartTime, state.settingEndTime, userId);
370 if (code != ERR_OK) {
371 alarmTimerManager_.ClearTimerByUserId(userId);
372 return code;
373 }
374 DarkModeMode mode = DARK_MODE_INVALID;
375 if (AlarmTimerManager::IsWithinTimeInterval(state.settingStartTime, state.settingEndTime)) {
376 isDarkMode = true;
377 mode = DARK_MODE_ALWAYS_DARK;
378 } else {
379 isDarkMode = false;
380 mode = DARK_MODE_ALWAYS_LIGHT;
381 }
382
383 if (needUpdateCallback) {
384 UpdateDarkModeSchedule(mode, userId, resetTempColorModeFlag);
385 }
386 return ERR_OK;
387 }
388
OnChangeDarkMode(const DarkModeMode mode,const int32_t userId)389 void DarkModeManager::OnChangeDarkMode(const DarkModeMode mode, const int32_t userId)
390 {
391 if (!updateCallback_) {
392 LOGE("no update callback, mode: %{public}d, userId: %{public}d", mode, userId);
393 return;
394 }
395 updateCallback_(mode == DARK_MODE_ALWAYS_DARK, userId);
396 if (temporaryColorModeMgr_.IsColorModeTemporary(userId)) {
397 temporaryColorModeMgr_.SetColorModeNormal(userId);
398 }
399 }
400
CreateOrUpdateTimers(int32_t startTime,int32_t endTime,int32_t userId)401 ErrCode DarkModeManager::CreateOrUpdateTimers(int32_t startTime, int32_t endTime, int32_t userId)
402 {
403 auto callbackSetDark = [startTime, endTime, userId]() {
404 LOGI("timer callback, startTime: %{public}d, endTime: %{public}d, userId: %{public}d",
405 startTime, endTime, userId);
406 ErrCode code = GetInstance().CheckTimerCallbackParams(startTime, endTime, userId);
407 if (code != ERR_OK) {
408 LOGE("timer callback, params check failed: %{public}d", code);
409 return;
410 }
411 GetInstance().UpdateDarkModeSchedule(DARK_MODE_ALWAYS_DARK, userId, false);
412 };
413
414 auto callbackSetLight = [startTime, endTime, userId]() {
415 LOGI("timer callback, startTime: %{public}d, endTime: %{public}d, userId: %{public}d",
416 startTime, endTime, userId);
417 ErrCode code = GetInstance().CheckTimerCallbackParams(startTime, endTime, userId);
418 if (code != ERR_OK) {
419 LOGE("timer callback, params check failed: %{public}d", code);
420 return;
421 }
422 GetInstance().UpdateDarkModeSchedule(DARK_MODE_ALWAYS_LIGHT, userId, false);
423 };
424
425 return alarmTimerManager_.SetScheduleTime(startTime, endTime, userId, callbackSetDark, callbackSetLight);
426 }
427
CheckTimerCallbackParams(const int32_t startTime,const int32_t endTime,const int32_t userId)428 ErrCode DarkModeManager::CheckTimerCallbackParams(const int32_t startTime, const int32_t endTime, const int32_t userId)
429 {
430 std::lock_guard lock(darkModeStatesMutex_);
431 DarkModeState& state = darkModeStates_[userId];
432 if (state.settingMode != DARK_MODE_CUSTOM_AUTO) {
433 LOGE("timer callback, param wrong, setting mode: %{public}d", state.settingMode);
434 return ERR_INVALID_OPERATION;
435 }
436 if (state.settingStartTime != startTime) {
437 LOGE("timer callback, param wrong, startTime: %{public}d, setting: %{public}d",
438 startTime, state.settingStartTime);
439 return ERR_INVALID_OPERATION;
440 }
441 if (state.settingEndTime != endTime) {
442 LOGE("timer callback, param wrong, endTime: %{public}d, setting: %{public}d", endTime, state.settingEndTime);
443 return ERR_INVALID_OPERATION;
444 }
445 return ERR_OK;
446 }
447 } // namespace OHOS::ArkUi::UiAppearance
448