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 }
27
GetInstance()28 DarkModeManager &DarkModeManager::GetInstance()
29 {
30 static DarkModeManager instance;
31 return instance;
32 }
33
Initialize(const std::function<void (bool,int32_t)> & updateCallback)34 ErrCode DarkModeManager::Initialize(const std::function<void(bool, int32_t)>& updateCallback)
35 {
36 LoadSettingDataObserversCallback();
37 updateCallback_ = updateCallback;
38 return ERR_OK;
39 }
40
LoadUserSettingData(const int32_t userId,const bool needUpdateCallback,bool & isDarkMode)41 ErrCode DarkModeManager::LoadUserSettingData(const int32_t userId, const bool needUpdateCallback, bool &isDarkMode)
42 {
43 SettingDataManager& manager = SettingDataManager::GetInstance();
44 int32_t darkMode = DARK_MODE_INVALID;
45 manager.GetInt32ValueStrictly(SETTING_DARK_MODE_MODE, darkMode, userId);
46 if (darkMode < DARK_MODE_INVALID || darkMode >= DARK_MODE_SIZE) {
47 LOGE("dark mode out of range: %{public}d, userId: %{public}d", darkMode, userId);
48 darkMode = DARK_MODE_INVALID;
49 }
50 int32_t startTime = -1;
51 manager.GetInt32ValueStrictly(SETTING_DARK_MODE_START_TIME, startTime, userId);
52 int32_t endTime = -1;
53 manager.GetInt32ValueStrictly(SETTING_DARK_MODE_END_TIME, endTime, userId);
54
55 std::lock_guard lock(darkModeStatesMutex_);
56 DarkModeState& state = darkModeStates_[userId];
57 state.settingMode = static_cast<DarkModeMode>(darkMode);
58 state.settingStartTime = startTime;
59 state.settingEndTime = endTime;
60 LOGI("load user setting data, userId: %{public}d, mode: %{public}d, start: %{public}d, end : %{public}d",
61 userId, darkMode, startTime, endTime);
62 return OnStateChangeLocked(userId, needUpdateCallback, isDarkMode);
63 }
64
NotifyDarkModeUpdate(const int32_t userId,const bool isDarkMode)65 void DarkModeManager::NotifyDarkModeUpdate(const int32_t userId, const bool isDarkMode)
66 {
67 SettingDataManager& manager = SettingDataManager::GetInstance();
68 std::lock_guard lock(darkModeStatesMutex_);
69 const DarkModeState& state = darkModeStates_[userId];
70 if (isDarkMode) {
71 if (state.settingMode == DARK_MODE_ALWAYS_LIGHT || state.settingMode == DARK_MODE_INVALID) {
72 LOGI("notify change to always dark, userId: %{public}d", userId);
73 manager.SetStringValue(SETTING_DARK_MODE_MODE, std::to_string(DARK_MODE_ALWAYS_DARK), userId);
74 } // else no need to change
75 } else {
76 if (state.settingMode == DARK_MODE_ALWAYS_DARK || state.settingMode == DARK_MODE_INVALID) {
77 LOGI("notify change to always light, userId: %{public}d", userId);
78 manager.SetStringValue(SETTING_DARK_MODE_MODE, std::to_string(DARK_MODE_ALWAYS_LIGHT), userId);
79 } // else no need to change
80 }
81 }
82
OnSwitchUser(const int32_t userId)83 ErrCode DarkModeManager::OnSwitchUser(const int32_t userId)
84 {
85 SettingDataManager& manager = SettingDataManager::GetInstance();
86 if (!manager.IsInitialized()) {
87 ErrCode code = manager.Initialize();
88 if (code != ERR_OK || manager.IsInitialized() == false) {
89 LOGE("setting data manager is not initialized");
90 return ERR_NO_INIT;
91 }
92 }
93
94 if (userId <= INVALID_USER_ID || userId == settingDataObserversUserId_) {
95 LOGE("invalid userId: %{public}d", userId);
96 return ERR_INVALID_OPERATION;
97 }
98
99 std::lock_guard lock(settingDataObserversMutex_);
100 if (settingDataObserversUserId_ != INVALID_USER_ID) {
101 LOGI("clear timers and unregister observers for userId: %{public}d", settingDataObserversUserId_);
102 alarmTimerManager_.ClearTimerByUserId(settingDataObserversUserId_);
103 UnregisterSettingDataObserversLocked(settingDataObserversUserId_);
104 settingDataObserversUserId_ = INVALID_USER_ID;
105 }
106
107 ErrCode code = RegisterSettingDataObserversLocked(userId);
108 settingDataObserversUserId_ = userId;
109 return code;
110 }
111
RestartTimer()112 ErrCode DarkModeManager::RestartTimer()
113 {
114 std::lock_guard lock(darkModeStatesMutex_);
115 DarkModeMode mode = darkModeStates_[settingDataObserversUserId_].settingMode;
116 if (mode != DARK_MODE_CUSTOM_AUTO) {
117 LOGD("no need to restart timer.");
118 return ERR_OK;
119 }
120
121 int32_t startTime = darkModeStates_[settingDataObserversUserId_].settingStartTime;
122 int32_t endTime = darkModeStates_[settingDataObserversUserId_].settingEndTime;
123 if (AlarmTimerManager::IsWithinTimeInterval(startTime, endTime)) {
124 OnChangeDarkMode(DARK_MODE_ALWAYS_DARK, settingDataObserversUserId_);
125 } else {
126 OnChangeDarkMode(DARK_MODE_ALWAYS_LIGHT, settingDataObserversUserId_);
127 }
128 return alarmTimerManager_.RestartAllTimer();
129 }
130
Dump()131 void DarkModeManager::Dump()
132 {
133 {
134 std::lock_guard observersGuard(settingDataObserversMutex_);
135 LOGD("settingData observers size: %{public}zu, userId: %{public}d",
136 settingDataObservers_.size(), settingDataObserversUserId_);
137 }
138
139 std::lock_guard stateGuard(darkModeStatesMutex_);
140 LOGD("darkModeStates size: %{public}zu", darkModeStates_.size());
141 for (const auto& state : darkModeStates_) {
142 LOGD("userId: %{public}d, mode: %{public}d, start: %{public}d, end: %{public}d",
143 state.first, state.second.settingMode, state.second.settingStartTime, state.second.settingEndTime);
144 }
145
146 alarmTimerManager_.Dump();
147 }
148
LoadSettingDataObserversCallback()149 void DarkModeManager::LoadSettingDataObserversCallback()
150 {
151 std::lock_guard lock(settingDataObserversMutex_);
152 settingDataObservers_.clear();
153 settingDataObservers_.emplace_back(SETTING_DARK_MODE_MODE, [&](const std::string& key, int32_t userId) {
154 SettingDataDarkModeModeUpdateFunc(key, userId);
155 });
156 settingDataObservers_.emplace_back(SETTING_DARK_MODE_START_TIME, [&](const std::string& key, int32_t userId) {
157 SettingDataDarkModeStartTimeUpdateFunc(key, userId);
158 });
159 settingDataObservers_.emplace_back(SETTING_DARK_MODE_END_TIME, [&](const std::string& key, int32_t userId) {
160 SettingDataDarkModeEndTimeUpdateFunc(key, userId);
161 });
162 }
163
RegisterSettingDataObserversLocked(const int32_t userId) const164 ErrCode DarkModeManager::RegisterSettingDataObserversLocked(const int32_t userId) const
165 {
166 SettingDataManager& manager = SettingDataManager::GetInstance();
167 size_t count = 0;
168 for (const auto& observer : settingDataObservers_) {
169 if (manager.RegisterObserver(observer.first, observer.second, userId) != ERR_OK) {
170 count++;
171 }
172 }
173 if (count != 0) {
174 LOGE("setting data observers are not all initialized");
175 return ERR_NO_INIT;
176 }
177 LOGD("setting data observers are all initialized");
178 return ERR_OK;
179 }
180
UnregisterSettingDataObserversLocked(const int32_t userId) const181 void DarkModeManager::UnregisterSettingDataObserversLocked(const int32_t userId) const
182 {
183 SettingDataManager& manager = SettingDataManager::GetInstance();
184 for (const auto& observer : settingDataObservers_) {
185 manager.UnregisterObserver(observer.first, userId);
186 }
187 }
188
SettingDataDarkModeModeUpdateFunc(const std::string & key,const int32_t userId)189 void DarkModeManager::SettingDataDarkModeModeUpdateFunc(const std::string& key, const int32_t userId)
190 {
191 SettingDataManager& manager = SettingDataManager::GetInstance();
192 int32_t value = DARK_MODE_INVALID;
193 ErrCode code = manager.GetInt32ValueStrictly(key, value, userId);
194 if (code != ERR_OK) {
195 LOGE("get dark mode value failed, key: %{public}s, userId: %{public}d, code: %{public}d, set to default",
196 key.c_str(), userId, code);
197 value = DARK_MODE_INVALID;
198 }
199 if (value < DARK_MODE_INVALID || value >= DARK_MODE_SIZE) {
200 LOGE("dark mode value is invalid, key: %{public}s, userId: %{public}d, value: %{public}d, set to default",
201 key.c_str(), userId, value);
202 value = DARK_MODE_INVALID;
203 }
204
205 auto mode = static_cast<DarkModeMode>(value);
206 std::lock_guard lock(darkModeStatesMutex_);
207 LOGI("dark mode change, key: %{public}s, userId: %{public}d, from %{public}d to %{public}d",
208 key.c_str(), userId, darkModeStates_[userId].settingMode, value);
209 darkModeStates_[userId].settingMode = mode;
210 bool isDarkMode = false;
211 OnStateChangeLocked(userId, true, isDarkMode);
212 }
213
SettingDataDarkModeStartTimeUpdateFunc(const std::string & key,const int32_t userId)214 void DarkModeManager::SettingDataDarkModeStartTimeUpdateFunc(const std::string& key, const int32_t userId)
215 {
216 SettingDataManager& manager = SettingDataManager::GetInstance();
217 int32_t value = -1;
218 manager.GetInt32ValueStrictly(key, value, userId);
219 std::lock_guard lock(darkModeStatesMutex_);
220 LOGI("dark mode start time change, key: %{public}s, userId: %{public}d, from %{public}d to %{public}d",
221 key.c_str(), userId, darkModeStates_[userId].settingStartTime, value);
222 darkModeStates_[userId].settingStartTime = value;
223 bool isDarkMode = false;
224 OnStateChangeLocked(userId, true, isDarkMode);
225 }
226
SettingDataDarkModeEndTimeUpdateFunc(const std::string & key,const int32_t userId)227 void DarkModeManager::SettingDataDarkModeEndTimeUpdateFunc(const std::string& key, const int32_t userId)
228 {
229 SettingDataManager& manager = SettingDataManager::GetInstance();
230 int32_t value = -1;
231 manager.GetInt32ValueStrictly(key, value, userId);
232 std::lock_guard lock(darkModeStatesMutex_);
233 LOGI("dark mode end time change, key: %{public}s, userId: %{public}d, from %{public}d to %{public}d",
234 key.c_str(), userId, darkModeStates_[userId].settingEndTime, value);
235 darkModeStates_[userId].settingEndTime = value;
236 bool isDarkMode = false;
237 OnStateChangeLocked(userId, true, isDarkMode);
238 }
239
OnStateChangeLocked(const int32_t userId,const bool needUpdateCallback,bool & isDarkMode)240 ErrCode DarkModeManager::OnStateChangeLocked(const int32_t userId, const bool needUpdateCallback, bool& isDarkMode)
241 {
242 ErrCode code = ERR_OK;
243 DarkModeState& state = darkModeStates_[userId];
244 switch (state.settingMode) {
245 case DARK_MODE_ALWAYS_LIGHT:
246 case DARK_MODE_ALWAYS_DARK:
247 code = OnStateChangeToAllDayMode(userId, state.settingMode, needUpdateCallback, isDarkMode);
248 break;
249 case DARK_MODE_CUSTOM_AUTO:
250 code = OnStateChangeToCustomAutoMode(userId, state, needUpdateCallback, isDarkMode);
251 break;
252 default:
253 // do nothing
254 code = ERR_INVALID_OPERATION;
255 break;
256 }
257 return code;
258 }
259
OnStateChangeToAllDayMode(const int32_t userId,const DarkModeMode darkMode,const bool needUpdateCallback,bool & isDarkMode)260 ErrCode DarkModeManager::OnStateChangeToAllDayMode(
261 const int32_t userId, const DarkModeMode darkMode, const bool needUpdateCallback, bool &isDarkMode)
262 {
263 alarmTimerManager_.ClearTimerByUserId(userId);
264 isDarkMode = darkMode == DARK_MODE_ALWAYS_DARK;
265 if (needUpdateCallback) {
266 OnChangeDarkMode(darkMode, userId);
267 }
268 return ERR_OK;
269 }
270
OnStateChangeToCustomAutoMode(const int32_t userId,const DarkModeState & state,const bool needUpdateCallback,bool & isDarkMode)271 ErrCode DarkModeManager::OnStateChangeToCustomAutoMode(
272 const int32_t userId, const DarkModeState& state, const bool needUpdateCallback, bool &isDarkMode)
273 {
274 ErrCode code = CreateOrUpdateTimers(state.settingStartTime, state.settingEndTime, userId);
275 if (code != ERR_OK) {
276 alarmTimerManager_.ClearTimerByUserId(userId);
277 return code;
278 }
279 DarkModeMode mode = DARK_MODE_INVALID;
280 if (AlarmTimerManager::IsWithinTimeInterval(state.settingStartTime, state.settingEndTime)) {
281 isDarkMode = true;
282 mode = DARK_MODE_ALWAYS_DARK;
283 } else {
284 isDarkMode = false;
285 mode = DARK_MODE_ALWAYS_LIGHT;
286 }
287
288 if (needUpdateCallback) {
289 OnChangeDarkMode(mode, userId);
290 }
291 return ERR_OK;
292 }
293
OnChangeDarkMode(const DarkModeMode mode,const int32_t userId) const294 void DarkModeManager::OnChangeDarkMode(const DarkModeMode mode, const int32_t userId) const
295 {
296 if (!updateCallback_) {
297 LOGE("no update callback, mode: %{public}d, userId: %{public}d", mode, userId);
298 return;
299 }
300 updateCallback_(mode == DARK_MODE_ALWAYS_DARK, userId);
301 }
302
CreateOrUpdateTimers(int32_t startTime,int32_t endTime,int32_t userId)303 ErrCode DarkModeManager::CreateOrUpdateTimers(int32_t startTime, int32_t endTime, int32_t userId)
304 {
305 auto callbackSetDark = [startTime, endTime, userId]() {
306 LOGI("timer callback, startTime: %{public}d, endTime: %{public}d, userId: %{public}d",
307 startTime, endTime, userId);
308 ErrCode code = GetInstance().CheckTimerCallbackParams(startTime, endTime, userId);
309 if (code != ERR_OK) {
310 LOGE("timer callback, params check failed: %{public}d", code);
311 return;
312 }
313 GetInstance().OnChangeDarkMode(DARK_MODE_ALWAYS_DARK, userId);
314 };
315
316 auto callbackSetLight = [startTime, endTime, userId]() {
317 LOGI("timer callback, startTime: %{public}d, endTime: %{public}d, userId: %{public}d",
318 startTime, endTime, userId);
319 ErrCode code = GetInstance().CheckTimerCallbackParams(startTime, endTime, userId);
320 if (code != ERR_OK) {
321 LOGE("timer callback, params check failed: %{public}d", code);
322 return;
323 }
324 GetInstance().OnChangeDarkMode(DARK_MODE_ALWAYS_LIGHT, userId);
325 };
326
327 return alarmTimerManager_.SetScheduleTime(startTime, endTime, userId, callbackSetDark, callbackSetLight);
328 }
329
CheckTimerCallbackParams(const int32_t startTime,const int32_t endTime,const int32_t userId)330 ErrCode DarkModeManager::CheckTimerCallbackParams(const int32_t startTime, const int32_t endTime, const int32_t userId)
331 {
332 std::lock_guard lock(darkModeStatesMutex_);
333 DarkModeState& state = darkModeStates_[userId];
334 if (state.settingMode != DARK_MODE_CUSTOM_AUTO) {
335 LOGE("timer callback, param wrong, setting mode: %{public}d", state.settingMode);
336 return ERR_INVALID_OPERATION;
337 }
338 if (state.settingStartTime != startTime) {
339 LOGE("timer callback, param wrong, startTime: %{public}d, setting: %{public}d",
340 startTime, state.settingStartTime);
341 return ERR_INVALID_OPERATION;
342 }
343 if (state.settingEndTime != endTime) {
344 LOGE("timer callback, param wrong, endTime: %{public}d, setting: %{public}d", endTime, state.settingEndTime);
345 return ERR_INVALID_OPERATION;
346 }
347 return ERR_OK;
348 }
349 } // namespace OHOS::ArkUi::UiAppearance
350