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 "i18n_hilog.h"
17 #include "locale_config.h"
18 #include "os_account_manager.h"
19 #include "parameter.h"
20 #include "utils.h"
21 
22 #include "multi_users.h"
23 
24 namespace OHOS {
25 namespace Global {
26 namespace I18n {
27 const std::string MultiUsers::MULTI_USERS_LANGUAGE_KEY = "languageData";
28 const std::string MultiUsers::MULTI_USERS_LOCALE_KEY = "localeData";
29 const std::string MultiUsers::MULTI_USERS_HOUR_KEY = "is24HourData";
30 const std::string MultiUsers::INIT_KEY = "init";
31 const std::string MultiUsers::PREFERENCE_PATH = "/data/service/el1/public/i18n/global/GlobalParamData";
32 const int32_t MultiUsers::DEFAULT_LOCAL_ID = 100;
33 const int MultiUsers::CONFIG_LEN = 128;
34 std::shared_ptr<NativePreferences::Preferences> MultiUsers::preferences = nullptr;
35 
InitMultiUser()36 void MultiUsers::InitMultiUser()
37 {
38     InitPreferences();
39     if (preferences == nullptr) {
40         HILOG_ERROR_I18N("InitMultiUser: InitPreferences failed");
41         return;
42     }
43     bool init = preferences->GetBool(INIT_KEY, false);
44     std::string localId;
45     I18nErrorCode errCode = GetForegroundLocalId(localId);
46     if (errCode != I18nErrorCode::SUCCESS) {
47         HILOG_ERROR_I18N("InitMultiUser: get foreground local id failed");
48         return;
49     }
50     if (!init) {
51         AddUser(localId);
52         preferences->PutBool(INIT_KEY, true);
53         preferences->Flush();
54         HILOG_INFO_I18N("InitMultiUser: init multi user data success");
55     }
56 }
57 
SwitchUser(const std::string& curLocalId)58 void MultiUsers::SwitchUser(const std::string& curLocalId)
59 {
60     if (!IsValidLocalId(curLocalId)) {
61         HILOG_ERROR_I18N("SwitchUser: curLocalId is an invalid LocalId");
62         return;
63     }
64     I18nErrorCode errCode = LoadGlobalParam(curLocalId);
65     if (errCode != I18nErrorCode::SUCCESS) {
66         HILOG_ERROR_I18N("SwitchUser: load global params failed");
67     }
68 }
69 
AddUser(const std::string& localId)70 void MultiUsers::AddUser(const std::string& localId)
71 {
72     if (!IsValidLocalId(localId)) {
73         HILOG_ERROR_I18N("AddUser: localId is invalid");
74         return;
75     }
76     I18nErrorCode errCode = SaveGlobalParam(localId);
77     if (errCode != I18nErrorCode::SUCCESS) {
78         HILOG_ERROR_I18N("AddUser: add global param failed");
79     }
80 }
81 
RemoveUser(const std::string& localId)82 void MultiUsers::RemoveUser(const std::string& localId)
83 {
84     if (!IsValidLocalId(localId)) {
85         HILOG_ERROR_I18N("RemoveUser: localId is invalid");
86         return;
87     }
88     I18nErrorCode errCode = RemoveGlobalParam(localId);
89     if (errCode != I18nErrorCode::SUCCESS) {
90         HILOG_ERROR_I18N("RemoveUser: remove global param failed");
91     }
92 }
93 
GetForegroundLocalId(std::string& localId)94 I18nErrorCode MultiUsers::GetForegroundLocalId(std::string& localId)
95 {
96     int id = 0;
97     int errCode = OHOS::AccountSA::OsAccountManager::GetForegroundOsAccountLocalId(id);
98     if (errCode != 0) {
99         HILOG_ERROR_I18N("GetForegroundLocalId: get foreground locale Id failed, errCode is %{public}d", errCode);
100         return I18nErrorCode::FAILED;
101     }
102     localId = std::to_string(id);
103     return I18nErrorCode::SUCCESS;
104 }
105 
SaveLanguage(const std::string& localId, const std::string& language)106 I18nErrorCode MultiUsers::SaveLanguage(const std::string& localId, const std::string& language)
107 {
108     std::string foregroundLocalId = localId;
109     I18nErrorCode errCode = I18nErrorCode::SUCCESS;
110     if (localId.empty()) {
111         errCode = MultiUsers::GetForegroundLocalId(foregroundLocalId);
112     }
113     if (errCode != I18nErrorCode::SUCCESS) {
114         HILOG_ERROR_I18N("SaveLanguage: get foreground locale Id failed");
115         return I18nErrorCode::FAILED;
116     }
117 
118     errCode =
119         WriteMultiUsersParameter(MULTI_USERS_LANGUAGE_KEY, language, foregroundLocalId, false);
120     if (errCode != I18nErrorCode::SUCCESS) {
121         HILOG_ERROR_I18N("SaveLanguage: save language failed");
122         return I18nErrorCode::FAILED;
123     }
124     return I18nErrorCode::SUCCESS;
125 }
126 
SaveLocale(const std::string& localId, const std::string& locale)127 I18nErrorCode MultiUsers::SaveLocale(const std::string& localId, const std::string& locale)
128 {
129     std::string foregroundLocalId = localId;
130     I18nErrorCode errCode = I18nErrorCode::SUCCESS;
131     if (localId.empty()) {
132         errCode = MultiUsers::GetForegroundLocalId(foregroundLocalId);
133     }
134     if (errCode != I18nErrorCode::SUCCESS) {
135         HILOG_ERROR_I18N("SaveLocale: get foreground locale Id failed");
136         return I18nErrorCode::FAILED;
137     }
138 
139     errCode =
140         WriteMultiUsersParameter(MULTI_USERS_LOCALE_KEY, locale, foregroundLocalId, false);
141     if (errCode != I18nErrorCode::SUCCESS) {
142         HILOG_ERROR_I18N("SaveLocale: save locale failed");
143         return I18nErrorCode::FAILED;
144     }
145     return I18nErrorCode::SUCCESS;
146 }
147 
SaveIs24Hour(const std::string& localId, const std::string& is24Hour)148 I18nErrorCode MultiUsers::SaveIs24Hour(const std::string& localId, const std::string& is24Hour)
149 {
150     std::string foregroundLocalId = localId;
151     I18nErrorCode errCode = I18nErrorCode::SUCCESS;
152     if (localId.empty()) {
153         errCode = MultiUsers::GetForegroundLocalId(foregroundLocalId);
154     }
155     if (errCode != I18nErrorCode::SUCCESS) {
156         HILOG_ERROR_I18N("SaveLanguage: get foreground locale Id failed");
157         return I18nErrorCode::FAILED;
158     }
159     errCode =
160         WriteMultiUsersParameter(MULTI_USERS_HOUR_KEY, is24Hour, foregroundLocalId, false);
161     if (errCode != I18nErrorCode::SUCCESS) {
162         HILOG_ERROR_I18N("SaveIs24Hour: save is24Hour failed");
163         return I18nErrorCode::FAILED;
164     }
165     return I18nErrorCode::SUCCESS;
166 }
167 
SaveGlobalParam(const std::string& localId)168 I18nErrorCode MultiUsers::SaveGlobalParam(const std::string& localId)
169 {
170     std::string language = ReadSystemParameter(LocaleConfig::GetLanguageKey().data(), CONFIG_LEN);
171     std::string locale = ReadSystemParameter(LocaleConfig::GetLocaleKey().data(), CONFIG_LEN);
172     std::string is24Hour = ReadSystemParameter(LocaleConfig::GetHourKey().data(), CONFIG_LEN);
173     I18nErrorCode errCode = SaveLanguage(localId, language);
174     if (errCode != I18nErrorCode::SUCCESS) {
175         HILOG_ERROR_I18N("SaveGlobalParam: save language failed");
176         return I18nErrorCode::FAILED;
177     }
178     errCode = SaveLocale(localId, locale);
179     if (errCode != I18nErrorCode::SUCCESS) {
180         HILOG_ERROR_I18N("SaveGlobalParam: save locale failed");
181         return I18nErrorCode::FAILED;
182     }
183     errCode = SaveIs24Hour(localId, is24Hour);
184     if (errCode != I18nErrorCode::SUCCESS) {
185         HILOG_ERROR_I18N("SaveGlobalParam: save is24Hour failed");
186         return I18nErrorCode::FAILED;
187     }
188     return I18nErrorCode::SUCCESS;
189 }
190 
LoadGlobalParam(const std::string& localId)191 I18nErrorCode MultiUsers::LoadGlobalParam(const std::string& localId)
192 {
193     std::string newLocale = ReadMultiUsersParameter(MULTI_USERS_LOCALE_KEY, localId);
194     if (!newLocale.empty() && SetParameter(LocaleConfig::GetLocaleKey().data(), newLocale.data()) != 0) {
195         HILOG_ERROR_I18N("LoadGlobalParam: set locale failed");
196         return I18nErrorCode::FAILED;
197     }
198 
199     std::string newLanguage = ReadMultiUsersParameter(MULTI_USERS_LANGUAGE_KEY, localId);
200     if (!newLanguage.empty() && LocaleConfig::SetSystemLanguage(newLanguage) != 0) {
201         HILOG_ERROR_I18N("LoadGlobalParam: set language failed");
202         return I18nErrorCode::FAILED;
203     }
204 
205     std::string newIs24Hour = ReadMultiUsersParameter(MULTI_USERS_HOUR_KEY, localId);
206     if (!newIs24Hour.empty() && LocaleConfig::Set24HourClock(newIs24Hour) != 0) {
207         HILOG_ERROR_I18N("LoadGlobalParam: set is24Hour failed");
208         return I18nErrorCode::FAILED;
209     }
210     return I18nErrorCode::SUCCESS;
211 }
212 
RemoveGlobalParam(const std::string& localId)213 I18nErrorCode MultiUsers::RemoveGlobalParam(const std::string& localId)
214 {
215     I18nErrorCode errCode = WriteMultiUsersParameter(MULTI_USERS_LANGUAGE_KEY, "", localId, true);
216     if (errCode != I18nErrorCode::SUCCESS) {
217         HILOG_ERROR_I18N("RemoveGlobalParam: remove language failed");
218         return I18nErrorCode::FAILED;
219     }
220 
221     errCode = WriteMultiUsersParameter(MULTI_USERS_LOCALE_KEY, "", localId, true);
222     if (errCode != I18nErrorCode::SUCCESS) {
223         HILOG_ERROR_I18N("RemoveGlobalParam: remove locale failed");
224         return I18nErrorCode::FAILED;
225     }
226 
227     errCode = WriteMultiUsersParameter(MULTI_USERS_HOUR_KEY, "", localId, true);
228     if (errCode != I18nErrorCode::SUCCESS) {
229         HILOG_ERROR_I18N("RemoveGlobalParam: remove is24Hour failed");
230         return I18nErrorCode::FAILED;
231     }
232     return I18nErrorCode::SUCCESS;
233 }
234 
ReadMultiUsersParameter(const std::string& paramKey, const std::string& localId)235 std::string MultiUsers::ReadMultiUsersParameter(const std::string& paramKey, const std::string& localId)
236 {
237     std::string param = GetParamFromPreferences(paramKey);
238     if (param.empty()) {
239         return "";
240     }
241     std::vector<std::string> multiUsersParam;
242     Split(param, ";", multiUsersParam);
243     for (auto& userParam : multiUsersParam) {
244         std::vector<std::string> content;
245         Split(userParam, ":", content);
246         // 2 is number of param
247         if (content.size() != 2) {
248             continue;
249         }
250         if (content[0] == localId) {
251             return content[1];
252         }
253     }
254     return "";
255 }
256 
WriteMultiUsersParameter(const std::string& paramKey, const std::string& paramValue, const std::string& localId, bool isDel)257 I18nErrorCode MultiUsers::WriteMultiUsersParameter(const std::string& paramKey, const std::string& paramValue,
258     const std::string& localId, bool isDel)
259 {
260     std::string param = GetParamFromPreferences(paramKey);
261     std::vector<std::string> multiUsersParam;
262     Split(param, ";", multiUsersParam);
263     std::vector<std::string> newMultiUsersParam;
264     bool userIsExist = false;
265     for (auto& userParam : multiUsersParam) {
266         std::vector<std::string> content;
267         Split(userParam, ":", content);
268         // 2 is number of param
269         if (content.size() != 2) {
270             continue;
271         }
272         std::string userLocalId = content[0];
273         if (!isDel && userLocalId == localId) {
274             content[1] = paramValue;
275             Merge(content, ":", userParam);
276             userIsExist = true;
277         }
278         newMultiUsersParam.emplace_back(userParam);
279         if (isDel && userLocalId == localId) {
280             newMultiUsersParam.pop_back();
281         }
282     }
283     if (!isDel && !userIsExist) {
284         newMultiUsersParam.push_back(localId + ":" + paramValue);
285     }
286     std::string newParam;
287     Merge(newMultiUsersParam, ";", newParam);
288     if (SetParamFromPreferences(paramKey, newParam) != I18nErrorCode::SUCCESS) {
289         HILOG_ERROR_I18N("WriteMultiUsersParameter: set param %{public}s failed", paramKey.c_str());
290         return I18nErrorCode::FAILED;
291     }
292     return I18nErrorCode::SUCCESS;
293 }
294 
IsValidLocalId(const std::string& localId)295 bool MultiUsers::IsValidLocalId(const std::string& localId)
296 {
297     if (std::atoi(localId.c_str()) < DEFAULT_LOCAL_ID) {
298         HILOG_ERROR_I18N("IsValidLocalId: invalid local ID");
299         return false;
300     }
301     return true;
302 }
303 
InitPreferences()304 void MultiUsers::InitPreferences()
305 {
306     if (preferences == nullptr) {
307         HILOG_INFO_I18N("InitPreferences: preferences Init");
308         OHOS::NativePreferences::Options opt(PREFERENCE_PATH);
309         int status;
310         preferences = NativePreferences::PreferencesHelper::GetPreferences(opt, status);
311         if (status != 0) {
312             HILOG_ERROR_I18N("InitPreferences: get preferences failed");
313             preferences = nullptr;
314         }
315     }
316 }
317 
GetParamFromPreferences(const std::string& paramKey)318 std::string MultiUsers::GetParamFromPreferences(const std::string& paramKey)
319 {
320     InitPreferences();
321     if (preferences == nullptr) {
322         HILOG_ERROR_I18N("GetParamFromPreferences: preferences is nullptr");
323         return "";
324     }
325     return preferences->GetString(paramKey, "");
326 }
327 
SetParamFromPreferences(const std::string& paramKey, const std::string& paramValue)328 I18nErrorCode MultiUsers::SetParamFromPreferences(const std::string& paramKey, const std::string& paramValue)
329 {
330     InitPreferences();
331     if (preferences == nullptr) {
332         HILOG_ERROR_I18N("SetParamFromPreferences: preferences is nullptr");
333         return I18nErrorCode::FAILED;
334     }
335     int status = preferences->PutString(paramKey, paramValue);
336     if (status != 0) {
337         HILOG_ERROR_I18N("SetParamFromPreferences: put param %{public}s failed", paramKey.c_str());
338         return I18nErrorCode::FAILED;
339     }
340     preferences->Flush();
341     return I18nErrorCode::SUCCESS;
342 }
343 } // namespace I18n
344 } // namespace Global
345 } // namespace OHOS
346