• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "ime_enabled_info_manager.h"
17 
18 #include <algorithm>
19 #include <chrono>
20 #include <iomanip>
21 #include <set>
22 #include <sstream>
23 
24 #include "enable_upgrade_manager.h"
25 #include "ime_info_inquirer.h"
26 namespace OHOS {
27 namespace MiscServices {
28 using namespace std::chrono;
GetInstance()29 ImeEnabledInfoManager &ImeEnabledInfoManager::GetInstance()
30 {
31     static ImeEnabledInfoManager instance;
32     return instance;
33 }
34 
~ImeEnabledInfoManager()35 ImeEnabledInfoManager::~ImeEnabledInfoManager()
36 {
37 }
38 
SetCurrentImeStatusChangedHandler(CurrentImeStatusChangedHandler handler)39 void ImeEnabledInfoManager::SetCurrentImeStatusChangedHandler(CurrentImeStatusChangedHandler handler)
40 {
41     if (currentImeStatusChangedHandler_ != nullptr) {
42         return;
43     }
44     currentImeStatusChangedHandler_ = std::move(handler);
45 }
46 
SetEventHandler(const std::shared_ptr<AppExecFwk::EventHandler> & eventHandler)47 void ImeEnabledInfoManager::SetEventHandler(const std::shared_ptr<AppExecFwk::EventHandler> &eventHandler)
48 {
49     serviceHandler_ = eventHandler;
50 }
51 
Init(const std::map<int32_t,std::vector<FullImeInfo>> & fullImeInfos)52 int32_t ImeEnabledInfoManager::Init(const std::map<int32_t, std::vector<FullImeInfo>> &fullImeInfos)
53 {
54     std::lock_guard<std::mutex> lock(operateLock_);
55     if (!SettingsDataUtils::GetInstance().IsDataShareReady()) {
56         IMSA_HILOGE("data share not ready.");
57         return ErrorCode::ERROR_ENABLE_IME;
58     }
59     IMSA_HILOGI("run in, user num:%{public}zu.", fullImeInfos.size());
60     for (const auto &fullImeInfo : fullImeInfos) {
61         auto cfg = GetEnabledCache(fullImeInfo.first);
62         if (!cfg.enabledInfos.empty()) {
63             continue;
64         }
65         UpdateEnabledCfgCache(fullImeInfo.first, fullImeInfo.second);
66     }
67     return ErrorCode::NO_ERROR;
68 }
69 
Switch(int32_t userId,const std::vector<FullImeInfo> & imeInfos)70 int32_t ImeEnabledInfoManager::Switch(int32_t userId, const std::vector<FullImeInfo> &imeInfos)
71 {
72     std::lock_guard<std::mutex> lock(operateLock_);
73     IMSA_HILOGI("userId:%{public}d", userId);
74     auto cfg = GetEnabledCache(userId);
75     if (!cfg.enabledInfos.empty()) {
76         UpdateGlobalEnabledTable(userId, cfg); // user switch, replace global table by user table
77         return ErrorCode::NO_ERROR;
78     }
79     if (!SettingsDataUtils::GetInstance().IsDataShareReady()) {
80         IMSA_HILOGE("data share not ready.");
81         return ErrorCode::ERROR_ENABLE_IME;
82     }
83     return UpdateEnabledCfgCache(userId, imeInfos);
84 }
85 
UpdateEnabledCfgCache(int32_t userId,const std::vector<FullImeInfo> & imeInfos)86 int32_t ImeEnabledInfoManager::UpdateEnabledCfgCache(int32_t userId, const std::vector<FullImeInfo> &imeInfos)
87 {
88     IMSA_HILOGI("run in, userId:%{public}d", userId);
89     ImeEnabledCfg cfg;
90     auto ret = GetEnabledCfg(userId, imeInfos, cfg);
91     if (ret != ErrorCode::NO_ERROR) {
92         IMSA_HILOGE("userId:%{public}d get enabled cfg failed:%{public}d.", userId, ret);
93         return ret;
94     }
95     return UpdateEnabledCfgCache(userId, cfg);
96 }
97 
Delete(int32_t userId)98 int32_t ImeEnabledInfoManager::Delete(int32_t userId)
99 {
100     ClearEnabledCache(userId);
101     return ErrorCode::NO_ERROR;
102 }
103 
Add(int32_t userId,const FullImeInfo & imeInfo)104 int32_t ImeEnabledInfoManager::Add(int32_t userId, const FullImeInfo &imeInfo)
105 {
106     std::lock_guard<std::mutex> lock(operateLock_);
107     IMSA_HILOGI("userId:%{public}d, bundleName:%{public}s", userId, imeInfo.prop.name.c_str());
108     if (imeInfo.prop.name == ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName) {
109         IMSA_HILOGI("[%{public}d,%{public}s] is sys ime, deal in init or user add.", userId, imeInfo.prop.name.c_str());
110         return ErrorCode::NO_ERROR;
111     }
112     ImeEnabledCfg enabledCfg;
113     auto ret = GetEnabledCacheWithCorrect(userId, enabledCfg);
114     if (ret != ErrorCode::NO_ERROR) {
115         return ret;
116     }
117     auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
118         [&imeInfo](const ImeEnabledInfo &info) { return imeInfo.prop.name == info.bundleName; });
119     if (iter != enabledCfg.enabledInfos.end()) {
120         IMSA_HILOGI("%{public}d/%{public}s install after uninstall", userId, imeInfo.prop.name.c_str());
121         if (iter->extensionName.empty()) {
122             IMSA_HILOGW(
123                 "%{public}d/%{public}s uninstall before upgrade install again.", userId, imeInfo.prop.name.c_str());
124             iter->extensionName = imeInfo.prop.id;
125             return UpdateEnabledCfgCache(userId, enabledCfg);
126         }
127         return ErrorCode::NO_ERROR;
128     }
129     enabledCfg.enabledInfos.emplace_back(imeInfo.prop.name, imeInfo.prop.id,
130         ComputeEnabledStatus(imeInfo.prop.name, ImeInfoInquirer::GetInstance().GetSystemConfig().initEnabledState));
131     return UpdateEnabledCfgCache(userId, enabledCfg);
132 }
133 
Delete(int32_t userId,const std::string & bundleName)134 int32_t ImeEnabledInfoManager::Delete(int32_t userId, const std::string &bundleName)
135 {
136     std::lock_guard<std::mutex> lock(operateLock_);
137     IMSA_HILOGI("enable Delete run in, userId:%{public}d, bundleName:%{public}s", userId, bundleName.c_str());
138     ImeEnabledCfg enabledCfg;
139     auto ret = GetEnabledCacheWithCorrect(userId, enabledCfg);
140     if (ret != ErrorCode::NO_ERROR) {
141         IMSA_HILOGE("user:%{public}d get enabledCfg failed:%{public}d.", userId, ret);
142         return ret;
143     }
144     if (!IsCurrentIme(bundleName, enabledCfg.enabledInfos)) {
145         return ErrorCode::NO_ERROR;
146     }
147     IMSA_HILOGW("current ime %{public}d/%{public}s uninstall", userId, bundleName.c_str());
148     ModCurrentIme(enabledCfg.enabledInfos);
149     ret = UpdateEnabledCfgCache(userId, enabledCfg);
150     if (ret != ErrorCode::NO_ERROR) {
151         IMSA_HILOGE("%{public}d update enable info failed:%{public}d.", userId, ret);
152     }
153     NotifyCurrentImeStatusChanged(userId, bundleName, EnabledStatus::DISABLED);
154     return ErrorCode::NO_ERROR;
155 }
156 
CheckUpdate(int32_t userId,const std::string & bundleName,const std::string & extensionName,EnabledStatus status)157 int32_t ImeEnabledInfoManager::CheckUpdate(
158     int32_t userId, const std::string &bundleName, const std::string &extensionName, EnabledStatus status)
159 {
160     IMSA_HILOGI("update info:[%{public}d, %{public}s, %{public}s, %{public}d].", userId, bundleName.c_str(),
161         extensionName.c_str(), static_cast<int32_t>(status));
162     if (bundleName.empty() || status < EnabledStatus::DISABLED || status > EnabledStatus::FULL_EXPERIENCE_MODE) {
163         IMSA_HILOGE(
164             "%{public}d/%{public}s/%{public}d abnormal.", userId, bundleName.c_str(), static_cast<int32_t>(status));
165         return ErrorCode::ERROR_BAD_PARAMETERS;
166     }
167     if (extensionName.empty()) {
168         if (!ImeInfoInquirer::GetInstance().IsInputMethod(userId, bundleName)) {
169             IMSA_HILOGE(
170                 "[%{public}d, %{public}s, %{public}s] not an ime.", userId, bundleName.c_str(), extensionName.c_str());
171             return ErrorCode::ERROR_IME_NOT_FOUND;
172         }
173     } else {
174         if (!ImeInfoInquirer::GetInstance().IsImeInstalled(userId, bundleName, extensionName)) {
175             IMSA_HILOGE(
176                 "[%{public}d, %{public}s, %{public}s] not an ime.", userId, bundleName.c_str(), extensionName.c_str());
177             return ErrorCode::ERROR_IME_NOT_FOUND;
178         }
179     }
180     auto defaultIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
181     if (defaultIme.bundleName == bundleName) {
182         IMSA_HILOGW("%{public}d/%{public}s/%{public}s is sys ime, do not set this mode.", userId, bundleName.c_str(),
183             extensionName.c_str());
184         return ErrorCode::ERROR_OPERATE_SYSTEM_IME;
185     }
186     return ErrorCode::NO_ERROR;
187 }
188 // LCOV_EXCL_START
Update(int32_t userId,const std::string & bundleName,const std::string & extensionName,EnabledStatus status)189 int32_t ImeEnabledInfoManager::Update(
190     int32_t userId, const std::string &bundleName, const std::string &extensionName, EnabledStatus status)
191 {
192     std::lock_guard<std::mutex> lock(operateLock_);
193     auto ret = CheckUpdate(userId, bundleName, extensionName, status);
194     if (ret != ErrorCode::NO_ERROR) {
195         return ret;
196     }
197     ImeEnabledCfg enabledCfg;
198     ret = GetEnabledCacheWithCorrect(userId, bundleName, extensionName, enabledCfg);
199     if (ret != ErrorCode::NO_ERROR) {
200         return ErrorCode::ERROR_ENABLE_IME;
201     }
202     auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
203         [&bundleName](const ImeEnabledInfo &info) { return bundleName == info.bundleName; });
204     if (iter == enabledCfg.enabledInfos.end()) {
205         IMSA_HILOGE("[%{public}d, %{public}s] not find.", userId, bundleName.c_str());
206         return ErrorCode::ERROR_IME_NOT_FOUND;
207     }
208     if (iter->enabledStatus == status) {
209         return ErrorCode::NO_ERROR;
210     }
211     iter->enabledStatus = status;
212     iter->stateUpdateTime =
213         std::to_string(duration_cast<std::chrono::milliseconds>(system_clock::now().time_since_epoch()).count());
214     auto isCurrentIme = IsCurrentIme(bundleName, enabledCfg.enabledInfos);
215     if (isCurrentIme && status == EnabledStatus::DISABLED) {
216         ModCurrentIme(enabledCfg.enabledInfos);
217     }
218     ret = UpdateEnabledCfgCache(userId, enabledCfg);
219     if (ret != ErrorCode::NO_ERROR) {
220         IMSA_HILOGE("%{public}d update enable info failed:%{public}d.", userId, ret);
221         return ErrorCode::ERROR_ENABLE_IME;
222     }
223     if (isCurrentIme) {
224         NotifyCurrentImeStatusChanged(userId, bundleName, iter->enabledStatus);
225     }
226     return ErrorCode::NO_ERROR;
227 }
228 // LCOV_EXCL_STOP
GetEnabledState(int32_t userId,const std::string & bundleName,EnabledStatus & status)229 int32_t ImeEnabledInfoManager::GetEnabledState(int32_t userId, const std::string &bundleName, EnabledStatus &status)
230 {
231     std::lock_guard<std::mutex> lock(operateLock_);
232     IMSA_HILOGD("[%{public}d, %{public}s] start.", userId, bundleName.c_str());
233     if (bundleName.empty()) {
234         IMSA_HILOGW("%{public}d bundleName is empty.", userId);
235         return ErrorCode::ERROR_BAD_PARAMETERS;
236     }
237     if (bundleName == ImeInfoInquirer::GetInstance().GetSystemSpecialIme()) {
238         status = EnabledStatus::FULL_EXPERIENCE_MODE;
239         return ErrorCode::NO_ERROR;
240     }
241     auto ret = GetEnabledStateInner(userId, bundleName, status);
242     if (bundleName == ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName &&
243         (ret != ErrorCode::NO_ERROR || status == EnabledStatus::DISABLED)) {
244         IMSA_HILOGI("mod sys ime enabledStatus.");
245         status = EnabledStatus::BASIC_MODE;
246     }
247     if (ret != ErrorCode::NO_ERROR) {
248         IMSA_HILOGE("%{public}d %{public}s get status failed %{public}d.", userId, bundleName.c_str(), ret);
249         return ErrorCode::ERROR_ENABLE_IME;
250     }
251     return ErrorCode::NO_ERROR;
252 }
253 
GetEnabledStates(int32_t userId,std::vector<Property> & props)254 int32_t ImeEnabledInfoManager::GetEnabledStates(int32_t userId, std::vector<Property> &props)
255 {
256     std::lock_guard<std::mutex> lock(operateLock_);
257     if (props.empty()) {
258         return ErrorCode::ERROR_BAD_PARAMETERS;
259     }
260     auto ret = GetEnabledStatesInner(userId, props);
261     for (auto &prop : props) {
262         if (prop.name == ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName &&
263             prop.status == EnabledStatus::DISABLED) {
264             IMSA_HILOGI("mod sys ime enabledStatus.");
265             prop.status = EnabledStatus::BASIC_MODE;
266             break;
267         }
268     }
269     if (ret != ErrorCode::NO_ERROR) {
270         return ErrorCode::ERROR_ENABLE_IME;
271     }
272     return ErrorCode::NO_ERROR;
273 }
274 
GetEnabledStateInner(int32_t userId,const std::string & bundleName,EnabledStatus & status)275 int32_t ImeEnabledInfoManager::GetEnabledStateInner(
276     int32_t userId, const std::string &bundleName, EnabledStatus &status)
277 {
278     IMSA_HILOGD("%{public}d/%{public}s get enabledStatus start.", userId, bundleName.c_str());
279     ImeEnabledCfg enabledCfg;
280     auto ret = GetEnabledCacheWithCorrect(userId, bundleName, "", enabledCfg);
281     if (ret != ErrorCode::NO_ERROR) {
282         return ErrorCode::ERROR_ENABLE_IME;
283     }
284     auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
285         [&bundleName](const ImeEnabledInfo &info) { return bundleName == info.bundleName; });
286     if (iter == enabledCfg.enabledInfos.end()) {
287         IMSA_HILOGE("not find [%{public}d, %{public}s] in enableCfg.", userId, bundleName.c_str());
288         return ErrorCode::ERROR_ENABLE_IME;
289     }
290     status = iter->enabledStatus;
291     IMSA_HILOGD("%{public}d/%{public}s get enabledStatus end:%{public}d.", userId, bundleName.c_str(),
292         static_cast<int32_t>(status));
293     return ErrorCode::NO_ERROR;
294 }
295 
GetEnabledStatesInner(int32_t userId,std::vector<Property> & props)296 int32_t ImeEnabledInfoManager::GetEnabledStatesInner(int32_t userId, std::vector<Property> &props)
297 {
298     IMSA_HILOGD("%{public}d/%{public}zu get enabledStatus start.", userId, props.size());
299     auto cfg = GetEnabledCache(userId);
300     if (cfg.enabledInfos.empty()) {
301         auto ret = UpdateEnabledCfgCache(userId);
302         if (ret != ErrorCode::NO_ERROR) {
303             IMSA_HILOGE("%{public}d update enable info failed:%{public}d.", userId, ret);
304             return ret;
305         }
306         cfg = GetEnabledCache(userId);
307     }
308     for (auto &prop : props) {
309         auto iter = std::find_if(cfg.enabledInfos.begin(), cfg.enabledInfos.end(),
310             [&prop](const ImeEnabledInfo &info) { return prop.name == info.bundleName; });
311         if (iter == cfg.enabledInfos.end()) {
312             IMSA_HILOGW("%{public}d/%{public}s enable info abnormal.", userId, prop.name.c_str());
313             continue;
314         }
315         prop.status = iter->enabledStatus;
316         IMSA_HILOGD("%{public}d/%{public}s get succeed:%{public}d.", userId, prop.name.c_str(),
317             static_cast<int32_t>(prop.status));
318     }
319     return ErrorCode::NO_ERROR;
320 }
321 
GetEnabledCacheWithCorrect(int32_t userId,ImeEnabledCfg & enabledCfg)322 int32_t ImeEnabledInfoManager::GetEnabledCacheWithCorrect(int32_t userId, ImeEnabledCfg &enabledCfg)
323 {
324     enabledCfg = GetEnabledCache(userId);
325     if (!enabledCfg.enabledInfos.empty()) {
326         return ErrorCode::NO_ERROR;
327     }
328     auto ret = UpdateEnabledCfgCache(userId);
329     if (ret != ErrorCode::NO_ERROR) {
330         IMSA_HILOGE("%{public}d update enable info failed:%{public}d.", userId, ret);
331         return ret;
332     }
333     enabledCfg = GetEnabledCache(userId);
334     return enabledCfg.enabledInfos.empty() ? ErrorCode::ERROR_ENABLE_IME : ErrorCode::NO_ERROR;
335 }
336 
GetEnabledCacheWithCorrect(int32_t userId,const std::string & bundleName,const std::string & extensionName,ImeEnabledCfg & enabledCfg)337 int32_t ImeEnabledInfoManager::GetEnabledCacheWithCorrect(
338     int32_t userId, const std::string &bundleName, const std::string &extensionName, ImeEnabledCfg &enabledCfg)
339 {
340     enabledCfg = GetEnabledCache(userId);
341     auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
342         [&bundleName](const ImeEnabledInfo &info) { return bundleName == info.bundleName; });
343     if (iter != enabledCfg.enabledInfos.end()) {
344         return ErrorCode::NO_ERROR;
345     }
346     auto ret = UpdateEnabledCfgCache(userId);
347     if (ret != ErrorCode::NO_ERROR) {
348         IMSA_HILOGE("%{public}d update enable info failed:%{public}d.", userId, ret);
349         return ret;
350     }
351     enabledCfg = GetEnabledCache(userId);
352     return enabledCfg.enabledInfos.empty() ? ErrorCode::ERROR_ENABLE_IME : ErrorCode::NO_ERROR;
353 }
354 
IsInEnabledCache(int32_t userId,const std::string & bundleName,const std::string & extensionName)355 bool ImeEnabledInfoManager::IsInEnabledCache(
356     int32_t userId, const std::string &bundleName, const std::string &extensionName)
357 {
358     auto cfg = GetEnabledCache(userId);
359     auto iter = std::find_if(cfg.enabledInfos.begin(), cfg.enabledInfos.end(),
360         [&bundleName](const ImeEnabledInfo &info) { return bundleName == info.bundleName; });
361     return iter != cfg.enabledInfos.end();
362 }
363 
SetEnabledCache(int32_t userId,const ImeEnabledCfg & cfg)364 void ImeEnabledInfoManager::SetEnabledCache(int32_t userId, const ImeEnabledCfg &cfg)
365 {
366     std::lock_guard<std::mutex> cgfLock(imeEnabledCfgLock_);
367     imeEnabledCfg_.insert_or_assign(userId, cfg);
368 }
369 
GetEnabledCache(int32_t userId)370 ImeEnabledCfg ImeEnabledInfoManager::GetEnabledCache(int32_t userId)
371 {
372     std::lock_guard<std::mutex> lock(imeEnabledCfgLock_);
373     auto it = imeEnabledCfg_.find(userId);
374     if (it == imeEnabledCfg_.end()) {
375         IMSA_HILOGE("not find %{public}d in cache.", userId);
376         return {};
377     }
378     IMSA_HILOGD("num %{public}zu in cache.", it->second.enabledInfos.size());
379     return it->second;
380 }
381 
ClearEnabledCache(int32_t userId)382 void ImeEnabledInfoManager::ClearEnabledCache(int32_t userId)
383 {
384     std::lock_guard<std::mutex> cfgLock(imeEnabledCfgLock_);
385     imeEnabledCfg_.erase(userId);
386 }
387 // LCOV_EXCL_START
GetEnabledCfg(int32_t userId,const std::vector<FullImeInfo> & imeInfos,ImeEnabledCfg & cfg)388 int32_t ImeEnabledInfoManager::GetEnabledCfg(
389     int32_t userId, const std::vector<FullImeInfo> &imeInfos, ImeEnabledCfg &cfg)
390 {
391     std::string userContent;
392     auto ret = SettingsDataUtils::GetInstance().GetStringValue(
393         SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true", SettingsDataUtils::ENABLE_IME, userContent);
394     if (ret != ErrorCode::NO_ERROR && ret != ErrorCode::ERROR_KEYWORD_NOT_FOUND) {
395         IMSA_HILOGE("%{public}d get enabled table failed:%{public}d.", userId, ret);
396         return ret;
397     }
398     // system reboot
399     if (userContent.find("version") != std::string::npos) {
400         cfg.Unmarshall(userContent);
401         return CorrectByBundleMgr(userId, imeInfos, cfg.enabledInfos);
402     }
403     // the system version upgrade or the system starts for the first time
404     ret = EnableUpgradeManager::GetInstance().Upgrade(userId, imeInfos);
405     if (ret != ErrorCode::NO_ERROR) {
406         IMSA_HILOGE("%{public}d upgrade failed:%{public}d.", userId, ret);
407         return ret;
408     }
409     ret = SettingsDataUtils::GetInstance().GetStringValue(
410         SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true", SettingsDataUtils::ENABLE_IME, userContent);
411     if (ret != ErrorCode::NO_ERROR && ret != ErrorCode::ERROR_KEYWORD_NOT_FOUND) {
412         IMSA_HILOGE("%{public}d get enabled table failed after upgrade:%{public}d.", userId, ret);
413         return ret;
414     }
415     cfg.Unmarshall(userContent);
416     return ErrorCode::NO_ERROR;
417 }
418 
CorrectByBundleMgr(int32_t userId,const std::vector<FullImeInfo> & imeInfos,std::vector<ImeEnabledInfo> & enabledInfos)419 int32_t ImeEnabledInfoManager::CorrectByBundleMgr(
420     int32_t userId, const std::vector<FullImeInfo> &imeInfos, std::vector<ImeEnabledInfo> &enabledInfos)
421 {
422     auto finalImeInfos = imeInfos;
423     if (finalImeInfos.empty()) {
424         auto ret = ImeInfoInquirer::GetInstance().QueryFullImeInfo(userId, finalImeInfos, true);
425         if (ret != ErrorCode::NO_ERROR) {
426             IMSA_HILOGE("%{public}d QueryFullImeInfo failed.", userId);
427             return ret;
428         }
429     }
430     IMSA_HILOGI("ime size, enabled:%{public}zu, installed:%{public}zu.", enabledInfos.size(), finalImeInfos.size());
431     for (const auto &enabledInfo : enabledInfos) {
432         if (!enabledInfo.extraInfo.isDefaultIme) {
433             continue;
434         }
435         auto iter = std::find_if(finalImeInfos.begin(), finalImeInfos.end(),
436             [&enabledInfo](const FullImeInfo &imeInfoTmp) { return enabledInfo.bundleName == imeInfoTmp.prop.name; });
437         if (iter == finalImeInfos.end()) {
438             IMSA_HILOGW("current ime %{public}d/%{public}s uninstall when imsa abnormal", userId,
439                 enabledInfo.bundleName.c_str());
440             ModCurrentIme(enabledInfos);
441             break;
442         }
443     }
444     for (const auto &imeInfo : finalImeInfos) {
445         auto iter = std::find_if(enabledInfos.begin(), enabledInfos.end(),
446             [&imeInfo](const auto &enabledInfoTmp) { return enabledInfoTmp.bundleName == imeInfo.prop.name; });
447         if (iter != enabledInfos.end()) {
448             if (iter->extensionName.empty()) {
449                 IMSA_HILOGW("%{public}d/%{public}s uninstall before upgrade install again when imsa abnormal", userId,
450                     imeInfo.prop.name.c_str());
451                 iter->extensionName = imeInfo.prop.id;
452             }
453             continue;
454         }
455         IMSA_HILOGW("%{public}d/%{public}s first install when imsa abnormal", userId, imeInfo.prop.name.c_str());
456         enabledInfos.emplace_back(imeInfo.prop.name, imeInfo.prop.id,
457             ComputeEnabledStatus(imeInfo.prop.name, ImeInfoInquirer::GetInstance().GetSystemConfig().initEnabledState));
458     }
459     return ErrorCode::NO_ERROR;
460 }
461 // LCOV_EXCL_STOP
ComputeEnabledStatus(const std::string & bundleName,EnabledStatus initStatus)462 EnabledStatus ImeEnabledInfoManager::ComputeEnabledStatus(const std::string &bundleName, EnabledStatus initStatus)
463 {
464     if (!HasEnabledSwitch()) {
465         return EnabledStatus::FULL_EXPERIENCE_MODE;
466     }
467     auto sysIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
468     if (bundleName == sysIme.bundleName && initStatus == EnabledStatus::DISABLED) {
469         return EnabledStatus::BASIC_MODE;
470     }
471     return initStatus;
472 }
473 
UpdateEnabledCfgCache(int32_t userId,const ImeEnabledCfg & cfg)474 int32_t ImeEnabledInfoManager::UpdateEnabledCfgCache(int32_t userId, const ImeEnabledCfg &cfg)
475 {
476     std::string content;
477     if (!cfg.Marshall(content)) {
478         IMSA_HILOGE("Marshall failed");
479         return ErrorCode::ERROR_ENABLE_IME;
480     }
481     IMSA_HILOGD("[%{public}d, %{public}s].", userId, content.c_str());
482     if (!SettingsDataUtils::GetInstance().SetStringValue(
483         SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true", SettingsDataUtils::ENABLE_IME, content)) {
484         IMSA_HILOGE("%{public}d SetStringValue:%{public}s failed.", userId, content.c_str());
485         return ErrorCode::ERROR_ENABLE_IME;
486     }
487     SetEnabledCache(userId, cfg);
488     return ErrorCode::NO_ERROR;
489 }
490 
NotifyCurrentImeStatusChanged(int32_t userId,const std::string & bundleName,EnabledStatus newStatus)491 void ImeEnabledInfoManager::NotifyCurrentImeStatusChanged(
492     int32_t userId, const std::string &bundleName, EnabledStatus newStatus)
493 {
494     if (serviceHandler_ == nullptr) {
495         return;
496     }
497     auto notifyTask = [this, userId, bundleName, newStatus]() {
498         if (currentImeStatusChangedHandler_ != nullptr) {
499             currentImeStatusChangedHandler_(userId, bundleName, newStatus);
500         }
501     };
502     serviceHandler_->PostTask(notifyTask, "NotifyCurrentImeStatusChanged", 0, AppExecFwk::EventQueue::Priority::VIP);
503 }
504 
HasEnabledSwitch()505 bool ImeEnabledInfoManager::HasEnabledSwitch()
506 {
507     auto sysCfg = ImeInfoInquirer::GetInstance().GetSystemConfig();
508     return sysCfg.enableInputMethodFeature || sysCfg.enableFullExperienceFeature;
509 }
510 
IsDefaultFullMode(int32_t userId,const std::string & bundleName)511 bool ImeEnabledInfoManager::IsDefaultFullMode(int32_t userId, const std::string &bundleName)
512 {
513     auto defaultIme = ImeInfoInquirer::GetInstance().GetDefaultImeCfgProp();
514     if (defaultIme != nullptr && bundleName == defaultIme->name) {
515         return true;
516     }
517     std::string appId;
518     uint32_t versionCode;
519     if (!ImeInfoInquirer::GetInstance().GetImeAppId(userId, bundleName, appId) ||
520         !ImeInfoInquirer::GetInstance().GetImeVersionCode(userId, bundleName, versionCode)) {
521         IMSA_HILOGE("%{public}s failed to get appId and versionCode", bundleName.c_str());
522         return false;
523     }
524     std::vector<DefaultFullImeInfo> defaultFullImeList;
525     if (!SysCfgParser::ParseDefaultFullIme(defaultFullImeList)) {
526         IMSA_HILOGE("failed to parse config");
527         return false;
528     }
529     auto ime = std::find_if(defaultFullImeList.begin(), defaultFullImeList.end(),
530         [&appId](const auto &ime) { return ime.appId == appId; });
531     if (ime == defaultFullImeList.end()) {
532         IMSA_HILOGD("not default FULL");
533         return false;
534     }
535     bool isDefaultFull = false;
536     if (ime->expirationVersionCode > 0) {
537         isDefaultFull = !IsExpired(ime->expirationTime) || versionCode < ime->expirationVersionCode;
538     } else {
539         isDefaultFull = !IsExpired(ime->expirationTime);
540     }
541     IMSA_HILOGI("ime: %{public}s, isDefaultFull: %{public}d", bundleName.c_str(), isDefaultFull);
542     return isDefaultFull;
543 }
544 
IsExpired(const std::string & expirationTime)545 bool ImeEnabledInfoManager::IsExpired(const std::string &expirationTime)
546 {
547     std::istringstream expirationTimeStr(expirationTime);
548     std::tm expTime = {};
549     expirationTimeStr >> std::get_time(&expTime, "%Y-%m-%d %H:%M:%S");
550     if (expirationTimeStr.fail()) {
551         IMSA_HILOGE("get time error, expirationTime: %{public}s", expirationTime.c_str());
552         return false;
553     }
554     auto expTimePoint = std::chrono::system_clock::from_time_t(std::mktime(&expTime));
555     auto now = std::chrono::system_clock::now();
556     return expTimePoint < now;
557 }
558 
UpdateGlobalEnabledTable(int32_t userId,const ImeEnabledCfg & newEnabledCfg)559 void ImeEnabledInfoManager::UpdateGlobalEnabledTable(int32_t userId, const ImeEnabledCfg &newEnabledCfg)
560 {
561     IMSA_HILOGD("start.");
562     if (serviceHandler_ == nullptr) {
563         return;
564     }
565     auto task = [userId, newEnabledCfg]() {
566         EnableUpgradeManager::GetInstance().UpdateGlobalEnabledTable(userId, newEnabledCfg);
567     };
568     serviceHandler_->PostTask(task, "UpdateGlobalEnabledTable", 0, AppExecFwk::EventQueue::Priority::LOW);
569     IMSA_HILOGD("end.");
570 }
571 
OnFullExperienceTableChanged(int32_t userId)572 void ImeEnabledInfoManager::OnFullExperienceTableChanged(int32_t userId)
573 {
574     auto defaultIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
575     if (defaultIme.bundleName.empty()) {
576         return;
577     }
578     std::set<std::string> bundleNames;
579     auto ret = EnableUpgradeManager::GetInstance().GetFullExperienceTable(userId, bundleNames);
580     if (ret != ErrorCode::NO_ERROR) {
581         IMSA_HILOGE("userId:%{public}d read full experience table failed: %{public}d", userId, ret);
582         return;
583     }
584     auto newStatus = EnabledStatus::BASIC_MODE;
585     auto it = std::find_if(bundleNames.begin(), bundleNames.end(),
586         [&defaultIme](const std::string &bundleName) { return bundleName == defaultIme.bundleName; });
587     if (it != bundleNames.end()) {
588         newStatus = EnabledStatus::FULL_EXPERIENCE_MODE;
589     }
590     IMSA_HILOGI("%{public}d full experience table changed.", userId);
591     ImeEnabledInfoManager::GetInstance().Update(userId, defaultIme.bundleName, defaultIme.extName, newStatus);
592 }
593 // LCOV_EXCL_START
SetCurrentIme(int32_t userId,const std::string & imeId,const std::string & subName,bool isSetByUser)594 int32_t ImeEnabledInfoManager::SetCurrentIme(
595     int32_t userId, const std::string &imeId, const std::string &subName, bool isSetByUser)
596 {
597     std::lock_guard<std::mutex> lock(operateLock_);
598     auto [bundleName, extName] = SplitImeId(imeId);
599     if (bundleName.empty()) {
600         return ErrorCode::NO_ERROR;
601     }
602     ImeEnabledCfg enabledCfg;
603     if (bundleName == ImeInfoInquirer::GetInstance().GetSystemSpecialIme()) {
604         auto ret = GetEnabledCacheWithCorrect(userId, enabledCfg);
605         if (ret != ErrorCode::NO_ERROR) {
606             IMSA_HILOGE("%{public}d get enable info failed:%{public}d.", userId, ret);
607             return ErrorCode::ERROR_ENABLE_IME;
608         }
609         auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
610             [bundleName = bundleName](const auto &info) { return bundleName == info.bundleName; });
611         if (iter == enabledCfg.enabledInfos.end()) {
612             enabledCfg.enabledInfos.emplace_back(bundleName, extName, EnabledStatus::FULL_EXPERIENCE_MODE);
613         }
614     } else {
615         auto ret = GetEnabledCacheWithCorrect(userId, bundleName, extName, enabledCfg);
616         if (ret != ErrorCode::NO_ERROR) {
617             IMSA_HILOGE("%{public}d/%{public}s get enable info failed:%{public}d.", userId, bundleName.c_str(), ret);
618             return ErrorCode::ERROR_ENABLE_IME;
619         }
620     }
621     auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
622         [](const auto &info) { return info.extraInfo.isTmpIme; });
623     if (iter != enabledCfg.enabledInfos.end()) {
624         IMSA_HILOGI("%{public}d has tmp ime:%{public}s, not mod.", userId, iter->bundleName.c_str());
625         return ErrorCode::NO_ERROR;
626     }
627     for (auto &info : enabledCfg.enabledInfos) {
628         info.extraInfo.currentSubName = "";
629         info.extraInfo.isDefaultImeSet = false;
630         info.extraInfo.isDefaultIme = false;
631         if (info.bundleName == bundleName) {
632             info.extensionName = extName;
633             info.extraInfo.currentSubName = subName;
634             info.extraInfo.isDefaultImeSet = isSetByUser;
635             info.extraInfo.isDefaultIme = true;
636         }
637     }
638     auto ret = UpdateEnabledCfgCache(userId, enabledCfg);
639     if (ret != ErrorCode::NO_ERROR) {
640         IMSA_HILOGE("%{public}d update enable info failed:%{public}d.", userId, ret);
641         return ErrorCode::ERROR_ENABLE_IME;
642     }
643     return ErrorCode::NO_ERROR;
644 }
645 
SetTmpIme(int32_t userId,const std::string & imeId)646 int32_t ImeEnabledInfoManager::SetTmpIme(int32_t userId, const std::string &imeId)
647 {
648     std::lock_guard<std::mutex> lock(operateLock_);
649     IMSA_HILOGD("%{public}d set tmp ime:%{public}s.", userId, imeId.c_str());
650     ImeEnabledCfg enabledCfg;
651     if (imeId.empty()) {
652         auto ret = GetEnabledCacheWithCorrect(userId, enabledCfg);
653         if (ret != ErrorCode::NO_ERROR) {
654             IMSA_HILOGE("%{public}d get enable info failed:%{public}d.", userId, ret);
655             return ret;
656         }
657         auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
658             [](const auto &info) { return info.extraInfo.isTmpIme; });
659         if (iter == enabledCfg.enabledInfos.end()) {
660             return ErrorCode::NO_ERROR;
661         }
662         for (auto &info : enabledCfg.enabledInfos) {
663             info.extraInfo.isTmpIme = false;
664         }
665     } else {
666         auto [bundleName, extName] = SplitImeId(imeId);
667         auto ret = GetEnabledCacheWithCorrect(userId, bundleName, extName, enabledCfg);
668         if (ret != ErrorCode::NO_ERROR) {
669             IMSA_HILOGE("%{public}d/%{public}s get enable info failed:%{public}d.", userId, bundleName.c_str(), ret);
670             return ret;
671         }
672         auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
673             [&tmpBundleName = bundleName](
674                 const auto &info) { return info.extraInfo.isTmpIme && info.bundleName == tmpBundleName; });
675         if (iter != enabledCfg.enabledInfos.end()) {
676             IMSA_HILOGI("%{public}d set ime same with tmp ime:%{public}s, not mod.", userId, iter->bundleName.c_str());
677             return ErrorCode::NO_ERROR;
678         }
679         for (auto &info : enabledCfg.enabledInfos) {
680             info.extraInfo.isTmpIme = false;
681             if (info.bundleName == bundleName) {
682                 info.extraInfo.isTmpIme = true;
683             }
684         }
685     }
686     auto ret = UpdateEnabledCfgCache(userId, enabledCfg);
687     if (ret != ErrorCode::NO_ERROR) {
688         IMSA_HILOGE("%{public}d update enable info failed:%{public}d.", userId, ret);
689         return ErrorCode::ERROR_ENABLE_IME;
690     }
691     return ErrorCode::NO_ERROR;
692 }
693 
GetCurrentImeCfg(int32_t userId)694 std::shared_ptr<ImeNativeCfg> ImeEnabledInfoManager::GetCurrentImeCfg(int32_t userId)
695 {
696     std::lock_guard<std::mutex> lock(operateLock_);
697     ImeEnabledCfg enabledCfg;
698     auto ret = GetEnabledCacheWithCorrect(userId, enabledCfg);
699     if (ret != ErrorCode::NO_ERROR) {
700         IMSA_HILOGE("%{public}d get enable info failed:%{public}d.", userId, ret);
701         return std::make_shared<ImeNativeCfg>();
702     }
703     auto iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
704         [](const auto &info) { return info.extraInfo.isTmpIme; });
705     if (iter != enabledCfg.enabledInfos.end()) {
706         IMSA_HILOGI("%{public}d has tmp default ime:%{public}s.", userId, iter->bundleName.c_str());
707         ImeNativeCfg nativeInfo;
708         nativeInfo.imeId = iter->bundleName + "/" + iter->extensionName;
709         nativeInfo.bundleName = iter->bundleName;
710         nativeInfo.extName = iter->extensionName;
711         return std::make_shared<ImeNativeCfg>(nativeInfo);
712     }
713     iter = std::find_if(enabledCfg.enabledInfos.begin(), enabledCfg.enabledInfos.end(),
714         [](const auto &info) { return info.extraInfo.isDefaultIme; });
715     if (iter != enabledCfg.enabledInfos.end()) {
716         IMSA_HILOGD("%{public}d has default ime:%{public}s.", userId, iter->bundleName.c_str());
717         ImeNativeCfg nativeInfo;
718         nativeInfo.imeId = iter->bundleName + "/" + iter->extensionName;
719         nativeInfo.bundleName = iter->bundleName;
720         nativeInfo.extName = iter->extensionName;
721         nativeInfo.subName = iter->extraInfo.currentSubName;
722         return std::make_shared<ImeNativeCfg>(nativeInfo);
723     }
724     IMSA_HILOGI("%{public}d not set default ime.", userId);
725     return std::make_shared<ImeNativeCfg>();
726 }
727 // LCOV_EXCL_STOP
IsDefaultImeSet(int32_t userId)728 bool ImeEnabledInfoManager::IsDefaultImeSet(int32_t userId)
729 {
730     std::lock_guard<std::mutex> lock(operateLock_);
731     ImeEnabledCfg enabledCfg;
732     auto ret = GetEnabledCacheWithCorrect(userId, enabledCfg);
733     if (ret != ErrorCode::NO_ERROR) {
734         IMSA_HILOGE("%{public}d get enable info failed:%{public}d.", userId, ret);
735         return false;
736     }
737     for (auto &info : enabledCfg.enabledInfos) {
738         if (info.extraInfo.isDefaultIme) {
739             return info.extraInfo.isDefaultImeSet;
740         }
741     }
742     return false;
743 }
744 
SplitImeId(const std::string & imeId)745 std::pair<std::string, std::string> ImeEnabledInfoManager::SplitImeId(const std::string &imeId)
746 {
747     std::string bundleName;
748     std::string extName;
749     auto pos = imeId.find('/');
750     if (pos != std::string::npos && pos + 1 < imeId.size()) {
751         bundleName = imeId.substr(0, pos);
752         extName = imeId.substr(pos + 1);
753     }
754     return std::make_pair(bundleName, extName);
755 }
756 
ModCurrentIme(std::vector<ImeEnabledInfo> & enabledInfos)757 void ImeEnabledInfoManager::ModCurrentIme(std::vector<ImeEnabledInfo> &enabledInfos)
758 {
759     std::string oldBundleName;
760     auto oldIter = std::find_if(enabledInfos.begin(), enabledInfos.end(),
761         [](const ImeEnabledInfo &enabledInfoTmp) { return enabledInfoTmp.extraInfo.isDefaultIme; });
762     auto newIter = std::find_if(enabledInfos.begin(), enabledInfos.end(), [](const ImeEnabledInfo &enabledInfoTmp) {
763         return enabledInfoTmp.bundleName == ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName;
764     });
765     if (newIter == enabledInfos.end()) {
766         newIter = std::find_if(enabledInfos.begin(), enabledInfos.end(), [](const ImeEnabledInfo &enabledInfoTmp) {
767             return enabledInfoTmp.enabledStatus != EnabledStatus::DISABLED;
768         });
769     }
770     if (newIter == enabledInfos.end()) {
771         return;
772     }
773     newIter->extraInfo.isDefaultIme = true;
774     if (oldIter != enabledInfos.end()) {
775         oldIter->extraInfo.isDefaultIme = false;
776         oldIter->extraInfo.isDefaultImeSet = false;
777         oldIter->extraInfo.isTmpIme = false;
778         oldIter->extraInfo.currentSubName = "";
779     }
780 }
781 
IsCurrentIme(const std::string & bundleName,const std::vector<ImeEnabledInfo> & enabledInfos)782 bool ImeEnabledInfoManager::IsCurrentIme(const std::string &bundleName, const std::vector<ImeEnabledInfo> &enabledInfos)
783 {
784     auto iter = std::find_if(enabledInfos.begin(), enabledInfos.end(),
785         [&bundleName](const ImeEnabledInfo &info) { return info.extraInfo.isDefaultIme; });
786     return iter != enabledInfos.end() && iter->bundleName == bundleName;
787 }
788 } // namespace MiscServices
789 } // namespace OHOS