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