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