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