• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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_info_inquirer.h"
17 
18 #include <algorithm>
19 #include <string>
20 
21 #include "application_info.h"
22 #include "bundle_mgr_client_impl.h"
23 #include "global.h"
24 #include "if_system_ability_manager.h"
25 #include "ime_cfg_manager.h"
26 #include "input_method_info.h"
27 #include "iservice_registry.h"
28 #include "parameter.h"
29 #include "string_ex.h"
30 #include "system_ability.h"
31 #include "system_ability_definition.h"
32 
33 namespace OHOS {
34 namespace MiscServices {
35 namespace {
36 using json = nlohmann::json;
37 using namespace OHOS::AppExecFwk;
38 constexpr const char *SUBTYPE_PROFILE_METADATA_NAME = "ohos.extension.input_method";
39 constexpr uint32_t SUBTYPE_PROFILE_NUM = 1;
40 constexpr uint32_t MAX_SUBTYPE_NUM = 256;
41 constexpr const char *DEFAULT_IME_KEY = "persist.sys.default_ime";
42 constexpr int32_t CONFIG_LEN = 128;
43 constexpr uint32_t RETRY_INTERVAL = 100;
44 constexpr uint32_t BLOCK_RETRY_TIMES = 1000;
45 } // namespace
GetInstance()46 ImeInfoInquirer &ImeInfoInquirer::GetInstance()
47 {
48     static ImeInfoInquirer instance;
49     return instance;
50 }
51 
QueryImeExtInfos(const int32_t userId,std::vector<ExtensionAbilityInfo> & infos)52 bool ImeInfoInquirer::QueryImeExtInfos(const int32_t userId, std::vector<ExtensionAbilityInfo> &infos)
53 {
54     IMSA_HILOGD("userId: %{public}d", userId);
55     auto bundleMgr = GetBundleMgr();
56     if (bundleMgr == nullptr) {
57         IMSA_HILOGE("GetBundleMgr failed");
58         return false;
59     }
60     return bundleMgr->QueryExtensionAbilityInfos(ExtensionAbilityType::INPUTMETHOD, userId, infos);
61 }
62 
GetExtInfosByBundleName(const int32_t userId,const std::string & bundleName,std::vector<AppExecFwk::ExtensionAbilityInfo> & extInfos)63 int32_t ImeInfoInquirer::GetExtInfosByBundleName(
64     const int32_t userId, const std::string &bundleName, std::vector<AppExecFwk::ExtensionAbilityInfo> &extInfos)
65 {
66     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s", userId, bundleName.c_str());
67     std::vector<AppExecFwk::ExtensionAbilityInfo> tempExtInfos;
68     BlockRetry(RETRY_INTERVAL, BLOCK_RETRY_TIMES,
69         [this, &userId, &tempExtInfos]() -> bool { return QueryImeExtInfos(userId, tempExtInfos); });
70     for (const auto &extInfo : tempExtInfos) {
71         if (extInfo.bundleName == bundleName) {
72             extInfos.emplace_back(extInfo);
73         }
74     }
75     if (extInfos.empty()) {
76         IMSA_HILOGE("bundleName: %{public}s extInfos is empty", bundleName.c_str());
77         return ErrorCode::ERROR_BAD_PARAMETERS;
78     }
79     return ErrorCode::NO_ERROR;
80 }
81 
GetImeInfo(const int32_t userId,const std::string & bundleName,const std::string & subName,ImeInfo & info)82 int32_t ImeInfoInquirer::GetImeInfo(
83     const int32_t userId, const std::string &bundleName, const std::string &subName, ImeInfo &info)
84 {
85     // if current ime, get info from currentImeInfos_
86     std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
87     if (currentImeInfo_ != nullptr && bundleName == currentImeInfo_->prop.name) {
88         return GetImeInfoFromNative(userId, subName, info);
89     }
90     return GetImeInfoFromBundleMgr(userId, bundleName, subName, info);
91 }
92 
GetImeInfoFromNative(const int32_t userId,const std::string & subName,ImeInfo & info)93 int32_t ImeInfoInquirer::GetImeInfoFromNative(const int32_t userId, const std::string &subName, ImeInfo &info)
94 {
95     IMSA_HILOGD("userId: %{public}d, subName: %{public}s", userId, subName.c_str());
96     std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
97     if (currentImeInfo_ == nullptr) {
98         return ErrorCode::ERROR_BAD_PARAMETERS;
99     }
100     info.subProps = currentImeInfo_->subProps;
101     info.prop = currentImeInfo_->prop;
102     info.isNewIme = currentImeInfo_->isNewIme;
103     if (subName == currentImeInfo_->subProp.id) {
104         info.subProp = currentImeInfo_->subProp;
105         return ErrorCode::NO_ERROR;
106     }
107 
108     auto it = std::find_if(currentImeInfo_->subProps.begin(), currentImeInfo_->subProps.end(),
109         [&subName](const SubProperty &subProp) { return subProp.id == subName; });
110     if (it == currentImeInfo_->subProps.end()) {
111         IMSA_HILOGE("Find subName: %{public}s failed", subName.c_str());
112         return ErrorCode::ERROR_BAD_PARAMETERS;
113     }
114     info.subProp = *it;
115     // old ime, make the id of prop same with the id of subProp.
116     if (!info.isNewIme) {
117         info.prop.id = info.subProp.id;
118     }
119     return ErrorCode::NO_ERROR;
120 }
121 
GetImeInfoFromBundleMgr(const int32_t userId,const std::string & bundleName,const std::string & subName,ImeInfo & info)122 int32_t ImeInfoInquirer::GetImeInfoFromBundleMgr(
123     const int32_t userId, const std::string &bundleName, const std::string &subName, ImeInfo &info)
124 {
125     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s, subName: %{public}s", userId, bundleName.c_str(),
126         subName.c_str());
127     std::vector<AppExecFwk::ExtensionAbilityInfo> extInfos;
128     auto ret = ImeInfoInquirer::GetInstance().GetExtInfosByBundleName(userId, bundleName, extInfos);
129     if (ret != ErrorCode::NO_ERROR || extInfos.empty()) {
130         IMSA_HILOGE("userId: %{public}d getExtInfosByBundleName %{public}s failed", userId, bundleName.c_str());
131         return ErrorCode::ERROR_BAD_PARAMETERS;
132     }
133     info.prop.name = extInfos[0].bundleName;
134     info.prop.id = extInfos[0].name;
135     info.prop.label =
136         GetStringById(extInfos[0].bundleName, extInfos[0].moduleName, extInfos[0].applicationInfo.labelId, userId);
137     info.prop.labelId = extInfos[0].applicationInfo.labelId;
138     info.prop.iconId = extInfos[0].applicationInfo.iconId;
139 
140     std::vector<SubProperty> subProps;
141     info.isNewIme = IsNewExtInfos(extInfos);
142     ret = info.isNewIme ? ListInputMethodSubtype(userId, extInfos[0], subProps)
143                         : ListInputMethodSubtype(userId, extInfos, subProps);
144     if (ret != ErrorCode::NO_ERROR || subProps.empty()) {
145         IMSA_HILOGE("userId: %{public}d listInputMethodSubtype failed", userId);
146         return ErrorCode::ERROR_BAD_PARAMETERS;
147     }
148     info.subProps = subProps;
149     if (subName.empty()) {
150         info.subProp = subProps[0];
151     } else {
152         auto it = std::find_if(subProps.begin(), subProps.end(),
153             [&subName](const SubProperty &subProp) { return subProp.id == subName; });
154         if (it == subProps.end()) {
155             IMSA_HILOGE("Find subName: %{public}s failed", subName.c_str());
156             return ErrorCode::ERROR_BAD_PARAMETERS;
157         }
158         info.subProp = *it;
159     }
160     // old ime, make the id of prop same with the id of subProp.
161     if (!info.isNewIme) {
162         info.prop.id = info.subProp.id;
163     }
164     return ErrorCode::NO_ERROR;
165 }
166 
SetCurrentImeInfo(const ImeInfo & info)167 void ImeInfoInquirer::SetCurrentImeInfo(const ImeInfo &info)
168 {
169     std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
170     currentImeInfo_ = std::make_shared<ImeInfo>(info);
171 }
172 
SetCurrentImeInfo(const int32_t userId)173 void ImeInfoInquirer::SetCurrentImeInfo(const int32_t userId)
174 {
175     IMSA_HILOGD("userId: %{public}d", userId);
176     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
177     ImeInfo info;
178     auto ret = GetImeInfoFromBundleMgr(userId, currentImeCfg->bundleName, currentImeCfg->subName, info);
179     if (ret != ErrorCode::NO_ERROR) {
180         IMSA_HILOGE("userId: %{public}d, bundleName: %{public}s, subName: %{public}s getImeInfoFromBundleMgr failed",
181             userId, currentImeCfg->bundleName.c_str(), currentImeCfg->subName.c_str());
182         return;
183     }
184     std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
185     currentImeInfo_ = std::make_shared<ImeInfo>(info);
186 }
187 
ResetCurrentImeInfo()188 void ImeInfoInquirer::ResetCurrentImeInfo()
189 {
190     std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
191     currentImeInfo_ = nullptr;
192 }
193 
GetInputMethodParam(const int32_t userId)194 std::string ImeInfoInquirer::GetInputMethodParam(const int32_t userId)
195 {
196     auto properties = ListInputMethodInfo(userId);
197     if (properties.empty()) {
198         return "";
199     }
200     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
201     bool isBegin = true;
202     std::string params = "{\"imeList\":[";
203     for (const auto &property : properties) {
204         params += isBegin ? "" : "},";
205         isBegin = false;
206 
207         std::string imeId = property.mPackageName + "/" + property.mAbilityName;
208         params += "{\"ime\": \"" + imeId + "\",";
209         params += "\"labelId\": \"" + std::to_string(property.labelId) + "\",";
210         params += "\"descriptionId\": \"" + std::to_string(property.descriptionId) + "\",";
211         std::string isCurrentIme = currentImeCfg->imeId == imeId ? "true" : "false";
212         params += "\"isCurrentIme\": \"" + isCurrentIme + "\",";
213         params += "\"label\": \"" + property.label + "\",";
214         params += "\"description\": \"" + property.description + "\"";
215     }
216     params += "}]}";
217     return params;
218 }
219 
ListInputMethodInfo(const int32_t userId)220 std::vector<InputMethodInfo> ImeInfoInquirer::ListInputMethodInfo(const int32_t userId)
221 {
222     IMSA_HILOGD("userId: %{public}d", userId);
223     std::vector<ExtensionAbilityInfo> extensionInfos;
224     if (!QueryImeExtInfos(userId, extensionInfos)) {
225         IMSA_HILOGE("userId: %{public}d queryImeExtInfos failed", userId);
226         return {};
227     }
228     std::vector<InputMethodInfo> properties;
229     for (const auto &extension : extensionInfos) {
230         auto applicationInfo = extension.applicationInfo;
231         auto label = GetStringById(extension.bundleName, extension.moduleName, applicationInfo.labelId, userId);
232         auto description =
233             GetStringById(extension.bundleName, extension.moduleName, applicationInfo.descriptionId, userId);
234         InputMethodInfo property;
235         property.mPackageName = extension.bundleName;
236         property.mAbilityName = extension.name;
237         property.labelId = applicationInfo.labelId;
238         property.descriptionId = applicationInfo.descriptionId;
239         property.label = label;
240         property.description = description;
241         properties.emplace_back(property);
242     }
243     return properties;
244 }
245 
ListInputMethod(const int32_t userId,const InputMethodStatus status,std::vector<Property> & props)246 int32_t ImeInfoInquirer::ListInputMethod(
247     const int32_t userId, const InputMethodStatus status, std::vector<Property> &props)
248 {
249     IMSA_HILOGD("userId: %{public}d, status: %{public}d", userId, status);
250     if (status == InputMethodStatus::ALL) {
251         return ListInputMethod(userId, props);
252     }
253     if (status == InputMethodStatus::ENABLE) {
254         return ListEnabledInputMethod(userId, props);
255     }
256     if (status == InputMethodStatus::DISABLE) {
257         return ListDisabledInputMethod(userId, props);
258     }
259     return ErrorCode::ERROR_BAD_PARAMETERS;
260 }
261 
ListInputMethod(const int32_t userId,std::vector<Property> & props)262 int32_t ImeInfoInquirer::ListInputMethod(const int32_t userId, std::vector<Property> &props)
263 {
264     IMSA_HILOGD("userId: %{public}d", userId);
265     std::vector<ExtensionAbilityInfo> extensionInfos;
266     BlockRetry(RETRY_INTERVAL, BLOCK_RETRY_TIMES,
267         [this, &userId, &extensionInfos]() -> bool { return QueryImeExtInfos(userId, extensionInfos); });
268     for (const auto &extension : extensionInfos) {
269         auto it = std::find_if(props.begin(), props.end(),
270             [&extension](const Property &prop) { return prop.name == extension.bundleName; });
271         if (it != props.end()) {
272             continue;
273         }
274         props.push_back({ .name = extension.bundleName,
275             .id = extension.name,
276             .label =
277                 GetStringById(extension.bundleName, extension.moduleName, extension.applicationInfo.labelId, userId),
278             .labelId = extension.applicationInfo.labelId,
279             .iconId = extension.applicationInfo.iconId });
280     }
281     return ErrorCode::NO_ERROR;
282 }
283 
ListEnabledInputMethod(const int32_t userId,std::vector<Property> & props)284 int32_t ImeInfoInquirer::ListEnabledInputMethod(const int32_t userId, std::vector<Property> &props)
285 {
286     IMSA_HILOGD("userId: %{public}d", userId);
287     auto prop = GetCurrentInputMethod(userId);
288     if (prop == nullptr) {
289         IMSA_HILOGI("userId: %{public}d getCurrentInputMethod failed", userId);
290         return ErrorCode::ERROR_NULL_POINTER;
291     }
292     props = { *prop };
293     return ErrorCode::NO_ERROR;
294 }
295 
ListDisabledInputMethod(const int32_t userId,std::vector<Property> & props)296 int32_t ImeInfoInquirer::ListDisabledInputMethod(const int32_t userId, std::vector<Property> &props)
297 {
298     IMSA_HILOGD("userId: %{public}d", userId);
299     auto ret = ListInputMethod(userId, props);
300     if (ret != ErrorCode::NO_ERROR) {
301         IMSA_HILOGE("userId: %{public}d listInputMethod failed", userId);
302         return ret;
303     }
304     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
305     for (auto iter = props.begin(); iter != props.end();) {
306         if (iter->name == currentImeCfg->bundleName) {
307             iter = props.erase(iter);
308             continue;
309         }
310         ++iter;
311     }
312     return ErrorCode::NO_ERROR;
313 }
314 
ListInputMethodSubtype(const int32_t userId,const std::string & bundleName,std::vector<SubProperty> & subProps)315 int32_t ImeInfoInquirer::ListInputMethodSubtype(
316     const int32_t userId, const std::string &bundleName, std::vector<SubProperty> &subProps)
317 {
318     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s", userId, bundleName.c_str());
319     {
320         std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
321         if (currentImeInfo_ != nullptr && currentImeInfo_->prop.name == bundleName) {
322             subProps = currentImeInfo_->subProps;
323             return ErrorCode::NO_ERROR;
324         }
325     }
326     std::vector<ExtensionAbilityInfo> extInfos;
327     auto ret = GetExtInfosByBundleName(userId, bundleName, extInfos);
328     if (ret != ErrorCode::NO_ERROR) {
329         IMSA_HILOGE("userId: %{public}d getExtInfosByBundleName %{public}s failed", userId, bundleName.c_str());
330         return ret;
331     }
332     return IsNewExtInfos(extInfos) ? ListInputMethodSubtype(userId, extInfos[0], subProps)
333                                    : ListInputMethodSubtype(userId, extInfos, subProps);
334 }
335 
ListCurrentInputMethodSubtype(const int32_t userId,std::vector<SubProperty> & subProps)336 int32_t ImeInfoInquirer::ListCurrentInputMethodSubtype(const int32_t userId, std::vector<SubProperty> &subProps)
337 {
338     // If the local currentImeInfo_ exists, the value is taken directly form currentImeInfo_
339     {
340         std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
341         if (currentImeInfo_ != nullptr) {
342             subProps = currentImeInfo_->subProps;
343             return ErrorCode::NO_ERROR;
344         }
345     }
346     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
347     IMSA_HILOGD("currentIme: %{public}s", currentImeCfg->imeId.c_str());
348     return ListInputMethodSubtype(userId, currentImeCfg->bundleName, subProps);
349 }
350 
IsNewExtInfos(const std::vector<ExtensionAbilityInfo> & extInfos)351 bool ImeInfoInquirer::IsNewExtInfos(const std::vector<ExtensionAbilityInfo> &extInfos)
352 {
353     if (extInfos.empty()) {
354         IMSA_HILOGE("extInfos is empty");
355         return false;
356     }
357     auto iter = std::find_if(extInfos[0].metadata.begin(), extInfos[0].metadata.end(),
358         [](const Metadata &metadata) { return metadata.name == SUBTYPE_PROFILE_METADATA_NAME; });
359     return iter != extInfos[0].metadata.end();
360 }
361 
ListInputMethodSubtype(const int32_t userId,const std::vector<ExtensionAbilityInfo> & extInfos,std::vector<SubProperty> & subProps)362 int32_t ImeInfoInquirer::ListInputMethodSubtype(
363     const int32_t userId, const std::vector<ExtensionAbilityInfo> &extInfos, std::vector<SubProperty> &subProps)
364 {
365     IMSA_HILOGD("oldIme, userId: %{public}d", userId);
366     for (const auto &extInfo : extInfos) {
367         SubProperty subProperty;
368         subProperty.labelId = extInfo.labelId;
369         subProperty.label = GetStringById(extInfo.bundleName, extInfo.moduleName, extInfo.labelId, userId);
370         subProperty.id = extInfo.name;
371         subProperty.name = extInfo.bundleName;
372         subProperty.iconId = extInfo.iconId;
373         std::vector<Metadata> extends = extInfo.metadata;
374         auto property = GetExtends(extends);
375         subProperty.language = property.language;
376         subProperty.mode = property.mode;
377         subProperty.locale = property.locale;
378         subProperty.icon = property.icon;
379         subProps.emplace_back(subProperty);
380     }
381     return ErrorCode::NO_ERROR;
382 }
383 
ListInputMethodSubtype(const int32_t userId,const ExtensionAbilityInfo & extInfo,std::vector<SubProperty> & subProps)384 int32_t ImeInfoInquirer::ListInputMethodSubtype(
385     const int32_t userId, const ExtensionAbilityInfo &extInfo, std::vector<SubProperty> &subProps)
386 {
387     IMSA_HILOGD("newIme, userId: %{public}d", userId);
388     auto iter = std::find_if(extInfo.metadata.begin(), extInfo.metadata.end(),
389         [](const Metadata &metadata) { return metadata.name == SUBTYPE_PROFILE_METADATA_NAME; });
390     if (iter == extInfo.metadata.end()) {
391         IMSA_HILOGE("find metadata name:SUBTYPE_PROFILE_METADATA_NAME failed");
392         return ErrorCode::ERROR_BAD_PARAMETERS;
393     }
394     OHOS::AppExecFwk::BundleMgrClientImpl clientImpl;
395     std::vector<std::string> profiles;
396     if (!clientImpl.GetResConfigFile(extInfo, iter->name, profiles)) {
397         IMSA_HILOGE("GetProfileFromExtension failed");
398         return ErrorCode::ERROR_PACKAGE_MANAGER;
399     }
400     if (!ParseSubProp(profiles, subProps)) {
401         IMSA_HILOGE("ParseSubProp failed");
402         return ErrorCode::ERROR_BAD_PARAMETERS;
403     }
404     IMSA_HILOGD("subProps size: %{public}zu", subProps.size());
405     for (auto &subProp : subProps) {
406         subProp.name = extInfo.bundleName;
407         auto pos = subProp.label.find(':');
408         if (pos != std::string::npos && pos + 1 < subProp.label.size()) {
409             subProp.labelId = atoi(subProp.label.substr(pos + 1).c_str());
410             subProp.label = GetStringById(extInfo.bundleName, extInfo.moduleName, subProp.labelId, userId);
411         }
412         pos = subProp.icon.find(':');
413         if (pos != std::string::npos && pos + 1 < subProp.icon.size()) {
414             subProp.iconId = atoi(subProp.icon.substr(pos + 1).c_str());
415         }
416         ParseLanguage(subProp.locale, subProp.language);
417     }
418     return ErrorCode::NO_ERROR;
419 }
420 
ParseLanguage(const std::string & locale,std::string & language)421 void ImeInfoInquirer::ParseLanguage(const std::string &locale, std::string &language)
422 {
423     language = locale;
424     auto pos = locale.find('-');
425     if (pos != std::string::npos) {
426         language = locale.substr(0, pos);
427     }
428     // compatible with the locale configuration of original ime
429     pos = locale.find('_');
430     if (pos != std::string::npos) {
431         language = locale.substr(0, pos);
432     }
433     if (language == "en") {
434         language = "english";
435     }
436     if (language == "zh") {
437         language = "chinese";
438     }
439 }
440 
GetStringById(const std::string & bundleName,const std::string & moduleName,int32_t labelId,int32_t userId)441 std::string ImeInfoInquirer::GetStringById(
442     const std::string &bundleName, const std::string &moduleName, int32_t labelId, int32_t userId)
443 {
444     auto bundleMgr = GetBundleMgr();
445     return bundleMgr == nullptr ? "" : bundleMgr->GetStringById(bundleName, moduleName, labelId, userId);
446 }
447 
GetExtends(const std::vector<Metadata> & metaData)448 SubProperty ImeInfoInquirer::GetExtends(const std::vector<Metadata> &metaData)
449 {
450     SubProperty property;
451     for (const auto &data : metaData) {
452         if (data.name == "language") {
453             property.language = data.value;
454             continue;
455         }
456         if (data.name == "mode") {
457             property.mode = data.value;
458             continue;
459         }
460         if (data.name == "locale") {
461             property.locale = data.value;
462             continue;
463         }
464         if (data.name == "icon") {
465             property.icon = data.value;
466         }
467     }
468     return property;
469 }
470 
GetCurrentInputMethod(const int32_t userId)471 std::shared_ptr<Property> ImeInfoInquirer::GetCurrentInputMethod(const int32_t userId)
472 {
473     // If the local currentImeInfo_ exists, the value is taken directly form currentImeInfo_
474     {
475         std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
476         if (currentImeInfo_ != nullptr) {
477             return std::make_shared<Property>(currentImeInfo_->prop);
478         }
479     }
480     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
481     IMSA_HILOGD("currentIme: %{public}s", currentImeCfg->imeId.c_str());
482     std::vector<AppExecFwk::ExtensionAbilityInfo> extInfos;
483     auto ret = ImeInfoInquirer::GetInstance().GetExtInfosByBundleName(userId, currentImeCfg->bundleName, extInfos);
484     if (ret != ErrorCode::NO_ERROR || extInfos.empty()) {
485         IMSA_HILOGE(
486             "userId: %{public}d getExtInfosByBundleName %{public}s failed", userId, currentImeCfg->bundleName.c_str());
487         return nullptr;
488     }
489     Property prop = { .name = extInfos[0].bundleName,
490         .id = currentImeCfg->extName, // if old ime, the extInfos[0].name maybe not same with currentImeExtName
491         .label =
492             GetStringById(extInfos[0].bundleName, extInfos[0].moduleName, extInfos[0].applicationInfo.labelId, userId),
493         .labelId = extInfos[0].applicationInfo.labelId,
494         .iconId = extInfos[0].applicationInfo.iconId };
495     return std::make_shared<Property>(prop);
496 }
497 
GetCurrentInputMethodSubtype(const int32_t userId)498 std::shared_ptr<SubProperty> ImeInfoInquirer::GetCurrentInputMethodSubtype(const int32_t userId)
499 {
500     // If the local currentImeInfo_ exists, the value is taken directly form currentImeInfo_
501     {
502         std::lock_guard<std::recursive_mutex> lock(currentImeInfoLock_);
503         if (currentImeInfo_ != nullptr) {
504             return std::make_shared<SubProperty>(currentImeInfo_->subProp);
505         }
506     }
507     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
508     IMSA_HILOGD("currentIme: %{public}s", currentImeCfg->imeId.c_str());
509     std::vector<SubProperty> subProps = {};
510     auto ret = ListInputMethodSubtype(userId, currentImeCfg->bundleName, subProps);
511     if (ret != ErrorCode::NO_ERROR || subProps.empty()) {
512         IMSA_HILOGE("userId: %{public}d listInputMethodSubtype by bundleName: %{public}s failed", userId,
513             currentImeCfg->bundleName.c_str());
514         return nullptr;
515     }
516     auto it = std::find_if(subProps.begin(), subProps.end(),
517         [&currentImeCfg](const SubProperty &subProp) { return subProp.id == currentImeCfg->subName; });
518     if (it != subProps.end()) {
519         return std::make_shared<SubProperty>(*it);
520     }
521     IMSA_HILOGE("Find subName: %{public}s failed", currentImeCfg->subName.c_str());
522     return std::make_shared<SubProperty>(subProps[0]);
523 }
524 
IsImeInstalled(const int32_t userId,const std::string & bundleName,const std::string & extName)525 bool ImeInfoInquirer::IsImeInstalled(const int32_t userId, const std::string &bundleName, const std::string &extName)
526 {
527     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s, extName: %{public}s", userId, bundleName.c_str(),
528         extName.c_str());
529     std::vector<OHOS::AppExecFwk::ExtensionAbilityInfo> extInfos;
530     GetExtInfosByBundleName(userId, bundleName, extInfos);
531     auto iter = std::find_if(extInfos.begin(), extInfos.end(),
532         [&bundleName, &extName](const OHOS::AppExecFwk::ExtensionAbilityInfo &extInfo) {
533             return extInfo.bundleName == bundleName && extName == extInfo.name;
534         });
535     if (iter == extInfos.end()) {
536         IMSA_HILOGE("false");
537         return false;
538     }
539     IMSA_HILOGI("true");
540     return true;
541 }
542 
GetStartedIme(const int32_t userId)543 std::string ImeInfoInquirer::GetStartedIme(const int32_t userId)
544 {
545     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
546     IMSA_HILOGD("userId: %{public}d, currentIme: %{public}s", userId, currentImeCfg->imeId.c_str());
547     if (currentImeCfg->imeId.empty() || !IsImeInstalled(userId, currentImeCfg->bundleName, currentImeCfg->extName)) {
548         auto newUserIme = GetDefaultIme();
549         std::string subName;
550         auto info = GetDefaultImeInfo(userId);
551         if (info == nullptr) {
552             IMSA_HILOGE("GetDefaultImeInfo failed");
553             subName = "";
554         } else {
555             subName = info->subProp.id;
556             SetCurrentImeInfo(*info);
557         }
558         currentImeCfg->imeId.empty() ? ImeCfgManager::GetInstance().AddImeCfg({ userId, newUserIme, subName })
559                                      : ImeCfgManager::GetInstance().ModifyImeCfg({ userId, newUserIme, subName });
560         return newUserIme;
561     }
562     // service start, user switch, set the currentImeInfo_.
563     SetCurrentImeInfo(userId);
564     return currentImeCfg->imeId;
565 }
566 
GetDefaultImeInfo(const int32_t userId)567 std::shared_ptr<ImeInfo> ImeInfoInquirer::GetDefaultImeInfo(const int32_t userId)
568 {
569     auto ime = GetDefaultIme();
570     auto pos = ime.find('/');
571     if (pos == std::string::npos || pos + 1 >= ime.size()) {
572         IMSA_HILOGE("defaultIme: %{public}s is abnormal", ime.c_str());
573         return nullptr;
574     }
575     auto bundleName = ime.substr(0, pos);
576     auto extName = ime.substr(pos + 1);
577     {
578         std::lock_guard<std::mutex> lock(defaultImeInfoLock_);
579         if (defaultImeInfo_ != nullptr && defaultImeInfo_->prop.name == bundleName
580             && defaultImeInfo_->prop.id == extName) {
581             return defaultImeInfo_;
582         }
583     }
584     ImeInfo info;
585     auto ret = GetImeInfoFromBundleMgr(userId, bundleName, "", info);
586     if (ret != ErrorCode::NO_ERROR) {
587         IMSA_HILOGE(
588             "userId: %{public}d, bundleName: %{public}s getImeInfoFromBundleMgr failed", userId, bundleName.c_str());
589         return nullptr;
590     }
591     if (!info.isNewIme) {
592         info.prop.id = extName;
593         auto it = std::find_if(info.subProps.begin(), info.subProps.end(),
594             [&extName](const SubProperty &subProp) { return subProp.id == extName; });
595         if (it != info.subProps.end()) {
596             info.subProp = *it;
597         }
598     }
599     std::lock_guard<std::mutex> lock(defaultImeInfoLock_);
600     defaultImeInfo_ = std::make_shared<ImeInfo>(info);
601     return defaultImeInfo_;
602 }
603 
GetDefaultIme()604 std::string ImeInfoInquirer::GetDefaultIme()
605 {
606     char value[CONFIG_LEN] = { 0 };
607     auto code = GetParameter(DEFAULT_IME_KEY, "", value, CONFIG_LEN);
608     return code > 0 ? value : "";
609 }
610 
GetBundleMgr()611 sptr<OHOS::AppExecFwk::IBundleMgr> ImeInfoInquirer::GetBundleMgr()
612 {
613     sptr<ISystemAbilityManager> systemAbilityManager =
614         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
615     if (systemAbilityManager == nullptr) {
616         IMSA_HILOGE("systemAbilityManager is nullptr");
617         return nullptr;
618     }
619     sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
620     if (remoteObject == nullptr) {
621         IMSA_HILOGE("remoteObject is nullptr");
622         return nullptr;
623     }
624     return iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
625 }
626 
GetImeSubProp(const std::vector<SubProperty> & subProps,const Condition & condition)627 std::shared_ptr<SubProperty> ImeInfoInquirer::GetImeSubProp(
628     const std::vector<SubProperty> &subProps, const Condition &condition)
629 {
630     auto it = subProps.end();
631     switch (condition) {
632         case Condition::UPPER: {
633             it = std::find_if(
634                 subProps.begin(), subProps.end(), [](const SubProperty &subProp) { return subProp.mode == "upper"; });
635             break;
636         }
637         case Condition::LOWER: {
638             it = std::find_if(
639                 subProps.begin(), subProps.end(), [](const SubProperty &subProp) { return subProp.mode == "lower"; });
640             break;
641         }
642         case Condition::ENGLISH: {
643             it = std::find_if(subProps.begin(), subProps.end(),
644                 [](const SubProperty &subProp) { return subProp.language == "english" && subProp.mode == "lower"; });
645             break;
646         }
647         case Condition::CHINESE: {
648             it = std::find_if(subProps.begin(), subProps.end(),
649                 [](const SubProperty &subProp) { return subProp.language == "chinese"; });
650             break;
651         }
652         default: {
653             break;
654         }
655     }
656     if (it == subProps.end()) {
657         return nullptr;
658     }
659     return std::make_shared<SubProperty>(*it);
660 }
661 
ParseSubProp(const std::vector<std::string> & profiles,std::vector<SubProperty> & subProps)662 bool ImeInfoInquirer::ParseSubProp(const std::vector<std::string> &profiles, std::vector<SubProperty> &subProps)
663 {
664     if (profiles.empty() || profiles.size() != SUBTYPE_PROFILE_NUM) {
665         IMSA_HILOGE("profiles size: %{public}zu", profiles.size());
666         return false;
667     }
668     json jsonSubProps;
669     SubProperty subProp;
670     IMSA_HILOGD("profiles[0]: %{public}s", profiles[0].c_str());
671     jsonSubProps = json::parse(profiles[0], nullptr, false);
672     if (jsonSubProps.is_null() || jsonSubProps.is_discarded() || !jsonSubProps.contains("subtypes")
673         || !jsonSubProps["subtypes"].is_array() || jsonSubProps["subtypes"].empty()) {
674         IMSA_HILOGE("json parse failed");
675         return false;
676     }
677     ParseSubProp(jsonSubProps, subProps);
678     return true;
679 }
680 
ParseSubProp(const json & jsonSubProps,std::vector<SubProperty> & subProps)681 void ImeInfoInquirer::ParseSubProp(const json &jsonSubProps, std::vector<SubProperty> &subProps)
682 {
683     IMSA_HILOGD("subType num: %{public}zu", jsonSubProps["subtypes"].size());
684     for (auto &jsonCfg : jsonSubProps["subtypes"]) {
685         if (subProps.size() >= MAX_SUBTYPE_NUM) {
686             break;
687         }
688         SubProperty subProp;
689         ParseSubProp(jsonCfg, subProp);
690         subProps.push_back(subProp);
691     }
692 }
693 
ParseSubProp(const json & jsonSubProp,SubProperty & subProp)694 void ImeInfoInquirer::ParseSubProp(const json &jsonSubProp, SubProperty &subProp)
695 {
696     if (jsonSubProp.find("label") != jsonSubProp.end() && jsonSubProp["label"].is_string()) {
697         jsonSubProp.at("label").get_to(subProp.label);
698     }
699     if (jsonSubProp.find("id") != jsonSubProp.end() && jsonSubProp["id"].is_string()) {
700         jsonSubProp.at("id").get_to(subProp.id);
701     }
702     if (jsonSubProp.find("icon") != jsonSubProp.end() && jsonSubProp["icon"].is_string()) {
703         jsonSubProp.at("icon").get_to(subProp.icon);
704     }
705     if (jsonSubProp.find("mode") != jsonSubProp.end() && jsonSubProp["mode"].is_string()) {
706         jsonSubProp.at("mode").get_to(subProp.mode);
707     }
708     if (jsonSubProp.find("locale") != jsonSubProp.end() && jsonSubProp["locale"].is_string()) {
709         jsonSubProp.at("locale").get_to(subProp.locale);
710     }
711 }
712 } // namespace MiscServices
713 } // namespace OHOS