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 #ifdef SUPPORT_GRAPHICS
17 #include "app_mgr_client.h"
18 #include "ability_manager_client.h"
19 #include <common_event_manager.h>
20 #include <common_event_publish_info.h>
21 #include <common_event_support.h>
22 #endif
23 #include "i18n_hilog.h"
24 #include "locale_config.h"
25 #include "os_account_manager.h"
26 #include "parameter.h"
27 #include "utils.h"
28
29 #include "multi_users.h"
30
31 namespace OHOS {
32 namespace Global {
33 namespace I18n {
34 const std::string MultiUsers::MULTI_USERS_LANGUAGE_KEY = "languageData";
35 const std::string MultiUsers::MULTI_USERS_LOCALE_KEY = "localeData";
36 const std::string MultiUsers::MULTI_USERS_HOUR_KEY = "is24HourData";
37 const std::string MultiUsers::INIT_KEY = "init";
38 const std::string MultiUsers::PREFERENCE_PATH = "/data/service/el1/public/i18n/global/GlobalParamData";
39 const int32_t MultiUsers::DEFAULT_LOCAL_ID = 100;
40 const int MultiUsers::CONFIG_LEN = 128;
41 std::shared_ptr<NativePreferences::Preferences> MultiUsers::preferences = nullptr;
42
InitMultiUser()43 void MultiUsers::InitMultiUser()
44 {
45 InitPreferences();
46 if (preferences == nullptr) {
47 HILOG_ERROR_I18N("InitMultiUser: InitPreferences failed");
48 return;
49 }
50 bool init = preferences->GetBool(INIT_KEY, false);
51 std::string localId;
52 I18nErrorCode errCode = GetForegroundLocalId(localId);
53 if (errCode != I18nErrorCode::SUCCESS) {
54 HILOG_ERROR_I18N("InitMultiUser: get foreground local id failed");
55 return;
56 }
57 if (!init) {
58 AddUser(localId);
59 preferences->PutBool(INIT_KEY, true);
60 preferences->Flush();
61 HILOG_INFO_I18N("InitMultiUser: init multi user data success");
62 }
63 }
64
SwitchUser(const std::string & curLocalId)65 void MultiUsers::SwitchUser(const std::string& curLocalId)
66 {
67 if (!IsValidLocalId(curLocalId)) {
68 HILOG_ERROR_I18N("SwitchUser: curLocalId is an invalid LocalId");
69 return;
70 }
71 I18nErrorCode errCode = LoadGlobalParam(curLocalId);
72 if (errCode != I18nErrorCode::SUCCESS) {
73 HILOG_ERROR_I18N("SwitchUser: load global params failed");
74 }
75 }
76
AddUser(const std::string & localId)77 void MultiUsers::AddUser(const std::string& localId)
78 {
79 if (!IsValidLocalId(localId)) {
80 HILOG_ERROR_I18N("AddUser: localId is invalid");
81 return;
82 }
83 I18nErrorCode errCode = SaveGlobalParam(localId);
84 if (errCode != I18nErrorCode::SUCCESS) {
85 HILOG_ERROR_I18N("AddUser: add global param failed");
86 }
87 }
88
RemoveUser(const std::string & localId)89 void MultiUsers::RemoveUser(const std::string& localId)
90 {
91 if (!IsValidLocalId(localId)) {
92 HILOG_ERROR_I18N("RemoveUser: localId is invalid");
93 return;
94 }
95 I18nErrorCode errCode = RemoveGlobalParam(localId);
96 if (errCode != I18nErrorCode::SUCCESS) {
97 HILOG_ERROR_I18N("RemoveUser: remove global param failed");
98 }
99 }
100
GetForegroundLocalId(std::string & localId)101 I18nErrorCode MultiUsers::GetForegroundLocalId(std::string& localId)
102 {
103 int id = 0;
104 int errCode = OHOS::AccountSA::OsAccountManager::GetForegroundOsAccountLocalId(id);
105 if (errCode != 0) {
106 HILOG_ERROR_I18N("GetForegroundLocalId: get foreground locale Id failed, errCode is %{public}d", errCode);
107 return I18nErrorCode::FAILED;
108 }
109 localId = std::to_string(id);
110 return I18nErrorCode::SUCCESS;
111 }
112
SaveLanguage(const std::string & localId,const std::string & language)113 I18nErrorCode MultiUsers::SaveLanguage(const std::string& localId, const std::string& language)
114 {
115 std::string foregroundLocalId = localId;
116 I18nErrorCode errCode = I18nErrorCode::SUCCESS;
117 if (localId.empty()) {
118 errCode = MultiUsers::GetForegroundLocalId(foregroundLocalId);
119 }
120 if (errCode != I18nErrorCode::SUCCESS) {
121 HILOG_ERROR_I18N("SaveLanguage: get foreground locale Id failed");
122 return I18nErrorCode::FAILED;
123 }
124
125 errCode =
126 WriteMultiUsersParameter(MULTI_USERS_LANGUAGE_KEY, language, foregroundLocalId, false);
127 if (errCode != I18nErrorCode::SUCCESS) {
128 HILOG_ERROR_I18N("SaveLanguage: save language failed");
129 return I18nErrorCode::FAILED;
130 }
131 return I18nErrorCode::SUCCESS;
132 }
133
SaveLocale(const std::string & localId,const std::string & locale)134 I18nErrorCode MultiUsers::SaveLocale(const std::string& localId, const std::string& locale)
135 {
136 std::string foregroundLocalId = localId;
137 I18nErrorCode errCode = I18nErrorCode::SUCCESS;
138 if (localId.empty()) {
139 errCode = MultiUsers::GetForegroundLocalId(foregroundLocalId);
140 }
141 if (errCode != I18nErrorCode::SUCCESS) {
142 HILOG_ERROR_I18N("SaveLocale: get foreground locale Id failed");
143 return I18nErrorCode::FAILED;
144 }
145
146 errCode =
147 WriteMultiUsersParameter(MULTI_USERS_LOCALE_KEY, locale, foregroundLocalId, false);
148 if (errCode != I18nErrorCode::SUCCESS) {
149 HILOG_ERROR_I18N("SaveLocale: save locale failed");
150 return I18nErrorCode::FAILED;
151 }
152 return I18nErrorCode::SUCCESS;
153 }
154
SaveIs24Hour(const std::string & localId,const std::string & is24Hour)155 I18nErrorCode MultiUsers::SaveIs24Hour(const std::string& localId, const std::string& is24Hour)
156 {
157 std::string foregroundLocalId = localId;
158 I18nErrorCode errCode = I18nErrorCode::SUCCESS;
159 if (localId.empty()) {
160 errCode = MultiUsers::GetForegroundLocalId(foregroundLocalId);
161 }
162 if (errCode != I18nErrorCode::SUCCESS) {
163 HILOG_ERROR_I18N("SaveLanguage: get foreground locale Id failed");
164 return I18nErrorCode::FAILED;
165 }
166 errCode =
167 WriteMultiUsersParameter(MULTI_USERS_HOUR_KEY, is24Hour, foregroundLocalId, false);
168 if (errCode != I18nErrorCode::SUCCESS) {
169 HILOG_ERROR_I18N("SaveIs24Hour: save is24Hour failed");
170 return I18nErrorCode::FAILED;
171 }
172 return I18nErrorCode::SUCCESS;
173 }
174
GetLanguageFromUserId(int32_t userId)175 std::string MultiUsers::GetLanguageFromUserId(int32_t userId)
176 {
177 std::string localId = std::to_string(userId);
178 std::string locale = ReadMultiUsersParameter(MULTI_USERS_LOCALE_KEY, localId);
179 std::string language = ReadMultiUsersParameter(MULTI_USERS_LANGUAGE_KEY, localId);
180 if (locale.empty() || language.empty()) {
181 HILOG_ERROR_I18N("MultiUsers::GetLanguageFromUserId: Get language from userId %{public}d failed, "
182 "locale %{public}s, language %{public}s.", userId, locale.c_str(), language.c_str());
183 return LocaleConfig::GetEffectiveLanguage();
184 }
185 return LocaleConfig::ComputeEffectiveLanguage(locale, language);
186 }
187
GetSystemLanguageFromUserId(int32_t userId)188 std::string MultiUsers::GetSystemLanguageFromUserId(int32_t userId)
189 {
190 if (userId == -1) {
191 return LocaleConfig::GetSystemLanguage();
192 }
193 std::string localId = std::to_string(userId);
194 std::string language = ReadMultiUsersParameter(MULTI_USERS_LANGUAGE_KEY, localId);
195 if (language.empty()) {
196 HILOG_ERROR_I18N("MultiUsers::GetSystemLanguageFromUserId: Get language failed.");
197 return LocaleConfig::GetSystemLanguage();
198 }
199 return language;
200 }
201
GetSystemLocaleFromUserId(int32_t userId)202 std::string MultiUsers::GetSystemLocaleFromUserId(int32_t userId)
203 {
204 if (userId == -1) {
205 return LocaleConfig::GetEffectiveLocale();
206 }
207 std::string localId = std::to_string(userId);
208 std::string locale = ReadMultiUsersParameter(MULTI_USERS_LOCALE_KEY, localId);
209 if (locale.empty()) {
210 HILOG_ERROR_I18N("MultiUsers::GetSystemLocaleFromUserId: Get locale failed.");
211 return LocaleConfig::GetEffectiveLocale();
212 }
213 return locale;
214 }
215
SaveGlobalParam(const std::string & localId)216 I18nErrorCode MultiUsers::SaveGlobalParam(const std::string& localId)
217 {
218 std::string language = LocaleConfig::GetSystemLanguage();
219 std::string locale = LocaleConfig::GetEffectiveLocale();
220 std::string is24Hour = ReadSystemParameter(LocaleConfig::HOUR_KEY.c_str(), CONFIG_LEN);
221 if (is24Hour.empty()) {
222 HILOG_ERROR_I18N("SaveIs24Hour: Get is24Hour failed");
223 return I18nErrorCode::FAILED;
224 }
225 I18nErrorCode errCode = SaveLanguage(localId, language);
226 if (errCode != I18nErrorCode::SUCCESS) {
227 HILOG_ERROR_I18N("SaveGlobalParam: save language failed");
228 return I18nErrorCode::FAILED;
229 }
230 errCode = SaveLocale(localId, locale);
231 if (errCode != I18nErrorCode::SUCCESS) {
232 HILOG_ERROR_I18N("SaveGlobalParam: save locale failed");
233 return I18nErrorCode::FAILED;
234 }
235 errCode = SaveIs24Hour(localId, is24Hour);
236 if (errCode != I18nErrorCode::SUCCESS) {
237 HILOG_ERROR_I18N("SaveGlobalParam: save is24Hour failed");
238 return I18nErrorCode::FAILED;
239 }
240 return I18nErrorCode::SUCCESS;
241 }
242
LoadGlobalParam(const std::string & localId)243 I18nErrorCode MultiUsers::LoadGlobalParam(const std::string& localId)
244 {
245 std::string newLocale = ReadMultiUsersParameter(MULTI_USERS_LOCALE_KEY, localId);
246 if (!newLocale.empty() && SetParameter(LocaleConfig::LOCALE_KEY.c_str(), newLocale.c_str()) != 0) {
247 HILOG_ERROR_I18N("LoadGlobalParam: set locale failed");
248 return I18nErrorCode::FAILED;
249 }
250
251 std::string newLanguage = ReadMultiUsersParameter(MULTI_USERS_LANGUAGE_KEY, localId);
252 if (!newLanguage.empty() && SetParameter(LocaleConfig::LANGUAGE_KEY.c_str(), newLanguage.c_str()) != 0) {
253 HILOG_ERROR_I18N("LoadGlobalParam: set language failed");
254 return I18nErrorCode::FAILED;
255 }
256
257 std::string newIs24Hour = ReadMultiUsersParameter(MULTI_USERS_HOUR_KEY, localId);
258 if (!newIs24Hour.empty() && SetParameter(LocaleConfig::HOUR_KEY.c_str(), newIs24Hour.c_str()) != 0) {
259 HILOG_ERROR_I18N("LoadGlobalParam: set is24Hour failed");
260 return I18nErrorCode::FAILED;
261 }
262 #ifdef SUPPORT_GRAPHICS
263 int32_t status = 0;
264 int32_t userId = ConvertString2Int(localId, status);
265 if (status == -1) {
266 HILOG_ERROR_I18N("LoadGlobalParam: convert userId failed");
267 return I18nErrorCode::FAILED;
268 }
269 std::string effectiveLanguage = LocaleConfig::ComputeEffectiveLanguage(newLocale, newLanguage);
270 UpdateConfiguration(newLocale, effectiveLanguage, newIs24Hour, userId);
271 return PublishCommonEvent(userId);
272 #endif
273 return I18nErrorCode::SUCCESS;
274 }
275
RemoveGlobalParam(const std::string & localId)276 I18nErrorCode MultiUsers::RemoveGlobalParam(const std::string& localId)
277 {
278 I18nErrorCode errCode = WriteMultiUsersParameter(MULTI_USERS_LANGUAGE_KEY, "", localId, true);
279 if (errCode != I18nErrorCode::SUCCESS) {
280 HILOG_ERROR_I18N("RemoveGlobalParam: remove language failed");
281 return I18nErrorCode::FAILED;
282 }
283
284 errCode = WriteMultiUsersParameter(MULTI_USERS_LOCALE_KEY, "", localId, true);
285 if (errCode != I18nErrorCode::SUCCESS) {
286 HILOG_ERROR_I18N("RemoveGlobalParam: remove locale failed");
287 return I18nErrorCode::FAILED;
288 }
289
290 errCode = WriteMultiUsersParameter(MULTI_USERS_HOUR_KEY, "", localId, true);
291 if (errCode != I18nErrorCode::SUCCESS) {
292 HILOG_ERROR_I18N("RemoveGlobalParam: remove is24Hour failed");
293 return I18nErrorCode::FAILED;
294 }
295
296 return I18nErrorCode::SUCCESS;
297 }
298
ReadMultiUsersParameter(const std::string & paramKey,const std::string & localId)299 std::string MultiUsers::ReadMultiUsersParameter(const std::string& paramKey, const std::string& localId)
300 {
301 std::string param = GetParamFromPreferences(paramKey);
302 if (param.empty()) {
303 return "";
304 }
305 std::vector<std::string> multiUsersParam;
306 Split(param, ";", multiUsersParam);
307 for (auto& userParam : multiUsersParam) {
308 std::vector<std::string> content;
309 Split(userParam, ":", content);
310 // 2 is number of param
311 if (content.size() != 2) {
312 continue;
313 }
314 if (content[0] == localId) {
315 return content[1];
316 }
317 }
318 return "";
319 }
320
WriteMultiUsersParameter(const std::string & paramKey,const std::string & paramValue,const std::string & localId,bool isDel)321 I18nErrorCode MultiUsers::WriteMultiUsersParameter(const std::string& paramKey, const std::string& paramValue,
322 const std::string& localId, bool isDel)
323 {
324 std::string param = GetParamFromPreferences(paramKey);
325 std::vector<std::string> multiUsersParam;
326 Split(param, ";", multiUsersParam);
327 std::vector<std::string> newMultiUsersParam;
328 bool userIsExist = false;
329 for (auto& userParam : multiUsersParam) {
330 std::vector<std::string> content;
331 Split(userParam, ":", content);
332 // 2 is number of param
333 if (content.size() != 2) {
334 continue;
335 }
336 std::string userLocalId = content[0];
337 if (!isDel && userLocalId == localId) {
338 content[1] = paramValue;
339 Merge(content, ":", userParam);
340 userIsExist = true;
341 }
342 newMultiUsersParam.emplace_back(userParam);
343 if (isDel && userLocalId == localId) {
344 newMultiUsersParam.pop_back();
345 }
346 }
347 if (!isDel && !userIsExist) {
348 newMultiUsersParam.push_back(localId + ":" + paramValue);
349 }
350 std::string newParam;
351 Merge(newMultiUsersParam, ";", newParam);
352 if (SetParamFromPreferences(paramKey, newParam) != I18nErrorCode::SUCCESS) {
353 HILOG_ERROR_I18N("WriteMultiUsersParameter: set param %{public}s failed", paramKey.c_str());
354 return I18nErrorCode::FAILED;
355 }
356 return I18nErrorCode::SUCCESS;
357 }
358
IsValidLocalId(const std::string & localId)359 bool MultiUsers::IsValidLocalId(const std::string& localId)
360 {
361 if (std::atoi(localId.c_str()) < DEFAULT_LOCAL_ID) {
362 HILOG_ERROR_I18N("IsValidLocalId: invalid local ID");
363 return false;
364 }
365 return true;
366 }
367
InitPreferences()368 void MultiUsers::InitPreferences()
369 {
370 if (preferences == nullptr) {
371 HILOG_INFO_I18N("InitPreferences: preferences Init");
372 OHOS::NativePreferences::Options opt(PREFERENCE_PATH);
373 int status = 0;
374 preferences = NativePreferences::PreferencesHelper::GetPreferences(opt, status);
375 if (status != 0) {
376 HILOG_ERROR_I18N("InitPreferences: get preferences failed");
377 preferences = nullptr;
378 }
379 }
380 }
381
GetParamFromPreferences(const std::string & paramKey)382 std::string MultiUsers::GetParamFromPreferences(const std::string& paramKey)
383 {
384 InitPreferences();
385 if (preferences == nullptr) {
386 HILOG_ERROR_I18N("GetParamFromPreferences: preferences is nullptr");
387 return "";
388 }
389 return preferences->GetString(paramKey, "");
390 }
391
SetParamFromPreferences(const std::string & paramKey,const std::string & paramValue)392 I18nErrorCode MultiUsers::SetParamFromPreferences(const std::string& paramKey, const std::string& paramValue)
393 {
394 InitPreferences();
395 if (preferences == nullptr) {
396 HILOG_ERROR_I18N("SetParamFromPreferences: preferences is nullptr");
397 return I18nErrorCode::FAILED;
398 }
399 int status = preferences->PutString(paramKey, paramValue);
400 if (status != 0) {
401 HILOG_ERROR_I18N("SetParamFromPreferences: put param %{public}s failed", paramKey.c_str());
402 return I18nErrorCode::FAILED;
403 }
404 preferences->Flush();
405 return I18nErrorCode::SUCCESS;
406 }
407
408 #ifdef SUPPORT_GRAPHICS
UpdateConfiguration(const std::string & locale,const std::string & language,const std::string & is24Hour,int32_t userId)409 void MultiUsers::UpdateConfiguration(const std::string& locale, const std::string& language,
410 const std::string& is24Hour, int32_t userId)
411 {
412 AppExecFwk::Configuration configuration;
413 configuration.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_LOCALE, locale);
414 configuration.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_LANGUAGE, language);
415 configuration.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_HOUR, is24Hour);
416 auto appMgrClient = std::make_unique<AppExecFwk::AppMgrClient>();
417
418 AppExecFwk::AppMgrResultCode status = appMgrClient->UpdateConfiguration(configuration, userId);
419 if (status != AppExecFwk::AppMgrResultCode::RESULT_OK) {
420 HILOG_ERROR_I18N("MultiUsers::UpdateConfiguration: Update configuration userId %{public}d failed.", userId);
421 return;
422 }
423 HILOG_INFO_I18N("MultiUsers::UpdateConfiguration: Update configuration userId %{public}d success.", userId);
424 }
425
PublishCommonEvent(int32_t userId)426 I18nErrorCode MultiUsers::PublishCommonEvent(int32_t userId)
427 {
428 OHOS::AAFwk::Want localeChangeWant;
429 localeChangeWant.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_LOCALE_CHANGED);
430 OHOS::EventFwk::CommonEventData localeChangeEvent(localeChangeWant);
431 if (!OHOS::EventFwk::CommonEventManager::PublishCommonEventAsUser(localeChangeEvent, userId)) {
432 HILOG_ERROR_I18N("MultiUsers::PublishCommonEvent: Failed to publish locale change event, userId %{public}d.",
433 userId);
434 return I18nErrorCode::PUBLISH_COMMON_EVENT_FAILED;
435 }
436
437 OHOS::AAFwk::Want is24HourChangeWant;
438 is24HourChangeWant.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_LOCALE_CHANGED);
439 OHOS::EventFwk::CommonEventData is24HourChangeEvent(is24HourChangeWant);
440 is24HourChangeEvent.SetData(LocaleConfig::HOUR_EVENT_DATA);
441 if (!OHOS::EventFwk::CommonEventManager::PublishCommonEventAsUser(is24HourChangeEvent, userId)) {
442 HILOG_ERROR_I18N("MultiUsers::PublishCommonEvent: Failed to publish is24Hour change event, userId %{public}d.",
443 userId);
444 return I18nErrorCode::PUBLISH_COMMON_EVENT_FAILED;
445 }
446
447 HILOG_INFO_I18N("MultiUsers::PublishCommonEvent: Publish event finished, userId %{public}d.", userId);
448 return I18nErrorCode::SUCCESS;
449 }
450 #endif
451 } // namespace I18n
452 } // namespace Global
453 } // namespace OHOS
454