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 [¤tImeBundle](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 [¤tImeCfg](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