1 /*
2  * Copyright (c) 2022 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 "ui_appearance_ability.h"
17 
18 #include <string>
19 
20 #include "accesstoken_kit.h"
21 #include "common_event_manager.h"
22 #include "common_event_support.h"
23 #include "dark_mode_manager.h"
24 #include "global_configuration_key.h"
25 #include "ipc_skeleton.h"
26 #include "iservice_registry.h"
27 #include "matching_skills.h"
28 #include "os_account_manager.h"
29 #include "syspara/parameter.h"
30 #include "system_ability_definition.h"
31 #include "ui_appearance_log.h"
32 
33 namespace {
34 static const std::string LIGHT = "light";
35 static const std::string DARK = "dark";
36 static const std::string BASE_SCALE = "1";
37 static const std::string PERSIST_DARKMODE_KEY = "persist.ace.darkmode";
38 static const std::string PERMISSION_UPDATE_CONFIGURATION = "ohos.permission.UPDATE_CONFIGURATION";
39 // current default accountId = 0, will change when have more user.
40 static const std::string FONT_SCAL_FOR_USER0 = "persist.sys.font_scale_for_user0";
41 static const std::string FONT_Weight_SCAL_FOR_USER0 = "persist.sys.font_wght_scale_for_user0";
42 
43 static const std::string PERSIST_DARKMODE_KEY_FOR_NONE = "persist.ace.darkmode.";
44 static const std::string FONT_SCAL_FOR_NONE = "persist.sys.font_scale_for_user.";
45 static const std::string FONT_WEIGHT_SCAL_FOR_NONE = "persist.sys.font_wght_scale_for_user.";
46 
47 static const std::string FIRST_INITIALIZATION = "persist.uiAppearance.first_initialization";
48 const static int32_t USER100 = 100;
49 const static std::string FIRST_UPGRADE = "1";
50 const static std::string NOT_FIRST_UPGRADE = "0";
51 } // namespace
52 
53 namespace OHOS {
54 namespace ArkUi::UiAppearance {
55 
UiAppearanceEventSubscriber(const EventFwk::CommonEventSubscribeInfo & subscriberInfo,const std::function<void (const int32_t)> & userSwitchCallback)56 UiAppearanceEventSubscriber::UiAppearanceEventSubscriber(
57     const EventFwk::CommonEventSubscribeInfo& subscriberInfo,
58     const std::function<void(const int32_t)>& userSwitchCallback): EventFwk::CommonEventSubscriber(subscriberInfo),
59     userSwitchCallback_(userSwitchCallback)
60 {}
61 
OnReceiveEvent(const EventFwk::CommonEventData & data)62 void UiAppearanceEventSubscriber::OnReceiveEvent(const EventFwk::CommonEventData& data)
63 {
64     const AAFwk::Want& want = data.GetWant();
65     std::string action = want.GetAction();
66     LOGI("action:%{public}s", action.c_str());
67 
68     if (action == EventFwk::CommonEventSupport::COMMON_EVENT_USER_SWITCHED) {
69         if (userSwitchCallback_ != nullptr) {
70             userSwitchCallback_(data.GetCode());
71         }
72     } else if (action == EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED) {
73         TimeChangeCallback();
74     } else if (action == EventFwk::CommonEventSupport::COMMON_EVENT_TIMEZONE_CHANGED) {
75         TimeChangeCallback();
76     } else if (action == EventFwk::CommonEventSupport::COMMON_EVENT_BOOT_COMPLETED) {
77         BootCompetedCallback();
78     }
79 }
80 
TimeChangeCallback()81 void UiAppearanceEventSubscriber::TimeChangeCallback()
82 {
83     DarkModeManager::GetInstance().RestartTimer();
84 }
85 
BootCompetedCallback()86 void UiAppearanceEventSubscriber::BootCompetedCallback()
87 {
88     std::call_once(bootCompleteFlag_, [] () {
89         std::vector<int32_t> ids;
90         AccountSA::OsAccountManager::QueryActiveOsAccountIds(ids);
91         int32_t userId;
92         if (ids.empty()) {
93             LOGE("no active user.");
94             userId = USER100;
95         } else {
96             userId = ids[0];
97         }
98         DarkModeManager &manager = DarkModeManager::GetInstance();
99         manager.OnSwitchUser(userId);
100         bool isDarkMode = false;
101         manager.LoadUserSettingData(userId, true, isDarkMode);
102     });
103 }
104 
105 REGISTER_SYSTEM_ABILITY_BY_ID(UiAppearanceAbility, ARKUI_UI_APPEARANCE_SERVICE_ID, true);
106 
UiAppearanceAbility(int32_t saId,bool runOnCreate)107 UiAppearanceAbility::UiAppearanceAbility(int32_t saId, bool runOnCreate) : SystemAbility(saId, runOnCreate) {}
108 
GetAppManagerInstance()109 sptr<AppExecFwk::IAppMgr> UiAppearanceAbility::GetAppManagerInstance()
110 {
111     sptr<ISystemAbilityManager> systemAbilityManager =
112         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
113     if (systemAbilityManager == nullptr) {
114         LOGE("Getting systemAbilityManager failed.");
115         return nullptr;
116     }
117 
118     sptr<IRemoteObject> appObject = systemAbilityManager->GetSystemAbility(APP_MGR_SERVICE_ID);
119     if (appObject == nullptr) {
120         LOGE("Get systemAbility failed.");
121         return nullptr;
122     }
123 
124     sptr<AppExecFwk::IAppMgr> systemAbility = iface_cast<AppExecFwk::IAppMgr>(appObject);
125     if (systemAbility == nullptr) {
126         LOGE("Get AppMgrProxy from SA failed.");
127         return nullptr;
128     }
129     return systemAbility;
130 }
131 
VerifyAccessToken(const std::string & permissionName)132 bool UiAppearanceAbility::VerifyAccessToken(const std::string& permissionName)
133 {
134     auto callerToken = IPCSkeleton::GetCallingTokenID();
135     int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerToken, permissionName);
136     if (ret == Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
137         return true;
138     }
139     LOGE("permission %{private}s denied, callerToken : %{public}u", permissionName.c_str(), callerToken);
140     return false;
141 }
142 
OnStart()143 void UiAppearanceAbility::OnStart()
144 {
145     bool res = Publish(this); // SA registers with SAMGR
146     if (!res) {
147         LOGE("publish failed.");
148         return;
149     }
150 
151     LOGI("AddSystemAbilityListener start.");
152     AddSystemAbilityListener(APP_MGR_SERVICE_ID);
153     return;
154 }
155 
OnStop()156 void UiAppearanceAbility::OnStop()
157 {
158     LOGI("UiAppearanceAbility SA stop.");
159 }
160 
GetUserIds()161 std::vector<int32_t> UiAppearanceAbility::GetUserIds()
162 {
163     std::vector<AccountSA::OsAccountInfo> infos;
164     auto errCode = AccountSA::OsAccountManager::QueryAllCreatedOsAccounts(infos);
165     if (errCode != 0) {
166         LOGW("QueryAllCreatedOsAccounts error: %{public}d.", errCode);
167         return {};
168     }
169     std::vector<int32_t> ids;
170     for (const auto& info : infos) {
171         ids.push_back(info.GetLocalId());
172     }
173     return ids;
174 }
175 
DoCompatibleProcess()176 void UiAppearanceAbility::DoCompatibleProcess()
177 {
178     LOGI("DoCompatibleProcess");
179     auto getOldParam = [this](const std::string& paramName, std::string& result) {
180         return GetParameterWrap(paramName, result);
181     };
182 
183     auto isParamAllreadaySetted = [this](const std::string& paramName) {
184         std::string value;
185         return GetParameterWrap(paramName, value);
186     };
187 
188     const std::vector<int32_t> userIds = GetUserIds();
189     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
190     std::string darkMode = LIGHT;
191     if (getOldParam(PERSIST_DARKMODE_KEY, darkMode)) {
192         for (auto id : userIds) {
193             if (isParamAllreadaySetted(DarkModeParamAssignUser(id))) {
194                 continue;
195             }
196             SetParameterWrap(DarkModeParamAssignUser(id), darkMode);
197             LOGI("userId:%{public}d set darkMode %{public}s", id, darkMode.c_str());
198         }
199     }
200     std::string fontSize = BASE_SCALE;
201     if (getOldParam(FONT_SCAL_FOR_USER0, fontSize)) {
202         for (auto id : userIds) {
203             if (isParamAllreadaySetted(FontScaleParamAssignUser(id))) {
204                 continue;
205             }
206             SetParameterWrap(FontScaleParamAssignUser(id), fontSize);
207             LOGI("userId:%{public}d set fontSize %{public}s", id, fontSize.c_str());
208         }
209     }
210     std::string fontWeightSize = BASE_SCALE;
211     if (getOldParam(FONT_Weight_SCAL_FOR_USER0, fontWeightSize)) {
212         for (auto id : userIds) {
213             if (isParamAllreadaySetted(FontWeightScaleParamAssignUser(id))) {
214                 continue;
215             }
216             SetParameterWrap(FontWeightScaleParamAssignUser(id), fontWeightSize);
217             LOGI("userId:%{public}d set fontWeightSize %{public}s", id, fontWeightSize.c_str());
218         }
219     }
220     SetParameterWrap(FIRST_INITIALIZATION, "0");
221     isNeedDoCompatibleProcess_ = false;
222 }
223 
DoInitProcess()224 void UiAppearanceAbility::DoInitProcess()
225 {
226     LOGI("DoInitProcess");
227     const std::vector<int32_t> userIds = GetUserIds();
228     for (auto userId : userIds) {
229         std::string darkValue = LIGHT;
230         GetParameterWrap(DarkModeParamAssignUser(userId), darkValue);
231 
232         std::string fontSize = BASE_SCALE;
233         GetParameterWrap(FontScaleParamAssignUser(userId), fontSize);
234 
235         std::string fontWeight = BASE_SCALE;
236         GetParameterWrap(FontWeightScaleParamAssignUser(userId), fontWeight);
237 
238         UiAppearanceParam tmpParam;
239         tmpParam.darkMode = darkValue == DARK ? DarkMode::ALWAYS_DARK : DarkMode::ALWAYS_LIGHT;
240         tmpParam.fontScale = fontSize;
241         tmpParam.fontWeightScale = fontWeight;
242         usersParam_[userId] = tmpParam;
243         LOGI("init userId:%{public}d, darkMode:%{public}s, fontSize:%{public}s, fontWeight:%{public}s", userId,
244             darkValue.c_str(), fontSize.c_str(), fontWeight.c_str());
245     }
246     isInitializationFinished_ = true;
247 }
248 
UpdateCurrentUserConfiguration(const int32_t userId,const bool isForceUpdate)249 void UiAppearanceAbility::UpdateCurrentUserConfiguration(const int32_t userId, const bool isForceUpdate)
250 {
251     UiAppearanceParam tmpParam = usersParam_[userId];
252     AppExecFwk::Configuration config;
253     config.AddItem(
254         AAFwk::GlobalConfigurationKey::SYSTEM_COLORMODE, tmpParam.darkMode == DarkMode::ALWAYS_DARK ? DARK : LIGHT);
255     config.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_FONT_SIZE_SCALE, tmpParam.fontScale);
256     config.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_FONT_WEIGHT_SCALE, tmpParam.fontWeightScale);
257 
258     auto appManagerInstance = GetAppManagerInstance();
259     if (!appManagerInstance) {
260         LOGE("GetAppManagerInstance error userId:%{public}d", userId);
261         return;
262     }
263 
264     if (isForceUpdate ||
265         userSwitchUpdateConfigurationOnceFlag_.find(userId) == userSwitchUpdateConfigurationOnceFlag_.end()) {
266         appManagerInstance->UpdateConfiguration(config, userId);
267         userSwitchUpdateConfigurationOnceFlag_.insert(userId);
268     } else {
269         appManagerInstance->UpdateConfiguration(config, 0);
270     }
271     SetParameterWrap(PERSIST_DARKMODE_KEY, tmpParam.darkMode == DarkMode::ALWAYS_DARK ? DARK : LIGHT);
272     SetParameterWrap(FONT_SCAL_FOR_USER0, tmpParam.fontScale);
273     SetParameterWrap(FONT_Weight_SCAL_FOR_USER0, tmpParam.fontWeightScale);
274     LOGI("update userId:%{public}d configuration:%{public}s", userId, config.GetName().c_str());
275 }
276 
UserSwitchFunc(const int32_t userId)277 void UiAppearanceAbility::UserSwitchFunc(const int32_t userId)
278 {
279     DarkModeManager& manager = DarkModeManager::GetInstance();
280     manager.OnSwitchUser(userId);
281     bool isDarkMode = false;
282     int32_t code = manager.LoadUserSettingData(userId, false, isDarkMode);
283 
284     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
285     if (isNeedDoCompatibleProcess_) {
286         DoCompatibleProcess();
287     }
288     if (!isInitializationFinished_) {
289         DoInitProcess();
290     }
291 
292     bool isForceUpdate = false;
293     if (code == ERR_OK) {
294         DarkMode darkMode = isDarkMode ? ALWAYS_DARK : ALWAYS_LIGHT;
295         if (usersParam_[userId].darkMode != darkMode) {
296             usersParam_[userId].darkMode = darkMode;
297             isForceUpdate = true;
298         }
299     }
300 
301     UpdateCurrentUserConfiguration(userId, isForceUpdate);
302 }
303 
SubscribeCommonEvent()304 void UiAppearanceAbility::SubscribeCommonEvent()
305 {
306     EventFwk::MatchingSkills matchingSkills;
307     matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_BOOT_COMPLETED);
308     matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_USER_SWITCHED);
309     matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED);
310     matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIMEZONE_CHANGED);
311     EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills);
312     subscribeInfo.SetThreadMode(EventFwk::CommonEventSubscribeInfo::COMMON);
313 
314     uiAppearanceEventSubscriber_ = std::make_shared<UiAppearanceEventSubscriber>(
315         subscribeInfo,
316         [this](const int32_t userId) { UserSwitchFunc(userId); });
317     bool subResult = EventFwk::CommonEventManager::SubscribeCommonEvent(uiAppearanceEventSubscriber_);
318     if (!subResult) {
319         LOGW("subscribe user switch event error");
320     }
321 }
322 
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)323 void UiAppearanceAbility::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
324 {
325     if (systemAbilityId != APP_MGR_SERVICE_ID) {
326         return;
327     }
328 
329     auto checkIfFirstUpgrade = [this]() {
330         std::string initFlag = NOT_FIRST_UPGRADE;
331         GetParameterWrap(FIRST_INITIALIZATION, initFlag);
332         if (initFlag == FIRST_UPGRADE) {
333             return true;
334         }
335         return false;
336     };
337     isNeedDoCompatibleProcess_ = checkIfFirstUpgrade();
338     DarkModeManager::GetInstance().Initialize([this](bool isDarkMode, int32_t userId) {
339         UpdateDarkModeCallback(isDarkMode, userId);
340     });
341     SubscribeCommonEvent();
342     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
343     if (isNeedDoCompatibleProcess_ && !GetUserIds().empty()) {
344         DoCompatibleProcess();
345     }
346 
347     if (!isInitializationFinished_ && !GetUserIds().empty()) {
348         DoInitProcess();
349         int32_t userId = USER100;
350         auto errCode = AccountSA::OsAccountManager::GetForegroundOsAccountLocalId(userId);
351         if (errCode != 0) {
352             LOGW("GetForegroundOsAccountLocalId error: %{public}d.", errCode);
353             userId = USER100;
354         }
355         UpdateCurrentUserConfiguration(userId, false);
356     }
357 }
358 
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)359 void UiAppearanceAbility::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
360 {
361     LOGI("systemAbilityId = %{public}d removed.", systemAbilityId);
362 }
363 
GetCallingUserId()364 int32_t UiAppearanceAbility::GetCallingUserId()
365 {
366     const static int32_t UID_TRANSFORM_DIVISOR = 200000;
367 
368     LOGD("CallingUid = %{public}d", OHOS::IPCSkeleton::GetCallingUid());
369     int32_t userId = OHOS::IPCSkeleton::GetCallingUid() / UID_TRANSFORM_DIVISOR;
370     if (userId == 0) {
371         auto errNo = AccountSA::OsAccountManager::GetForegroundOsAccountLocalId(userId);
372         if (errNo != 0) {
373             LOGE("CallingUid = %{public}d, GetForegroundOsAccountLocalId error:%{public}d",
374                 OHOS::IPCSkeleton::GetCallingUid(), errNo);
375             userId = USER100;
376         }
377     }
378     return userId;
379 }
380 
DarkModeParamAssignUser(const int32_t userId)381 std::string UiAppearanceAbility::DarkModeParamAssignUser(const int32_t userId)
382 {
383     return PERSIST_DARKMODE_KEY_FOR_NONE + std::to_string(userId);
384 }
FontScaleParamAssignUser(const int32_t userId)385 std::string UiAppearanceAbility::FontScaleParamAssignUser(const int32_t userId)
386 {
387     return FONT_SCAL_FOR_NONE + std::to_string(userId);
388 }
FontWeightScaleParamAssignUser(const int32_t userId)389 std::string UiAppearanceAbility::FontWeightScaleParamAssignUser(const int32_t userId)
390 {
391     return FONT_WEIGHT_SCAL_FOR_NONE + std::to_string(userId);
392 }
IsUserExist(const int32_t userId)393 bool UiAppearanceAbility::IsUserExist(const int32_t userId)
394 {
395     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
396     return usersParam_.find(userId) != usersParam_.end();
397 }
398 
GetParameterWrap(const std::string & paramName,std::string & value,const std::string & defaultValue)399 bool UiAppearanceAbility::GetParameterWrap(
400     const std::string& paramName, std::string& value, const std::string& defaultValue)
401 {
402     char buf[256] = { 0 };
403     auto res = GetParameter(paramName.c_str(), defaultValue.c_str(), buf, sizeof(buf));
404     if (res <= 0) {
405         LOGE("get parameter %{public}s failed", paramName.c_str());
406         return false;
407     }
408     LOGI("get parameter %{public}s:%{public}s", paramName.c_str(), value.c_str());
409     value = buf;
410     return true;
411 }
GetParameterWrap(const std::string & paramName,std::string & value)412 bool UiAppearanceAbility::GetParameterWrap(const std::string& paramName, std::string& value)
413 {
414     const auto defaultValue = value;
415     return GetParameterWrap(paramName, value, defaultValue);
416 }
SetParameterWrap(const std::string & paramName,const std::string & value)417 bool UiAppearanceAbility::SetParameterWrap(const std::string& paramName, const std::string& value)
418 {
419     auto res = SetParameter(paramName.c_str(), value.c_str());
420     if (res != 0) {
421         LOGE("set parameter %{public}s failed", paramName.c_str());
422         return false;
423     }
424     LOGI("set parameter %{public}s:%{public}s", paramName.c_str(), value.c_str());
425     return true;
426 }
427 
UpdateConfiguration(const AppExecFwk::Configuration & configuration,const int32_t userId)428 bool UiAppearanceAbility::UpdateConfiguration(const AppExecFwk::Configuration& configuration, const int32_t userId)
429 {
430     auto appManagerInstance = GetAppManagerInstance();
431     if (appManagerInstance == nullptr) {
432         LOGE("Get app manager proxy failed.");
433         return false;
434     }
435 
436     LOGI("update Configuration start,userId:%{public}d config = %{public}s.", userId, configuration.GetName().c_str());
437     auto errcode = appManagerInstance->UpdateConfiguration(configuration, userId);
438     if (errcode != 0) {
439         AppExecFwk::Configuration config;
440         auto retVal = appManagerInstance->GetConfiguration(config);
441         if (retVal != 0) {
442             LOGE("get configuration failed, update error, error is %{public}d.", retVal);
443             return false;
444         }
445         std::vector<std::string> diffVe;
446         config.CompareDifferent(diffVe, configuration);
447 
448         if (!diffVe.empty()) {
449             LOGE("update configuration failed, errcode = %{public}d.", errcode);
450             return false;
451         } else {
452             LOGW("uiappearance is different against configuration. Forced to use the configuration, error is "
453                  "%{public}d.",
454                 errcode);
455         }
456     }
457     return true;
458 }
459 
OnSetDarkMode(const int32_t userId,DarkMode mode)460 int32_t UiAppearanceAbility::OnSetDarkMode(const int32_t userId, DarkMode mode)
461 {
462     LOGI("setDarkMode, userId:%{public}d, mode: %{public}d", userId, mode);
463     bool ret = false;
464     std::string paramValue;
465     AppExecFwk::Configuration config;
466     switch (mode) {
467         case ALWAYS_LIGHT: {
468             ret = config.AddItem(
469                 AAFwk::GlobalConfigurationKey::SYSTEM_COLORMODE, AppExecFwk::ConfigurationInner::COLOR_MODE_LIGHT);
470             paramValue.assign(LIGHT);
471             break;
472         }
473         case ALWAYS_DARK: {
474             ret = config.AddItem(
475                 AAFwk::GlobalConfigurationKey::SYSTEM_COLORMODE, AppExecFwk::ConfigurationInner::COLOR_MODE_DARK);
476             paramValue.assign(DARK);
477             break;
478         }
479         default:
480             break;
481     }
482     if (!ret) {
483         LOGE("AddItem failed, mode = %{public}d", mode);
484         return INVALID_ARG;
485     }
486 
487     if (!UpdateConfiguration(config, userId)) {
488         return SYS_ERR;
489     }
490 
491     {
492         std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
493         if (IsUserExist(userId)) {
494             usersParam_[userId].darkMode = mode;
495         } else {
496             UiAppearanceParam tmpParam;
497             tmpParam.darkMode = mode;
498             usersParam_[userId] = tmpParam;
499         }
500     }
501 
502     SetParameterWrap(PERSIST_DARKMODE_KEY, paramValue);
503 
504     // persist to file: etc/para/ui_appearance.para
505     auto isSetPara = SetParameterWrap(DarkModeParamAssignUser(userId), paramValue);
506     if (!isSetPara) {
507         LOGE("set parameter failed");
508         return SYS_ERR;
509     }
510     DarkModeManager::GetInstance().NotifyDarkModeUpdate(userId, mode == ALWAYS_DARK);
511     return SUCCEEDED;
512 }
513 
SetDarkMode(DarkMode mode)514 int32_t UiAppearanceAbility::SetDarkMode(DarkMode mode)
515 {
516     // Verify permissions
517     auto isCallingPerm = VerifyAccessToken(PERMISSION_UPDATE_CONFIGURATION);
518     if (!isCallingPerm) {
519         LOGE("permission verification failed");
520         return PERMISSION_ERR;
521     }
522 
523     auto userId = GetCallingUserId();
524     DarkMode currentDarkMode = ALWAYS_LIGHT;
525     {
526         std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
527         auto it = usersParam_.find(userId);
528         if (it != usersParam_.end()) {
529             currentDarkMode = it->second.darkMode;
530         }
531     }
532     if (mode != currentDarkMode) {
533         return OnSetDarkMode(userId, mode);
534     } else {
535         LOGW("current color mode is %{public}d, no need to change", mode);
536         return SYS_ERR;
537     }
538 }
539 
InitGetDarkMode(const int32_t userId)540 UiAppearanceAbility::DarkMode UiAppearanceAbility::InitGetDarkMode(const int32_t userId)
541 {
542     std::string valueGet = LIGHT;
543 
544     // LIGHT is the default.
545     auto res = GetParameterWrap(DarkModeParamAssignUser(userId), valueGet);
546     if (!res) {
547         return ALWAYS_LIGHT;
548     }
549     if (valueGet == DARK) {
550         LOGI("current color mode is dark.");
551         return ALWAYS_DARK;
552     } else if (valueGet == LIGHT) {
553         LOGI("current color mode is light.");
554         return ALWAYS_LIGHT;
555     }
556     return ALWAYS_LIGHT;
557 }
558 
GetDarkMode()559 int32_t UiAppearanceAbility::GetDarkMode()
560 {
561     auto isCallingPerm = VerifyAccessToken(PERMISSION_UPDATE_CONFIGURATION);
562     if (!isCallingPerm) {
563         LOGE("permission verification failed");
564         return PERMISSION_ERR;
565     }
566     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
567     auto it = usersParam_.find(GetCallingUserId());
568     if (it != usersParam_.end()) {
569         return it->second.darkMode;
570     }
571     return DarkMode::ALWAYS_LIGHT;
572 }
573 
OnSetFontScale(const int32_t userId,std::string & fontScale)574 int32_t UiAppearanceAbility::OnSetFontScale(const int32_t userId, std::string& fontScale)
575 {
576     bool ret = false;
577     AppExecFwk::Configuration config;
578     ret = config.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_FONT_SIZE_SCALE, fontScale);
579     if (!ret) {
580         LOGE("AddItem failed, fontScale = %{public}s", fontScale.c_str());
581         return INVALID_ARG;
582     }
583     if (!UpdateConfiguration(config, userId)) {
584         return SYS_ERR;
585     }
586 
587     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
588     if (IsUserExist(userId)) {
589         usersParam_[userId].fontScale = fontScale;
590     } else {
591         UiAppearanceParam tmpParam;
592         tmpParam.fontScale = fontScale;
593         usersParam_[userId] = tmpParam;
594     }
595 
596     SetParameterWrap(FONT_SCAL_FOR_USER0, fontScale);
597     // persist to file: etc/para/ui_appearance.para
598     auto isSetPara = SetParameterWrap(FontScaleParamAssignUser(userId), fontScale);
599     if (!isSetPara) {
600         LOGE("set parameter failed");
601         return SYS_ERR;
602     }
603     return SUCCEEDED;
604 }
605 
SetFontScale(std::string & fontScale)606 int32_t UiAppearanceAbility::SetFontScale(std::string& fontScale)
607 {
608     // Verify permissions
609     auto isCallingPerm = VerifyAccessToken(PERMISSION_UPDATE_CONFIGURATION);
610     if (!isCallingPerm) {
611         LOGE("permission verification failed");
612         return PERMISSION_ERR;
613     }
614     if (!fontScale.empty()) {
615         return OnSetFontScale(GetCallingUserId(), fontScale);
616     } else {
617         LOGE("current fontScale is empty!");
618     }
619     return SYS_ERR;
620 }
621 
GetFontScale(std::string & fontScale)622 int32_t UiAppearanceAbility::GetFontScale(std::string& fontScale)
623 {
624     auto isCallingPerm = VerifyAccessToken(PERMISSION_UPDATE_CONFIGURATION);
625     if (!isCallingPerm) {
626         LOGE("permission verification failed");
627         return PERMISSION_ERR;
628     }
629     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
630     auto it = usersParam_.find(GetCallingUserId());
631     if (it != usersParam_.end()) {
632         fontScale = it->second.fontScale;
633     } else {
634         fontScale = BASE_SCALE;
635     }
636     LOGD("get font scale :%{public}s", fontScale.c_str());
637     return SUCCEEDED;
638 }
639 
OnSetFontWeightScale(const int32_t userId,std::string & fontWeightScale)640 int32_t UiAppearanceAbility::OnSetFontWeightScale(const int32_t userId, std::string& fontWeightScale)
641 {
642     bool ret = false;
643     AppExecFwk::Configuration config;
644     ret = config.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_FONT_WEIGHT_SCALE, fontWeightScale);
645     if (!ret) {
646         LOGE("AddItem failed, fontWeightScale = %{public}s", fontWeightScale.c_str());
647         return INVALID_ARG;
648     }
649 
650     if (!UpdateConfiguration(config, userId)) {
651         return SYS_ERR;
652     }
653     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
654     if (IsUserExist(userId)) {
655         usersParam_[userId].fontWeightScale = fontWeightScale;
656     } else {
657         UiAppearanceParam tmpParam;
658         tmpParam.fontWeightScale = fontWeightScale;
659         usersParam_[userId] = tmpParam;
660     }
661 
662     SetParameterWrap(FONT_Weight_SCAL_FOR_USER0, fontWeightScale);
663 
664     // persist to file: etc/para/ui_appearance.para
665     auto isSetPara = SetParameterWrap(FontWeightScaleParamAssignUser(userId), fontWeightScale);
666     if (!isSetPara) {
667         LOGE("set parameter failed");
668         return SYS_ERR;
669     }
670     return SUCCEEDED;
671 }
672 
SetFontWeightScale(std::string & fontWeightScale)673 int32_t UiAppearanceAbility::SetFontWeightScale(std::string& fontWeightScale)
674 {
675     // Verify permissions
676     auto isCallingPerm = VerifyAccessToken(PERMISSION_UPDATE_CONFIGURATION);
677     if (!isCallingPerm) {
678         LOGE("permission verification failed");
679         return PERMISSION_ERR;
680     }
681     if (!fontWeightScale.empty()) {
682         return OnSetFontWeightScale(GetCallingUserId(), fontWeightScale);
683     } else {
684         LOGE("current fontWeightScale is empty!");
685     }
686     return SYS_ERR;
687 }
688 
GetFontWeightScale(std::string & fontWeightScale)689 int32_t UiAppearanceAbility::GetFontWeightScale(std::string& fontWeightScale)
690 {
691     auto isCallingPerm = VerifyAccessToken(PERMISSION_UPDATE_CONFIGURATION);
692     if (!isCallingPerm) {
693         LOGE("permission verification failed");
694         return PERMISSION_ERR;
695     }
696     std::unique_lock<std::recursive_mutex> guard(usersParamMutex_);
697     auto it = usersParam_.find(GetCallingUserId());
698     if (it != usersParam_.end()) {
699         fontWeightScale = it->second.fontWeightScale;
700     } else {
701         fontWeightScale = BASE_SCALE;
702     }
703     LOGD("get font weight scale :%{public}s", fontWeightScale.c_str());
704     return SUCCEEDED;
705 }
706 
UpdateDarkModeCallback(const bool isDarkMode,const int32_t userId)707 void UiAppearanceAbility::UpdateDarkModeCallback(const bool isDarkMode, const int32_t userId)
708 {
709     bool ret = false;
710     std::string paramValue;
711     AppExecFwk::Configuration config;
712     if (isDarkMode) {
713         ret = config.AddItem(
714             AAFwk::GlobalConfigurationKey::SYSTEM_COLORMODE, AppExecFwk::ConfigurationInner::COLOR_MODE_DARK);
715         paramValue.assign(DARK);
716     } else {
717         ret = config.AddItem(
718             AAFwk::GlobalConfigurationKey::SYSTEM_COLORMODE, AppExecFwk::ConfigurationInner::COLOR_MODE_LIGHT);
719         paramValue.assign(LIGHT);
720     }
721     if (!ret) {
722         LOGE("AddItem failed, isDarkMode: %{public}d, userId: %{public}d", isDarkMode, userId);
723         return;
724     }
725 
726     if (!UpdateConfiguration(config, userId)) {
727         return;
728     }
729 
730     {
731         std::unique_lock guard(usersParamMutex_);
732         if (IsUserExist(userId)) {
733             usersParam_[userId].darkMode = isDarkMode ? ALWAYS_DARK : ALWAYS_LIGHT;
734         } else {
735             UiAppearanceParam tmpParam;
736             tmpParam.darkMode = isDarkMode ? ALWAYS_DARK : ALWAYS_LIGHT;
737             usersParam_[userId] = tmpParam;
738         }
739     }
740 
741     SetParameterWrap(PERSIST_DARKMODE_KEY, paramValue);
742     if (!SetParameterWrap(DarkModeParamAssignUser(userId), paramValue)) {
743         LOGE("set parameter failed");
744     }
745 }
746 } // namespace ArkUi::UiAppearance
747 } // namespace OHOS
748