• 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 "config_policy_utils.h"
24 #include "global.h"
25 #include "if_system_ability_manager.h"
26 #include "ime_cfg_manager.h"
27 #include "input_method_config_parser.h"
28 #include "input_method_info.h"
29 #include "input_type_manager.h"
30 #include "iservice_registry.h"
31 #include "parameter.h"
32 #include "string_ex.h"
33 #include "system_ability.h"
34 #include "system_ability_definition.h"
35 
36 namespace OHOS {
37 namespace MiscServices {
38 namespace {
39 using json = nlohmann::json;
40 using namespace OHOS::AppExecFwk;
41 constexpr const char *SUBTYPE_PROFILE_METADATA_NAME = "ohos.extension.input_method";
42 const std::string SYSTEM_CONFIG = "systemConfig";
43 const std::string SYSTEM_INPUT_METHOD_CONFIG_ABILITY = "systemInputMethodConfigAbility";
44 const std::string DEFAULT_INPUT_METHOD = "defaultInputMethod";
45 const std::string ENABLE_INPUT_METHOD_FEATURE = "enableInputMethodFeature";
46 const std::string ENABLE_FULL_EXPERIENCE_FEATURE = "enableFullExperienceFeature";
47 constexpr uint32_t SUBTYPE_PROFILE_NUM = 1;
48 constexpr uint32_t MAX_SUBTYPE_NUM = 256;
49 constexpr const char *DEFAULT_IME_KEY = "persist.sys.default_ime";
50 constexpr int32_t CONFIG_LEN = 128;
51 } // namespace
52 
from_json(const nlohmann::json & jsonConfigs,ImeConfig & config)53 void from_json(const nlohmann::json &jsonConfigs, ImeConfig &config)
54 {
55     if (jsonConfigs.find(SYSTEM_INPUT_METHOD_CONFIG_ABILITY) != jsonConfigs.end()
56         && jsonConfigs[SYSTEM_INPUT_METHOD_CONFIG_ABILITY].is_string()) {
57         jsonConfigs.at(SYSTEM_INPUT_METHOD_CONFIG_ABILITY).get_to(config.systemInputMethodConfigAbility);
58     }
59     if (jsonConfigs.find(DEFAULT_INPUT_METHOD) != jsonConfigs.end() && jsonConfigs[DEFAULT_INPUT_METHOD].is_string()) {
60         jsonConfigs.at(DEFAULT_INPUT_METHOD).get_to(config.defaultInputMethod);
61     }
62     if (jsonConfigs.find(ENABLE_INPUT_METHOD_FEATURE) != jsonConfigs.end()
63         && jsonConfigs[ENABLE_INPUT_METHOD_FEATURE].is_boolean()) {
64         jsonConfigs.at(ENABLE_INPUT_METHOD_FEATURE).get_to(config.enableInputMethodFeature);
65     }
66     if (jsonConfigs.find(ENABLE_FULL_EXPERIENCE_FEATURE) != jsonConfigs.end()
67         && jsonConfigs[ENABLE_FULL_EXPERIENCE_FEATURE].is_boolean()) {
68         jsonConfigs.at(ENABLE_FULL_EXPERIENCE_FEATURE).get_to(config.enableFullExperienceFeature);
69     }
70 }
71 
GetInstance()72 ImeInfoInquirer &ImeInfoInquirer::GetInstance()
73 {
74     static ImeInfoInquirer instance;
75     return instance;
76 }
77 
InitConfig()78 void ImeInfoInquirer::InitConfig()
79 {
80     ImeConfigParse::ParseFromCustomSystem(SYSTEM_CONFIG, imeConfig_);
81 }
82 
IsEnableInputMethod()83 bool ImeInfoInquirer::IsEnableInputMethod()
84 {
85     return imeConfig_.enableInputMethodFeature;
86 }
87 
IsEnableSecurityMode()88 bool ImeInfoInquirer::IsEnableSecurityMode()
89 {
90     return imeConfig_.enableFullExperienceFeature;
91 }
92 
QueryImeExtInfos(const int32_t userId,std::vector<ExtensionAbilityInfo> & infos)93 bool ImeInfoInquirer::QueryImeExtInfos(const int32_t userId, std::vector<ExtensionAbilityInfo> &infos)
94 {
95     IMSA_HILOGD("userId: %{public}d", userId);
96     auto bundleMgr = GetBundleMgr();
97     if (bundleMgr == nullptr) {
98         IMSA_HILOGE("GetBundleMgr failed");
99         return false;
100     }
101     if (!bundleMgr->QueryExtensionAbilityInfos(ExtensionAbilityType::INPUTMETHOD, userId, infos)) {
102         IMSA_HILOGF("Query extension infos failed from bundleMgr!");
103         return false;
104     }
105     return true;
106 }
107 
GetExtInfosByBundleName(const int32_t userId,const std::string & bundleName,std::vector<AppExecFwk::ExtensionAbilityInfo> & extInfos)108 int32_t ImeInfoInquirer::GetExtInfosByBundleName(
109     const int32_t userId, const std::string &bundleName, std::vector<AppExecFwk::ExtensionAbilityInfo> &extInfos)
110 {
111     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s", userId, bundleName.c_str());
112     std::vector<AppExecFwk::ExtensionAbilityInfo> tempExtInfos;
113     if (!QueryImeExtInfos(userId, tempExtInfos)) {
114         IMSA_HILOGE("QueryImeExtInfos failed!");
115         return ErrorCode::ERROR_BAD_PARAMETERS;
116     }
117     for (const auto &extInfo : tempExtInfos) {
118         if (extInfo.bundleName == bundleName) {
119             extInfos.emplace_back(extInfo);
120         }
121     }
122     if (extInfos.empty()) {
123         IMSA_HILOGE("bundleName: %{public}s extInfos is empty", bundleName.c_str());
124         return ErrorCode::ERROR_BAD_PARAMETERS;
125     }
126     return ErrorCode::NO_ERROR;
127 }
128 
GetImeInfo(int32_t userId,const std::string & bundleName,const std::string & subName)129 std::shared_ptr<ImeInfo> ImeInfoInquirer::GetImeInfo(
130     int32_t userId, const std::string &bundleName, const std::string &subName)
131 {
132     auto info = GetImeInfoFromCache(userId, bundleName, subName);
133     return info == nullptr ? GetImeInfoFromBundleMgr(userId, bundleName, subName) : info;
134 }
135 
GetImeInfoFromCache(const int32_t userId,const std::string & bundleName,const std::string & subName)136 std::shared_ptr<ImeInfo> ImeInfoInquirer::GetImeInfoFromCache(
137     const int32_t userId, const std::string &bundleName, const std::string &subName)
138 {
139     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s, subName: %{public}s", userId, bundleName.c_str(),
140         subName.c_str());
141     auto info = GetCurrentImeInfo();
142     if (info == nullptr || bundleName != info->prop.name) {
143         return nullptr;
144     }
145     if (subName == info->subProp.id) {
146         return std::make_shared<ImeInfo>(*info);
147     }
148 
149     auto newInfo = std::make_shared<ImeInfo>(*info);
150     auto it = std::find_if(newInfo->subProps.begin(), newInfo->subProps.end(),
151         [&subName](const SubProperty &subProp) { return subProp.id == subName; });
152     if (it == newInfo->subProps.end()) {
153         IMSA_HILOGE("Find subName: %{public}s failed", subName.c_str());
154         return nullptr;
155     }
156     newInfo->subProp = *it;
157     // old ime, make the id of prop same with the id of subProp.
158     if (!newInfo->isNewIme) {
159         newInfo->prop.id = newInfo->subProp.id;
160     }
161     return newInfo;
162 }
163 
GetImeInfoFromBundleMgr(const int32_t userId,const std::string & bundleName,const std::string & subName)164 std::shared_ptr<ImeInfo> ImeInfoInquirer::GetImeInfoFromBundleMgr(
165     const int32_t userId, const std::string &bundleName, const std::string &subName)
166 {
167     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s, subName: %{public}s", userId, bundleName.c_str(),
168         subName.c_str());
169     std::vector<AppExecFwk::ExtensionAbilityInfo> extInfos;
170     auto ret = ImeInfoInquirer::GetInstance().GetExtInfosByBundleName(userId, bundleName, extInfos);
171     if (ret != ErrorCode::NO_ERROR || extInfos.empty()) {
172         IMSA_HILOGE("userId: %{public}d getExtInfosByBundleName %{public}s failed", userId, bundleName.c_str());
173         return nullptr;
174     }
175     auto info = std::make_shared<ImeInfo>();
176     info->moduleName = extInfos[0].moduleName;
177     info->prop.name = extInfos[0].bundleName;
178     info->prop.id = extInfos[0].name;
179     info->prop.label =
180         GetStringById(extInfos[0].bundleName, extInfos[0].moduleName, extInfos[0].applicationInfo.labelId, userId);
181     info->prop.labelId = extInfos[0].applicationInfo.labelId;
182     info->prop.iconId = extInfos[0].applicationInfo.iconId;
183 
184     std::vector<SubProperty> subProps;
185     info->isNewIme = IsNewExtInfos(extInfos);
186     ret = info->isNewIme ? ListInputMethodSubtype(userId, extInfos[0], subProps)
187                          : ListInputMethodSubtype(userId, extInfos, subProps);
188     if (ret != ErrorCode::NO_ERROR || subProps.empty()) {
189         IMSA_HILOGE("userId: %{public}d listInputMethodSubtype failed", userId);
190         return nullptr;
191     }
192     info->subProps = subProps;
193     if (subName.empty()) {
194         info->subProp = subProps[0];
195     } else {
196         auto it = std::find_if(subProps.begin(), subProps.end(),
197             [&subName](const SubProperty &subProp) { return subProp.id == subName; });
198         if (it == subProps.end()) {
199             IMSA_HILOGE("Find subName: %{public}s failed", subName.c_str());
200             return nullptr;
201         }
202         info->subProp = *it;
203     }
204     // old ime, make the id of prop same with the id of subProp.
205     if (!info->isNewIme) {
206         info->prop.id = info->subProp.id;
207     }
208     return info;
209 }
210 
SetCurrentImeInfo(std::shared_ptr<ImeInfo> info)211 void ImeInfoInquirer::SetCurrentImeInfo(std::shared_ptr<ImeInfo> info)
212 {
213     std::lock_guard<std::mutex> lock(currentImeInfoLock_);
214     currentImeInfo_ = std::move(info);
215 }
216 
InitCache(int32_t userId)217 void ImeInfoInquirer::InitCache(int32_t userId)
218 {
219     IMSA_HILOGD("userId: %{public}d", userId);
220     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
221     auto info = GetImeInfoFromBundleMgr(userId, currentImeCfg->bundleName, currentImeCfg->subName);
222     if (info == nullptr) {
223         IMSA_HILOGE("userId: %{public}d, bundleName: %{public}s, subName: %{public}s getImeInfoFromBundleMgr failed",
224             userId, currentImeCfg->bundleName.c_str(), currentImeCfg->subName.c_str());
225         return;
226     }
227     SetCurrentImeInfo(info);
228 }
229 
GetCurrentImeInfo()230 std::shared_ptr<ImeInfo> ImeInfoInquirer::GetCurrentImeInfo()
231 {
232     std::lock_guard<std::mutex> lock(currentImeInfoLock_);
233     return currentImeInfo_;
234 }
235 
RefreshCurrentImeInfo(int32_t userId)236 void ImeInfoInquirer::RefreshCurrentImeInfo(int32_t userId)
237 {
238     IMSA_HILOGD("run in");
239     std::lock_guard<std::mutex> lock(currentImeInfoLock_);
240     if (currentImeInfo_ == nullptr) {
241         IMSA_HILOGD("currentImeInfo is nullptr");
242         return;
243     }
244     for (auto &subProp : currentImeInfo_->subProps) {
245         subProp.label = GetStringById(subProp.name, currentImeInfo_->moduleName, subProp.labelId, userId);
246         if (currentImeInfo_->subProp.id == subProp.id) {
247             currentImeInfo_->subProp.label = subProp.label;
248         }
249     }
250     currentImeInfo_->prop.label =
251         GetStringById(currentImeInfo_->prop.name, currentImeInfo_->moduleName, currentImeInfo_->prop.labelId, userId);
252 }
253 
GetDumpInfo(int32_t userId)254 std::string ImeInfoInquirer::GetDumpInfo(int32_t userId)
255 {
256     auto properties = ListInputMethodInfo(userId);
257     if (properties.empty()) {
258         return "";
259     }
260     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
261     bool isBegin = true;
262     std::string params = "{\"imeList\":[";
263     for (const auto &property : properties) {
264         params += isBegin ? "" : "},";
265         isBegin = false;
266 
267         std::string imeId = property.mPackageName + "/" + property.mAbilityName;
268         params += "{\"ime\": \"" + imeId + "\",";
269         params += "\"labelId\": \"" + std::to_string(property.labelId) + "\",";
270         params += "\"descriptionId\": \"" + std::to_string(property.descriptionId) + "\",";
271         std::string isCurrentIme = currentImeCfg->imeId == imeId ? "true" : "false";
272         params += "\"isCurrentIme\": \"" + isCurrentIme + "\",";
273         params += "\"label\": \"" + property.label + "\",";
274         params += "\"description\": \"" + property.description + "\"";
275     }
276     params += "}]}";
277     return params;
278 }
279 
ListInputMethodInfo(const int32_t userId)280 std::vector<InputMethodInfo> ImeInfoInquirer::ListInputMethodInfo(const int32_t userId)
281 {
282     IMSA_HILOGD("userId: %{public}d", userId);
283     std::vector<ExtensionAbilityInfo> extensionInfos;
284     if (!QueryImeExtInfos(userId, extensionInfos)) {
285         IMSA_HILOGE("userId: %{public}d queryImeExtInfos failed", userId);
286         return {};
287     }
288     std::vector<InputMethodInfo> properties;
289     for (const auto &extension : extensionInfos) {
290         auto applicationInfo = extension.applicationInfo;
291         auto label = GetStringById(extension.bundleName, extension.moduleName, applicationInfo.labelId, userId);
292         auto description =
293             GetStringById(extension.bundleName, extension.moduleName, applicationInfo.descriptionId, userId);
294         InputMethodInfo property;
295         property.mPackageName = extension.bundleName;
296         property.mAbilityName = extension.name;
297         property.labelId = applicationInfo.labelId;
298         property.descriptionId = applicationInfo.descriptionId;
299         property.label = label;
300         property.description = description;
301         properties.emplace_back(property);
302     }
303     return properties;
304 }
305 
ListInputMethod(int32_t userId,InputMethodStatus status,std::vector<Property> & props,bool enableOn)306 int32_t ImeInfoInquirer::ListInputMethod(
307     int32_t userId, InputMethodStatus status, std::vector<Property> &props, bool enableOn)
308 {
309     IMSA_HILOGD("userId: %{public}d, status: %{public}d", userId, status);
310     if (status == InputMethodStatus::ALL) {
311         return ListInputMethod(userId, props);
312     }
313     if (status == InputMethodStatus::ENABLE) {
314         return ListEnabledInputMethod(userId, props, enableOn);
315     }
316     if (status == InputMethodStatus::DISABLE) {
317         return ListDisabledInputMethod(userId, props, enableOn);
318     }
319     return ErrorCode::ERROR_BAD_PARAMETERS;
320 }
321 
ListInputMethod(const int32_t userId,std::vector<Property> & props)322 int32_t ImeInfoInquirer::ListInputMethod(const int32_t userId, std::vector<Property> &props)
323 {
324     IMSA_HILOGD("userId: %{public}d", userId);
325     std::vector<ExtensionAbilityInfo> extensionInfos;
326     if (!QueryImeExtInfos(userId, extensionInfos)) {
327         IMSA_HILOGE("QueryImeExtInfos failed!");
328         return ErrorCode::ERROR_BAD_PARAMETERS;
329     }
330     for (const auto &extension : extensionInfos) {
331         auto it = std::find_if(props.begin(), props.end(),
332             [&extension](const Property &prop) { return prop.name == extension.bundleName; });
333         if (it != props.end()) {
334             continue;
335         }
336         props.push_back({ .name = extension.bundleName,
337             .id = extension.name,
338             .label =
339                 GetStringById(extension.bundleName, extension.moduleName, extension.applicationInfo.labelId, userId),
340             .labelId = extension.applicationInfo.labelId,
341             .iconId = extension.applicationInfo.iconId });
342     }
343     return ErrorCode::NO_ERROR;
344 }
345 
ListEnabledInputMethod(const int32_t userId,std::vector<Property> & props,bool enableOn)346 int32_t ImeInfoInquirer::ListEnabledInputMethod(const int32_t userId, std::vector<Property> &props, bool enableOn)
347 {
348     IMSA_HILOGD("userId: %{public}d", userId);
349     int32_t ret = ListInputMethod(userId, props);
350     if (ret != ErrorCode::NO_ERROR) {
351         IMSA_HILOGE("userId: %{public}d listInputMethod failed", userId);
352         return ret;
353     }
354     if (enableOn) {
355         IMSA_HILOGD("enable on");
356         std::vector<std::string> enableVec;
357         ret = EnableImeDataParser::GetInstance()->GetEnableData(EnableImeDataParser::ENABLE_IME, enableVec, userId);
358         if (ret != ErrorCode::NO_ERROR) {
359             IMSA_HILOGE("Get enable data failed;");
360             return ret;
361         }
362         auto info = GetDefaultImeInfo(userId);
363         if (info != nullptr) {
364             enableVec.insert(enableVec.begin(), info->prop.name);
365         }
366 
367         auto newEnd = std::remove_if(props.begin(), props.end(), [&enableVec](const auto &prop) {
368             return std::find(enableVec.begin(), enableVec.end(), prop.name) == enableVec.end();
369         });
370         props.erase(newEnd, props.end());
371     }
372     return ErrorCode::NO_ERROR;
373 }
374 
ListDisabledInputMethod(const int32_t userId,std::vector<Property> & props,bool enableOn)375 int32_t ImeInfoInquirer::ListDisabledInputMethod(const int32_t userId, std::vector<Property> &props, bool enableOn)
376 {
377     IMSA_HILOGD("userId: %{public}d", userId);
378     if (!enableOn) {
379         IMSA_HILOGD("Enable mode off, get disabled ime.");
380         return ErrorCode::NO_ERROR;
381     }
382 
383     auto ret = ListInputMethod(userId, props);
384     if (ret != ErrorCode::NO_ERROR) {
385         IMSA_HILOGE("userId: %{public}d listInputMethod failed", userId);
386         return ret;
387     }
388 
389     std::vector<std::string> enableVec;
390     ret = EnableImeDataParser::GetInstance()->GetEnableData(EnableImeDataParser::ENABLE_IME, enableVec, userId);
391     if (ret != ErrorCode::NO_ERROR) {
392         IMSA_HILOGE("Get enable data failed;");
393         return ret;
394     }
395     auto info = GetDefaultImeInfo(userId);
396     if (info != nullptr) {
397         enableVec.insert(enableVec.begin(), info->prop.name);
398     }
399 
400     auto newEnd = std::remove_if(props.begin(), props.end(), [&enableVec](const auto &prop) {
401         return std::find(enableVec.begin(), enableVec.end(), prop.name) != enableVec.end();
402     });
403     props.erase(newEnd, props.end());
404     return ErrorCode::NO_ERROR;
405 }
406 
GetNextSwitchInfo(SwitchInfo & switchInfo,int32_t userId,bool enableOn)407 int32_t ImeInfoInquirer::GetNextSwitchInfo(SwitchInfo &switchInfo, int32_t userId, bool enableOn)
408 {
409     std::vector<Property> props;
410     auto ret = ListEnabledInputMethod(userId, props, enableOn);
411     if (ret != ErrorCode::NO_ERROR) {
412         IMSA_HILOGE("userId: %{public}d ListEnabledInputMethod failed", userId);
413         return ret;
414     }
415     auto currentImeBundle = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId)->bundleName;
416     auto iter = std::find_if(props.begin(), props.end(),
417         [&currentImeBundle](const Property &property) { return property.name == currentImeBundle; });
418     if (iter == props.end()) {
419         IMSA_HILOGE("Can not found current ime in enable list");
420         auto info = GetDefaultImeInfo(userId);
421         if (info != nullptr) {
422             switchInfo.bundleName = info->prop.name;
423             return ErrorCode::NO_ERROR;
424         }
425         IMSA_HILOGE("bundle manager error");
426         return ErrorCode::ERROR_PACKAGE_MANAGER;
427     }
428     auto nextIter = std::next(iter);
429     switchInfo.bundleName = nextIter == props.end() ? props[0].name: nextIter->name;
430     IMSA_HILOGD("Next ime: %{public}s", switchInfo.bundleName.c_str());
431     return ErrorCode::NO_ERROR;
432 }
433 
ListInputMethodSubtype(int32_t userId,const std::string & bundleName,std::vector<SubProperty> & subProps)434 int32_t ImeInfoInquirer::ListInputMethodSubtype(
435     int32_t userId, const std::string &bundleName, std::vector<SubProperty> &subProps)
436 {
437     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s", userId, bundleName.c_str());
438     std::vector<ExtensionAbilityInfo> extInfos;
439     auto ret = GetExtInfosByBundleName(userId, bundleName, extInfos);
440     if (ret != ErrorCode::NO_ERROR) {
441         IMSA_HILOGE("userId: %{public}d getExtInfosByBundleName %{public}s failed", userId, bundleName.c_str());
442         return ret;
443     }
444     return IsNewExtInfos(extInfos) ? ListInputMethodSubtype(userId, extInfos[0], subProps)
445                                    : ListInputMethodSubtype(userId, extInfos, subProps);
446 }
447 
ListCurrentInputMethodSubtype(int32_t userId,std::vector<SubProperty> & subProps)448 int32_t ImeInfoInquirer::ListCurrentInputMethodSubtype(int32_t userId, std::vector<SubProperty> &subProps)
449 {
450     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
451     IMSA_HILOGD("currentIme: %{public}s", currentImeCfg->imeId.c_str());
452     return ListInputMethodSubtype(userId, currentImeCfg->bundleName, subProps);
453 }
454 
IsNewExtInfos(const std::vector<ExtensionAbilityInfo> & extInfos)455 bool ImeInfoInquirer::IsNewExtInfos(const std::vector<ExtensionAbilityInfo> &extInfos)
456 {
457     if (extInfos.empty()) {
458         IMSA_HILOGE("extInfos is empty");
459         return false;
460     }
461     auto iter = std::find_if(extInfos[0].metadata.begin(), extInfos[0].metadata.end(),
462         [](const Metadata &metadata) { return metadata.name == SUBTYPE_PROFILE_METADATA_NAME; });
463     return iter != extInfos[0].metadata.end();
464 }
465 
ListInputMethodSubtype(const int32_t userId,const std::vector<ExtensionAbilityInfo> & extInfos,std::vector<SubProperty> & subProps)466 int32_t ImeInfoInquirer::ListInputMethodSubtype(
467     const int32_t userId, const std::vector<ExtensionAbilityInfo> &extInfos, std::vector<SubProperty> &subProps)
468 {
469     IMSA_HILOGD("oldIme, userId: %{public}d", userId);
470     for (const auto &extInfo : extInfos) {
471         SubProperty subProperty;
472         subProperty.labelId = extInfo.labelId;
473         subProperty.label = GetStringById(extInfo.bundleName, extInfo.moduleName, extInfo.labelId, userId);
474         subProperty.id = extInfo.name;
475         subProperty.name = extInfo.bundleName;
476         subProperty.iconId = extInfo.iconId;
477         std::vector<Metadata> extends = extInfo.metadata;
478         auto property = GetExtends(extends);
479         subProperty.language = property.language;
480         subProperty.mode = property.mode;
481         subProperty.locale = property.locale;
482         subProperty.icon = property.icon;
483         subProps.emplace_back(subProperty);
484     }
485     return ErrorCode::NO_ERROR;
486 }
487 
ListInputMethodSubtype(const int32_t userId,const ExtensionAbilityInfo & extInfo,std::vector<SubProperty> & subProps)488 int32_t ImeInfoInquirer::ListInputMethodSubtype(
489     const int32_t userId, const ExtensionAbilityInfo &extInfo, std::vector<SubProperty> &subProps)
490 {
491     IMSA_HILOGD("newIme, userId: %{public}d", userId);
492     auto iter = std::find_if(extInfo.metadata.begin(), extInfo.metadata.end(),
493         [](const Metadata &metadata) { return metadata.name == SUBTYPE_PROFILE_METADATA_NAME; });
494     if (iter == extInfo.metadata.end()) {
495         IMSA_HILOGE("find metadata name:SUBTYPE_PROFILE_METADATA_NAME failed");
496         return ErrorCode::ERROR_BAD_PARAMETERS;
497     }
498     OHOS::AppExecFwk::BundleMgrClientImpl clientImpl;
499     std::vector<std::string> profiles;
500     if (!clientImpl.GetResConfigFile(extInfo, iter->name, profiles)) {
501         IMSA_HILOGE("GetProfileFromExtension failed");
502         return ErrorCode::ERROR_PACKAGE_MANAGER;
503     }
504     if (!ParseSubProp(profiles, subProps)) {
505         IMSA_HILOGE("ParseSubProp failed");
506         return ErrorCode::ERROR_BAD_PARAMETERS;
507     }
508     IMSA_HILOGD("subProps size: %{public}zu", subProps.size());
509     for (auto it = subProps.begin(); it != subProps.end();) {
510         auto subProp = *it;
511         // subtype which provides a particular input type should not appear in the subtype list
512         if (InputTypeManager::GetInstance().IsInputType({ subProp.name, subProp.id })) {
513             it = subProps.erase(it);
514             continue;
515         }
516         subProp.name = extInfo.bundleName;
517         auto pos = subProp.label.find(':');
518         if (pos != std::string::npos && pos + 1 < subProp.label.size()) {
519             subProp.labelId = atoi(subProp.label.substr(pos + 1).c_str());
520             subProp.label = GetStringById(extInfo.bundleName, extInfo.moduleName, subProp.labelId, userId);
521         }
522         pos = subProp.icon.find(':');
523         if (pos != std::string::npos && pos + 1 < subProp.icon.size()) {
524             subProp.iconId = atoi(subProp.icon.substr(pos + 1).c_str());
525         }
526         ParseLanguage(subProp.locale, subProp.language);
527         *it = subProp;
528         ++it;
529     }
530     return ErrorCode::NO_ERROR;
531 }
532 
ParseLanguage(const std::string & locale,std::string & language)533 void ImeInfoInquirer::ParseLanguage(const std::string &locale, std::string &language)
534 {
535     language = locale;
536     auto pos = locale.find('-');
537     if (pos != std::string::npos) {
538         language = locale.substr(0, pos);
539     }
540     // compatible with the locale configuration of original ime
541     pos = locale.find('_');
542     if (pos != std::string::npos) {
543         language = locale.substr(0, pos);
544     }
545     if (language == "en") {
546         language = "english";
547     }
548     if (language == "zh") {
549         language = "chinese";
550     }
551 }
552 
GetStringById(const std::string & bundleName,const std::string & moduleName,int32_t labelId,int32_t userId)553 std::string ImeInfoInquirer::GetStringById(
554     const std::string &bundleName, const std::string &moduleName, int32_t labelId, int32_t userId)
555 {
556     auto bundleMgr = GetBundleMgr();
557     return bundleMgr == nullptr ? "" : bundleMgr->GetStringById(bundleName, moduleName, labelId, userId);
558 }
559 
GetExtends(const std::vector<Metadata> & metaData)560 SubProperty ImeInfoInquirer::GetExtends(const std::vector<Metadata> &metaData)
561 {
562     SubProperty property;
563     for (const auto &data : metaData) {
564         if (data.name == "language") {
565             property.language = data.value;
566             continue;
567         }
568         if (data.name == "mode") {
569             property.mode = data.value;
570             continue;
571         }
572         if (data.name == "locale") {
573             property.locale = data.value;
574             continue;
575         }
576         if (data.name == "icon") {
577             property.icon = data.value;
578         }
579     }
580     return property;
581 }
582 
GetImeByBundleName(int32_t userId,const std::string & bundleName)583 std::shared_ptr<Property> ImeInfoInquirer::GetImeByBundleName(int32_t userId, const std::string &bundleName)
584 {
585     IMSA_HILOGD("run in, bundleName: %{public}s", bundleName.c_str());
586     std::vector<AppExecFwk::ExtensionAbilityInfo> extInfos;
587     auto ret = ImeInfoInquirer::GetInstance().GetExtInfosByBundleName(userId, bundleName, extInfos);
588     if (ret != ErrorCode::NO_ERROR || extInfos.empty()) {
589         IMSA_HILOGE("userId: %{public}d getExtInfosByBundleName %{public}s failed", userId, bundleName.c_str());
590         return nullptr;
591     }
592     Property prop = { .name = extInfos[0].bundleName,
593         .id = extInfos[0].name,
594         .label = extInfos[0].applicationInfo.label,
595         .labelId = extInfos[0].applicationInfo.labelId,
596         .iconId = extInfos[0].applicationInfo.iconId };
597     return std::make_shared<Property>(prop);
598 }
599 
GetCurrentInputMethod(int32_t userId)600 std::shared_ptr<Property> ImeInfoInquirer::GetCurrentInputMethod(int32_t userId)
601 {
602     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
603     IMSA_HILOGD("currentIme: %{public}s", currentImeCfg->imeId.c_str());
604     std::vector<AppExecFwk::ExtensionAbilityInfo> extInfos;
605     auto ret = ImeInfoInquirer::GetInstance().GetExtInfosByBundleName(userId, currentImeCfg->bundleName, extInfos);
606     if (ret != ErrorCode::NO_ERROR || extInfos.empty()) {
607         IMSA_HILOGE(
608             "userId: %{public}d getExtInfosByBundleName %{public}s failed", userId, currentImeCfg->bundleName.c_str());
609         return nullptr;
610     }
611     Property prop = { .name = extInfos[0].bundleName,
612         .id = currentImeCfg->extName, // if old ime, the extInfos[0].name maybe not same with currentImeExtName
613         .label =
614             GetStringById(extInfos[0].bundleName, extInfos[0].moduleName, extInfos[0].applicationInfo.labelId, userId),
615         .labelId = extInfos[0].applicationInfo.labelId,
616         .iconId = extInfos[0].applicationInfo.iconId };
617     return std::make_shared<Property>(prop);
618 }
619 
GetCurrentSubtype(int32_t userId)620 std::shared_ptr<SubProperty> ImeInfoInquirer::GetCurrentSubtype(int32_t userId)
621 {
622     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
623     IMSA_HILOGD("currentIme: %{public}s", currentImeCfg->imeId.c_str());
624     std::vector<SubProperty> subProps = {};
625     auto ret = ListInputMethodSubtype(userId, currentImeCfg->bundleName, subProps);
626     if (ret != ErrorCode::NO_ERROR || subProps.empty()) {
627         IMSA_HILOGE("userId: %{public}d listInputMethodSubtype by bundleName: %{public}s failed", userId,
628             currentImeCfg->bundleName.c_str());
629         return nullptr;
630     }
631     auto it = std::find_if(subProps.begin(), subProps.end(),
632         [&currentImeCfg](const SubProperty &subProp) { return subProp.id == currentImeCfg->subName; });
633     if (it != subProps.end()) {
634         return std::make_shared<SubProperty>(*it);
635     }
636     IMSA_HILOGE("Find subName: %{public}s failed", currentImeCfg->subName.c_str());
637     return std::make_shared<SubProperty>(subProps[0]);
638 }
639 
IsImeInstalled(const int32_t userId,const std::string & bundleName,const std::string & extName)640 bool ImeInfoInquirer::IsImeInstalled(const int32_t userId, const std::string &bundleName, const std::string &extName)
641 {
642     IMSA_HILOGD("userId: %{public}d, bundleName: %{public}s, extName: %{public}s", userId, bundleName.c_str(),
643         extName.c_str());
644     std::vector<OHOS::AppExecFwk::ExtensionAbilityInfo> extInfos;
645     GetExtInfosByBundleName(userId, bundleName, extInfos);
646     auto iter = std::find_if(extInfos.begin(), extInfos.end(),
647         [&bundleName, &extName](const OHOS::AppExecFwk::ExtensionAbilityInfo &extInfo) {
648             return extInfo.bundleName == bundleName && extName == extInfo.name;
649         });
650     if (iter == extInfos.end()) {
651         IMSA_HILOGE("false");
652         return false;
653     }
654     IMSA_HILOGI("true");
655     return true;
656 }
657 
GetImeToStart(int32_t userId)658 std::shared_ptr<ImeNativeCfg> ImeInfoInquirer::GetImeToStart(int32_t userId)
659 {
660     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId);
661     IMSA_HILOGD("userId: %{public}d, currentIme: %{public}s", userId, currentImeCfg->imeId.c_str());
662     if (currentImeCfg->imeId.empty() || !IsImeInstalled(userId, currentImeCfg->bundleName, currentImeCfg->extName)) {
663         auto newIme = GetDefaultIme();
664         auto info = GetDefaultImeInfo(userId);
665         if (info == nullptr) {
666             IMSA_HILOGE("GetDefaultImeInfo failed");
667             newIme.subName = "";
668         } else {
669             newIme.subName = info->subProp.id;
670             SetCurrentImeInfo(info);
671         }
672         currentImeCfg->imeId.empty()
673             ? ImeCfgManager::GetInstance().AddImeCfg({ userId, newIme.imeId, newIme.subName })
674             : ImeCfgManager::GetInstance().ModifyImeCfg({ userId, newIme.imeId, newIme.subName });
675         return std::make_shared<ImeNativeCfg>(newIme);
676     }
677     // service start, user switch, set the currentImeInfo.
678     InitCache(userId);
679     return currentImeCfg;
680 }
681 
GetInputMethodConfig(const int32_t userId,AppExecFwk::ElementName & inputMethodConfig)682 int32_t ImeInfoInquirer::GetInputMethodConfig(const int32_t userId, AppExecFwk::ElementName &inputMethodConfig)
683 {
684     IMSA_HILOGD("userId: %{public}d", userId);
685     if (imeConfig_.systemInputMethodConfigAbility.empty()) {
686         IMSA_HILOGW("inputMethodConfig systemInputMethodConfigAbility is null");
687         return ErrorCode::NO_ERROR;
688     }
689     std::string bundleName = imeConfig_.systemInputMethodConfigAbility;
690     std::string moduleName;
691     std::string abilityName;
692     auto pos = bundleName.find('/');
693     if (pos != std::string::npos) {
694         abilityName = (pos + 1 < bundleName.size()) ? bundleName.substr(pos + 1) : "";
695         bundleName = bundleName.substr(0, pos);
696     }
697     pos = abilityName.find('/');
698     if (pos != std::string::npos) {
699         moduleName = abilityName.substr(0, pos);
700         abilityName = (pos + 1 < abilityName.size()) ? abilityName.substr(pos + 1) : "";
701     }
702     inputMethodConfig.SetBundleName(std::move(bundleName));
703     inputMethodConfig.SetModuleName(std::move(moduleName));
704     inputMethodConfig.SetAbilityName(std::move(abilityName));
705     return ErrorCode::NO_ERROR;
706 }
707 
GetDefaultInputMethod(const int32_t userId,std::shared_ptr<Property> & prop)708 int32_t ImeInfoInquirer::GetDefaultInputMethod(const int32_t userId, std::shared_ptr<Property> &prop)
709 {
710     IMSA_HILOGD("userId: %{public}d", userId);
711     auto imeInfo = GetDefaultImeInfo(userId);
712     if (imeInfo == nullptr) {
713         return ErrorCode::ERROR_NULL_POINTER;
714     }
715     IMSA_HILOGD("getDefaultInputMethod name: %{public}s", imeInfo->prop.name.c_str());
716     prop->name = imeInfo->prop.name;
717     prop->id = imeInfo->prop.id;
718     prop->label = imeInfo->prop.label;
719     prop->labelId = imeInfo->prop.labelId;
720     prop->iconId = imeInfo->prop.iconId;
721     return ErrorCode::NO_ERROR;
722 }
723 
GetDefaultImeInfo(int32_t userId)724 std::shared_ptr<ImeInfo> ImeInfoInquirer::GetDefaultImeInfo(int32_t userId)
725 {
726     auto defaultIme = GetDefaultImeCfgProp();
727     if (defaultIme == nullptr) {
728         IMSA_HILOGE("defaultIme is nullptr.");
729         return nullptr;
730     }
731     auto info = GetImeInfoFromBundleMgr(userId, defaultIme->name, "");
732     if (info == nullptr) {
733         IMSA_HILOGE("userId: %{public}d, bundleName: %{public}s getImeInfoFromBundleMgr failed", userId,
734             defaultIme->name.c_str());
735         return nullptr;
736     }
737     if (!info->isNewIme) {
738         info->prop.id = defaultIme->id;
739         auto it = std::find_if(info->subProps.begin(), info->subProps.end(),
740             [defaultIme](const SubProperty &subProp) { return subProp.id == defaultIme->id; });
741         if (it != info->subProps.end()) {
742             info->subProp = *it;
743         }
744     }
745     return info;
746 }
747 
GetDefaultIme()748 ImeNativeCfg ImeInfoInquirer::GetDefaultIme()
749 {
750     ImeNativeCfg imeCfg;
751     if (!imeConfig_.defaultInputMethod.empty()) {
752         IMSA_HILOGI("defaultInputMethod: %{public}s", imeConfig_.defaultInputMethod.c_str());
753         imeCfg.imeId = imeConfig_.defaultInputMethod;
754     } else {
755         char value[CONFIG_LEN] = { 0 };
756         auto code = GetParameter(DEFAULT_IME_KEY, "", value, CONFIG_LEN);
757         imeCfg.imeId = code > 0 ? value : "";
758     }
759     auto pos = imeCfg.imeId.find('/');
760     if (pos == std::string::npos || pos + 1 >= imeCfg.imeId.size()) {
761         IMSA_HILOGE("defaultIme: %{public}s is abnormal", imeCfg.imeId.c_str());
762         return {};
763     }
764     imeCfg.bundleName = imeCfg.imeId.substr(0, pos);
765     imeCfg.extName = imeCfg.imeId.substr(pos + 1);
766     return imeCfg;
767 }
768 
GetBundleMgr()769 sptr<OHOS::AppExecFwk::IBundleMgr> ImeInfoInquirer::GetBundleMgr()
770 {
771     sptr<ISystemAbilityManager> systemAbilityManager =
772         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
773     if (systemAbilityManager == nullptr) {
774         IMSA_HILOGE("systemAbilityManager is nullptr");
775         return nullptr;
776     }
777     sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
778     if (remoteObject == nullptr) {
779         IMSA_HILOGE("remoteObject is nullptr");
780         return nullptr;
781     }
782     return iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
783 }
784 
FindTargetSubtypeByCondition(const std::vector<SubProperty> & subProps,const Condition & condition)785 std::shared_ptr<SubProperty> ImeInfoInquirer::FindTargetSubtypeByCondition(
786     const std::vector<SubProperty> &subProps, const Condition &condition)
787 {
788     auto it = subProps.end();
789     switch (condition) {
790         case Condition::UPPER: {
791             it = std::find_if(
792                 subProps.begin(), subProps.end(), [](const SubProperty &subProp) { return subProp.mode == "upper"; });
793             break;
794         }
795         case Condition::LOWER: {
796             it = std::find_if(
797                 subProps.begin(), subProps.end(), [](const SubProperty &subProp) { return subProp.mode == "lower"; });
798             break;
799         }
800         case Condition::ENGLISH: {
801             it = std::find_if(subProps.begin(), subProps.end(),
802                 [](const SubProperty &subProp) { return subProp.language == "english" && subProp.mode == "lower"; });
803             break;
804         }
805         case Condition::CHINESE: {
806             it = std::find_if(subProps.begin(), subProps.end(),
807                 [](const SubProperty &subProp) { return subProp.language == "chinese"; });
808             break;
809         }
810         default: {
811             break;
812         }
813     }
814     if (it == subProps.end()) {
815         return nullptr;
816     }
817     return std::make_shared<SubProperty>(*it);
818 }
819 
ParseSubProp(const std::vector<std::string> & profiles,std::vector<SubProperty> & subProps)820 bool ImeInfoInquirer::ParseSubProp(const std::vector<std::string> &profiles, std::vector<SubProperty> &subProps)
821 {
822     if (profiles.empty() || profiles.size() != SUBTYPE_PROFILE_NUM) {
823         IMSA_HILOGE("profiles size: %{public}zu", profiles.size());
824         return false;
825     }
826     json jsonSubProps;
827     SubProperty subProp;
828     IMSA_HILOGD("profiles[0]: %{public}s", profiles[0].c_str());
829     jsonSubProps = json::parse(profiles[0], nullptr, false);
830     if (jsonSubProps.is_null() || jsonSubProps.is_discarded()) {
831         IMSA_HILOGE("json parse failed");
832         return false;
833     }
834     return ParseSubProp(jsonSubProps, subProps);
835 }
836 
ParseSubProp(const json & jsonSubProps,std::vector<SubProperty> & subProps)837 bool ImeInfoInquirer::ParseSubProp(const json &jsonSubProps, std::vector<SubProperty> &subProps)
838 {
839     if (!jsonSubProps.contains("subtypes") || !jsonSubProps["subtypes"].is_array() ||
840         jsonSubProps["subtypes"].empty()) {
841         IMSA_HILOGE("the context of json file is abnormal");
842         return false;
843     }
844     IMSA_HILOGD("subType num: %{public}zu", jsonSubProps["subtypes"].size());
845     for (auto &jsonCfg : jsonSubProps["subtypes"]) {
846         if (subProps.size() >= MAX_SUBTYPE_NUM) {
847             break;
848         }
849         SubProperty subProp;
850         ParseSubProp(jsonCfg, subProp);
851         subProps.push_back(subProp);
852     }
853     return true;
854 }
855 
ParseSubProp(const json & jsonSubProp,SubProperty & subProp)856 void ImeInfoInquirer::ParseSubProp(const json &jsonSubProp, SubProperty &subProp)
857 {
858     if (jsonSubProp.find("label") != jsonSubProp.end() && jsonSubProp["label"].is_string()) {
859         jsonSubProp.at("label").get_to(subProp.label);
860     }
861     if (jsonSubProp.find("id") != jsonSubProp.end() && jsonSubProp["id"].is_string()) {
862         jsonSubProp.at("id").get_to(subProp.id);
863     }
864     if (jsonSubProp.find("icon") != jsonSubProp.end() && jsonSubProp["icon"].is_string()) {
865         jsonSubProp.at("icon").get_to(subProp.icon);
866     }
867     if (jsonSubProp.find("mode") != jsonSubProp.end() && jsonSubProp["mode"].is_string()) {
868         jsonSubProp.at("mode").get_to(subProp.mode);
869     }
870     if (jsonSubProp.find("locale") != jsonSubProp.end() && jsonSubProp["locale"].is_string()) {
871         jsonSubProp.at("locale").get_to(subProp.locale);
872     }
873 }
874 
GetDefaultImeCfgProp()875 std::shared_ptr<Property> ImeInfoInquirer::GetDefaultImeCfgProp()
876 {
877     auto ime = GetDefaultIme();
878     if (ime.bundleName.empty() || ime.extName.empty()) {
879         IMSA_HILOGE("defaultIme is abnormal");
880         return nullptr;
881     }
882     auto defaultIme = std::make_shared<Property>();
883     defaultIme->name = ime.bundleName;
884     defaultIme->id = ime.extName;
885     return defaultIme;
886 }
887 } // namespace MiscServices
888 } // namespace OHOS