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
24namespace OHOS {
25namespace Global {
26namespace I18n {
27const std::string MultiUsers::MULTI_USERS_LANGUAGE_KEY = "languageData";
28const std::string MultiUsers::MULTI_USERS_LOCALE_KEY = "localeData";
29const std::string MultiUsers::MULTI_USERS_HOUR_KEY = "is24HourData";
30const std::string MultiUsers::INIT_KEY = "init";
31const std::string MultiUsers::PREFERENCE_PATH = "/data/service/el1/public/i18n/global/GlobalParamData";
32const int32_t MultiUsers::DEFAULT_LOCAL_ID = 100;
33const int MultiUsers::CONFIG_LEN = 128;
34std::shared_ptr<NativePreferences::Preferences> MultiUsers::preferences = nullptr;
35
36void 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
58void 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
70void 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
82void 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
94I18nErrorCode 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
106I18nErrorCode 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
127I18nErrorCode 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
148I18nErrorCode 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
168I18nErrorCode 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
191I18nErrorCode 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
213I18nErrorCode 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
235std::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
257I18nErrorCode 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
295bool 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
304void 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
318std::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
328I18nErrorCode 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