1 /*
2 * Copyright (C) 2021 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 "input_method_system_ability.h"
17
18 #include <global.h>
19 #include <utils.h>
20
21 #include "ability_connect_callback_proxy.h"
22 #include "ability_manager_errors.h"
23 #include "ability_manager_interface.h"
24 #include "application_info.h"
25 #include "bundle_checker.h"
26 #include "bundle_mgr_proxy.h"
27 #include "combination_key.h"
28 #include "common_event_support.h"
29 #include "errors.h"
30 #include "global.h"
31 #include "im_common_event_manager.h"
32 #include "ime_cfg_manager.h"
33 #include "input_method_status.h"
34 #include "ipc_skeleton.h"
35 #include "iservice_registry.h"
36 #include "itypes_util.h"
37 #include "key_event.h"
38 #include "message_handler.h"
39 #include "os_account_manager.h"
40 #include "resource_manager.h"
41 #include "system_ability.h"
42 #include "system_ability_definition.h"
43 #include "ui_service_mgr_client.h"
44
45 namespace OHOS {
46 namespace MiscServices {
47 using namespace MessageID;
48 using namespace AccountSA;
49 REGISTER_SYSTEM_ABILITY_BY_ID(InputMethodSystemAbility, INPUT_METHOD_SYSTEM_ABILITY_ID, true);
50 const std::int32_t INIT_INTERVAL = 10000L;
51 const std::int32_t MAIN_USER_ID = 100;
52 constexpr int32_t INVALID_USER_ID = -1;
53 static const std::string PERMISSION_CONNECT_IME_ABILITY = "ohos.permission.CONNECT_IME_ABILITY";
54 std::shared_ptr<AppExecFwk::EventHandler> InputMethodSystemAbility::serviceHandler_;
55
56 /**
57 * constructor
58 * @param systemAbilityId
59 * @param runOnCreate
60 */
InputMethodSystemAbility(int32_t systemAbilityId,bool runOnCreate)61 InputMethodSystemAbility::InputMethodSystemAbility(int32_t systemAbilityId, bool runOnCreate)
62 : SystemAbility(systemAbilityId, runOnCreate), state_(ServiceRunningState::STATE_NOT_START)
63 {
64 }
65
66 /**
67 * constructor
68 */
InputMethodSystemAbility()69 InputMethodSystemAbility::InputMethodSystemAbility() : state_(ServiceRunningState::STATE_NOT_START)
70 {
71 }
72
73 /**
74 * Destructor
75 */
~InputMethodSystemAbility()76 InputMethodSystemAbility::~InputMethodSystemAbility()
77 {
78 if (workThreadHandler.joinable()) {
79 workThreadHandler.join();
80 }
81 userSessions.clear();
82 std::map<int32_t, MessageHandler*>::const_iterator it2;
83 for (it2 = msgHandlers.cbegin(); it2 != msgHandlers.cend();) {
84 MessageHandler *handler = it2->second;
85 it2 = msgHandlers.erase(it2);
86 delete handler;
87 handler = nullptr;
88 }
89 msgHandlers.clear();
90 }
91
OnStart()92 void InputMethodSystemAbility::OnStart()
93 {
94 IMSA_HILOGI("InputMethodSystemAbility::OnStart.");
95 if (state_ == ServiceRunningState::STATE_RUNNING) {
96 IMSA_HILOGI("ImsaService is already running.");
97 return;
98 }
99 Initialize();
100 InitServiceHandler();
101 if (Init() != ErrorCode::NO_ERROR) {
102 auto callback = [=]() { Init(); };
103 serviceHandler_->PostTask(callback, INIT_INTERVAL);
104 IMSA_HILOGE("Init failed. Try again 10s later");
105 return;
106 }
107 InitHiTrace();
108 InputmethodTrace tracer("InputMethodController Attach trace.");
109 InputmethodDump::GetInstance().AddDumpAllMethod(
110 std::bind(&InputMethodSystemAbility::DumpAllMethod, this, std::placeholders::_1));
111 IMSA_HILOGI("Start ImsaService ErrorCode::NO_ERROR.");
112 return;
113 }
114
Dump(int fd,const std::vector<std::u16string> & args)115 int InputMethodSystemAbility::Dump(int fd, const std::vector<std::u16string> &args)
116 {
117 IMSA_HILOGI("InputMethodSystemAbility::Dump");
118 std::vector<std::string> argsStr;
119 for (auto item : args) {
120 argsStr.emplace_back(Str16ToStr8(item));
121 }
122 InputmethodDump::GetInstance().Dump(fd, argsStr);
123 return ERR_OK;
124 }
125
GetInputMethodParam(const std::vector<InputMethodInfo> & properties)126 std::string InputMethodSystemAbility::GetInputMethodParam(const std::vector<InputMethodInfo> &properties)
127 {
128 auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId_);
129 auto ¤tIme = cfg.currentIme;
130 bool isBegin = true;
131 std::string params = "{\"imeList\":[";
132 for (const auto &property : properties) {
133 params += isBegin ? "" : "},";
134 isBegin = false;
135
136 std::string imeId = Str16ToStr8(property.mPackageName) + "/" + Str16ToStr8(property.mAbilityName);
137 params += "{\"ime\": \"" + imeId + "\",";
138 params += "\"labelId\": \"" + std::to_string(property.labelId) + "\",";
139 params += "\"descriptionId\": \"" + std::to_string(property.descriptionId) + "\",";
140 std::string isCurrentIme = currentIme == imeId ? "true" : "false";
141 params += "\"isCurrentIme\": \"" + isCurrentIme + "\",";
142 params += "\"label\": \"" + Str16ToStr8(property.label) + "\",";
143 params += "\"description\": \"" + Str16ToStr8(property.description) + "\"";
144 }
145 params += "}]}";
146 return params;
147 }
148
DumpAllMethod(int fd)149 void InputMethodSystemAbility::DumpAllMethod(int fd)
150 {
151 IMSA_HILOGI("InputMethodSystemAbility::DumpAllMethod");
152 std::vector<int32_t> ids;
153 int errCode = OsAccountManager::QueryActiveOsAccountIds(ids);
154 if (errCode != ERR_OK) {
155 dprintf(fd, "\n - InputMethodSystemAbility::DumpAllMethod get Active Id failed.\n");
156 return;
157 }
158 dprintf(fd, "\n - DumpAllMethod get Active Id succeed,count=%zu,", ids.size());
159 for (auto id : ids) {
160 const auto &properties = ListInputMethodInfo(id);
161 if (properties.empty()) {
162 IMSA_HILOGI("The IME properties is empty.");
163 dprintf(fd, "\n - The IME properties about the Active Id %d is empty.\n", id);
164 continue;
165 }
166 const auto ¶ms = GetInputMethodParam(properties);
167 dprintf(fd, "\n - The Active Id:%d get input method:\n%s\n", id, params.c_str());
168 }
169 IMSA_HILOGI("InputMethodSystemAbility::DumpAllMethod end.");
170 }
171
Init()172 int32_t InputMethodSystemAbility::Init()
173 {
174 bool isSuccess = Publish(this);
175 if (!isSuccess) {
176 return -1;
177 }
178 IMSA_HILOGI("Publish ErrorCode::NO_ERROR.");
179 state_ = ServiceRunningState::STATE_RUNNING;
180 ImeCfgManager::GetInstance().Init();
181 // If restart is caused by exception, userId can be got without 'OnUserStarted'.
182 // It may be possible that sa can not get userId when device startup, then wait for 'OnUserStarted'.
183 std::vector<int32_t> userIds;
184 if (OsAccountManager::QueryActiveOsAccountIds(userIds) == ERR_OK && !userIds.empty()) {
185 userId_ = userIds[0];
186 IMSA_HILOGI("InputMethodSystemAbility::get current userId success, userId: %{public}d", userId_);
187 StartInputService(GetNewUserIme(userId_));
188 }
189 StartUserIdListener();
190 int32_t ret = InitKeyEventMonitor();
191 IMSA_HILOGI("init KeyEvent monitor %{public}s", ret == ErrorCode::NO_ERROR ? "success" : "failed");
192 return ErrorCode::NO_ERROR;
193 }
194
OnStop()195 void InputMethodSystemAbility::OnStop()
196 {
197 IMSA_HILOGI("OnStop started.");
198 if (state_ != ServiceRunningState::STATE_RUNNING) {
199 return;
200 }
201 serviceHandler_ = nullptr;
202
203 state_ = ServiceRunningState::STATE_NOT_START;
204 IMSA_HILOGI("OnStop end.");
205 }
206
InitServiceHandler()207 void InputMethodSystemAbility::InitServiceHandler()
208 {
209 IMSA_HILOGI("InitServiceHandler started.");
210 if (serviceHandler_) {
211 IMSA_HILOGI("InitServiceHandler already init.");
212 return;
213 }
214 std::shared_ptr<AppExecFwk::EventRunner> runner = AppExecFwk::EventRunner::Create("InputMethodSystemAbility");
215 serviceHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
216
217 IMSA_HILOGI("InitServiceHandler succeeded.");
218 }
219
220 /*! Initialization of Input method management service
221 \n It's called after the service starts, before any transaction.
222 */
Initialize()223 void InputMethodSystemAbility::Initialize()
224 {
225 IMSA_HILOGI("InputMethodSystemAbility::Initialize");
226 // init work thread to handle the messages
227 workThreadHandler = std::thread([this] { WorkThread(); });
228 userSessions.insert({ MAIN_USER_ID, std::make_shared<PerUserSession>(MAIN_USER_ID) });
229
230 userId_ = INVALID_USER_ID;
231 }
232
StartUserIdListener()233 void InputMethodSystemAbility::StartUserIdListener()
234 {
235 sptr<ImCommonEventManager> imCommonEventManager = ImCommonEventManager::GetInstance();
236 bool isSuccess = imCommonEventManager->SubscribeEvent(EventFwk::CommonEventSupport::COMMON_EVENT_USER_SWITCHED);
237 if (isSuccess) {
238 IMSA_HILOGI("InputMethodSystemAbility::Initialize subscribe service event success");
239 return;
240 }
241
242 IMSA_HILOGE("StartUserIdListener failed. Try again 10s later");
243 auto callback = [this]() { StartUserIdListener(); };
244 serviceHandler_->PostTask(callback, INIT_INTERVAL);
245 }
246
StartInputService(std::string imeId)247 bool InputMethodSystemAbility::StartInputService(std::string imeId)
248 {
249 IMSA_HILOGE("InputMethodSystemAbility::StartInputService() ime:%{public}s", imeId.c_str());
250 bool isStartSuccess = false;
251 sptr<AAFwk::IAbilityManager> abms = GetAbilityManagerService();
252 if (abms) {
253 AAFwk::Want want;
254 want.SetAction("action.system.inputmethod");
255 std::string::size_type pos = imeId.find("/");
256 want.SetElementName(imeId.substr(0, pos), imeId.substr(pos + 1));
257 int32_t result = abms->StartAbility(want);
258 if (result) {
259 IMSA_HILOGE("InputMethodSystemAbility::StartInputService failed, result = %{public}d", result);
260 isStartSuccess = false;
261 } else {
262 IMSA_HILOGE("InputMethodSystemAbility::StartInputService success.");
263 isStartSuccess = true;
264 }
265 }
266 if (!isStartSuccess) {
267 IMSA_HILOGE("StartInputService failed. Try again 10s later");
268 auto callback = [this, imeId]() { StartInputService(imeId); };
269 serviceHandler_->PostTask(callback, INIT_INTERVAL);
270 }
271 return isStartSuccess;
272 }
273
StopInputService(std::string imeId)274 void InputMethodSystemAbility::StopInputService(std::string imeId)
275 {
276 IMSA_HILOGE("InputMethodSystemAbility::StopInputService(%{public}s)", imeId.c_str());
277 auto session = GetUserSession(MAIN_USER_ID);
278 if (session == nullptr) {
279 IMSA_HILOGE("InputMethodSystemAbility::StopInputService abort session is nullptr");
280 return;
281 }
282 session->StopInputService(imeId);
283 }
284
285 /*! Handle the transaction from the remote binder
286 \n Run in binder thread
287 \param code transaction code number
288 \param data the params from remote binder
289 \param[out] reply the result of the transaction replied to the remote binder
290 \param flags the flags of handling transaction
291 \return int32_t
292 */
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)293 int32_t InputMethodSystemAbility::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply,
294 MessageOption &option)
295 {
296 return InputMethodSystemAbilityStub::OnRemoteRequest(code, data, reply, option);
297 }
298
PrepareInput(int32_t displayId,sptr<IInputClient> client,sptr<IInputDataChannel> channel,InputAttribute & attribute)299 int32_t InputMethodSystemAbility::PrepareInput(int32_t displayId, sptr<IInputClient> client,
300 sptr<IInputDataChannel> channel, InputAttribute &attribute)
301 {
302 int32_t pid = IPCSkeleton::GetCallingPid();
303 int32_t uid = IPCSkeleton::GetCallingUid();
304 auto session = GetUserSession(MAIN_USER_ID);
305 if (session == nullptr) {
306 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
307 return ErrorCode::ERROR_NULL_POINTER;
308 }
309 sptr<RemoteObjectDeathRecipient> clientDeathRecipient = new (std::nothrow) RemoteObjectDeathRecipient();
310 if (clientDeathRecipient == nullptr) {
311 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput clientDeathRecipient is nullptr");
312 return ErrorCode::ERROR_EX_NULL_POINTER;
313 }
314 return session->OnPrepareInput(
315 { pid, uid, userId_, displayId, client, channel, clientDeathRecipient, attribute });
316 };
317
ReleaseInput(sptr<IInputClient> client)318 int32_t InputMethodSystemAbility::ReleaseInput(sptr<IInputClient> client)
319 {
320 auto session = GetUserSession(MAIN_USER_ID);
321 if (session == nullptr) {
322 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
323 return ErrorCode::ERROR_NULL_POINTER;
324 }
325 return session->OnReleaseInput(client);
326 };
327
StartInput(sptr<IInputClient> client,bool isShowKeyboard)328 int32_t InputMethodSystemAbility::StartInput(sptr<IInputClient> client, bool isShowKeyboard)
329 {
330 auto session = GetUserSession(MAIN_USER_ID);
331 if (session == nullptr) {
332 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
333 return ErrorCode::ERROR_NULL_POINTER;
334 }
335 auto currentSubtype = GetCurrentInputMethodSubtype();
336 if (currentSubtype == nullptr) {
337 IMSA_HILOGE("currentSubtype is nullptr");
338 return ErrorCode::ERROR_NULL_POINTER;
339 }
340 session->SetCurrentSubProperty(*currentSubtype);
341 return session->OnStartInput(client, isShowKeyboard);
342 };
343
StopInput(sptr<IInputClient> client)344 int32_t InputMethodSystemAbility::StopInput(sptr<IInputClient> client)
345 {
346 auto session = GetUserSession(MAIN_USER_ID);
347 if (session == nullptr) {
348 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
349 return ErrorCode::ERROR_NULL_POINTER;
350 }
351 return session->OnStopInput(client);
352 };
353
StopInputSession()354 int32_t InputMethodSystemAbility::StopInputSession()
355 {
356 auto session = GetUserSession(MAIN_USER_ID);
357 if (session == nullptr) {
358 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
359 return ErrorCode::ERROR_NULL_POINTER;
360 }
361 return session->OnHideKeyboardSelf();
362 }
363
SetCoreAndAgent(sptr<IInputMethodCore> core,sptr<IInputMethodAgent> agent)364 int32_t InputMethodSystemAbility::SetCoreAndAgent(sptr<IInputMethodCore> core, sptr<IInputMethodAgent> agent)
365 {
366 IMSA_HILOGD("InputMethodSystemAbility run in");
367 auto currentIme = GetCurrentInputMethod();
368 if (currentIme == nullptr) {
369 return ErrorCode::ERROR_EX_NULL_POINTER;
370 }
371 if (!BundleChecker::IsCurrentIme(IPCSkeleton::GetCallingTokenID(), currentIme->name)) {
372 return ErrorCode::ERROR_NOT_CURRENT_IME;
373 }
374 auto session = GetUserSession(MAIN_USER_ID);
375 if (session == nullptr) {
376 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
377 return ErrorCode::ERROR_NULL_POINTER;
378 }
379 return session->OnSetCoreAndAgent(core, agent);
380 };
381
HideCurrentInput()382 int32_t InputMethodSystemAbility::HideCurrentInput()
383 {
384 IMSA_HILOGD("InputMethodSystemAbility run in");
385 if (!BundleChecker::CheckPermission(IPCSkeleton::GetCallingTokenID(), PERMISSION_CONNECT_IME_ABILITY)) {
386 return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
387 }
388 auto session = GetUserSession(MAIN_USER_ID);
389 if (session == nullptr) {
390 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
391 return ErrorCode::ERROR_NULL_POINTER;
392 }
393 return session->OnHideKeyboardSelf();
394 };
395
ShowCurrentInput()396 int32_t InputMethodSystemAbility::ShowCurrentInput()
397 {
398 IMSA_HILOGD("InputMethodSystemAbility run in");
399 if (!BundleChecker::CheckPermission(IPCSkeleton::GetCallingTokenID(), PERMISSION_CONNECT_IME_ABILITY)) {
400 return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
401 }
402 auto session = GetUserSession(MAIN_USER_ID);
403 if (session == nullptr) {
404 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
405 return ErrorCode::ERROR_NULL_POINTER;
406 }
407 return session->OnShowKeyboardSelf();
408 };
409
DisplayOptionalInputMethod()410 int32_t InputMethodSystemAbility::DisplayOptionalInputMethod()
411 {
412 IMSA_HILOGD("InputMethodSystemAbility run in");
413 if (!BundleChecker::CheckPermission(IPCSkeleton::GetCallingTokenID(), PERMISSION_CONNECT_IME_ABILITY)) {
414 return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
415 }
416 return OnDisplayOptionalInputMethod(userId_);
417 };
418
ListInputMethod(InputMethodStatus status,std::vector<Property> & props)419 int32_t InputMethodSystemAbility::ListInputMethod(InputMethodStatus status, std::vector<Property> &props)
420 {
421 return ListInputMethodByUserId(userId_, status, props);
422 }
423
ListAllInputMethod(int32_t userId,std::vector<Property> & props)424 int32_t InputMethodSystemAbility::ListAllInputMethod(int32_t userId, std::vector<Property> &props)
425 {
426 IMSA_HILOGI("InputMethodSystemAbility::listAllInputMethod");
427 return ListProperty(userId, props);
428 }
429
ListEnabledInputMethod(std::vector<Property> & props)430 int32_t InputMethodSystemAbility::ListEnabledInputMethod(std::vector<Property> &props)
431 {
432 IMSA_HILOGI("InputMethodSystemAbility::listEnabledInputMethod");
433 auto current = GetCurrentInputMethod();
434 if (current == nullptr) {
435 IMSA_HILOGE("GetCurrentInputMethod current is nullptr");
436 return ErrorCode::ERROR_NULL_POINTER;
437 }
438 auto property = FindProperty(current->name);
439 props = { property };
440 return ErrorCode::NO_ERROR;
441 }
442
ListDisabledInputMethod(int32_t userId,std::vector<Property> & props)443 int32_t InputMethodSystemAbility::ListDisabledInputMethod(int32_t userId, std::vector<Property> &props)
444 {
445 IMSA_HILOGI("InputMethodSystemAbility::listDisabledInputMethod");
446 auto ret = ListProperty(userId, props);
447 if (ret != ErrorCode::NO_ERROR) {
448 IMSA_HILOGE("list property is failed, ret = %{public}d", ret);
449 return ret;
450 }
451 auto filter = GetCurrentInputMethod();
452 if (filter == nullptr) {
453 IMSA_HILOGE("GetCurrentInputMethod property is nullptr");
454 return ErrorCode::ERROR_NULL_POINTER;
455 }
456 for (auto iter = props.begin(); iter != props.end();) {
457 if (iter->name == filter->name) {
458 iter = props.erase(iter);
459 continue;
460 }
461 ++iter;
462 }
463 return ErrorCode::NO_ERROR;
464 }
465
ListCurrentInputMethodSubtype(std::vector<SubProperty> & subProps)466 int32_t InputMethodSystemAbility::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps)
467 {
468 IMSA_HILOGI("InputMethodSystemAbility::ListCurrentInputMethodSubtype");
469 auto filter = GetCurrentInputMethod();
470 if (filter == nullptr) {
471 IMSA_HILOGE("GetCurrentInputMethod failed");
472 return ErrorCode::ERROR_NULL_POINTER;
473 }
474 return ListSubtypeByBundleName(userId_, filter->name, subProps);
475 }
476
ListInputMethodSubtype(const std::string & name,std::vector<SubProperty> & subProps)477 int32_t InputMethodSystemAbility::ListInputMethodSubtype(
478 const std::string &name, std::vector<SubProperty> &subProps)
479 {
480 IMSA_HILOGI("InputMethodSystemAbility::ListInputMethodSubtype");
481 return ListSubtypeByBundleName(userId_, name, subProps);
482 }
483
ListSubtypeByBundleName(int32_t userId,const std::string & name,std::vector<SubProperty> & subProps)484 int32_t InputMethodSystemAbility::ListSubtypeByBundleName(
485 int32_t userId, const std::string &name, std::vector<SubProperty> &subProps)
486 {
487 IMSA_HILOGI("InputMethodSystemAbility::ListSubtypeByBundleName");
488 std::vector<AppExecFwk::ExtensionAbilityInfo> subtypeInfos;
489 int32_t ret = QueryImeInfos(userId, subtypeInfos);
490 if (ret != ErrorCode::NO_ERROR) {
491 IMSA_HILOGE("Failed to query inputmethod infos");
492 return ret;
493 }
494 auto bundleMgr = GetBundleMgr();
495 if (bundleMgr == nullptr) {
496 IMSA_HILOGE("Failed to GetBundleMgr");
497 return ErrorCode::ERROR_NULL_POINTER;
498 }
499 for (const auto &subtypeInfo : subtypeInfos) {
500 if (subtypeInfo.bundleName == name) {
501 std::vector<Metadata> extends = subtypeInfo.metadata;
502 auto property = GetExtends(extends);
503 auto label = bundleMgr->GetStringById(subtypeInfo.bundleName, subtypeInfo.moduleName,
504 subtypeInfo.labelId, userId);
505 subProps.push_back({ .id = subtypeInfo.name,
506 .label = label,
507 .name = subtypeInfo.bundleName,
508 .iconId = subtypeInfo.iconId,
509 .language = property.language,
510 .mode = property.mode,
511 .locale = property.locale,
512 .icon = property.icon });
513 }
514 }
515 return ErrorCode::NO_ERROR;
516 }
517
GetExtends(const std::vector<Metadata> & metaData)518 SubProperty InputMethodSystemAbility::GetExtends(const std::vector<Metadata> &metaData)
519 {
520 IMSA_HILOGI("InputMethodSystemAbility::GetExtends");
521 SubProperty property;
522 for (const auto &data : metaData) {
523 if (data.name == "language") {
524 property.language = data.value;
525 continue;
526 }
527 if (data.name == "mode") {
528 property.mode = data.value;
529 continue;
530 }
531 if (data.name == "locale") {
532 property.locale = data.value;
533 continue;
534 }
535 if (data.name == "icon") {
536 property.icon = data.value;
537 }
538 }
539 return property;
540 }
541
SwitchInputMethod(const std::string & name,const std::string & subName)542 int32_t InputMethodSystemAbility::SwitchInputMethod(const std::string &name, const std::string &subName)
543 {
544 IMSA_HILOGI("InputMethodSystemAbility::SwitchInputMethod");
545 if (!BundleChecker::CheckPermission(IPCSkeleton::GetCallingTokenID(), PERMISSION_CONNECT_IME_ABILITY)) {
546 return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
547 }
548 return subName.empty() ? SwitchInputMethodType(name) : SwitchInputMethodSubtype(name, subName);
549 }
550
SwitchInputMethodType(const std::string & name)551 int32_t InputMethodSystemAbility::SwitchInputMethodType(const std::string &name)
552 {
553 IMSA_HILOGI("InputMethodSystemAbility::SwitchInputMethodType");
554 std::vector<Property> properties = {};
555 auto ret = ListInputMethodByUserId(userId_, ALL, properties);
556 if (ret != ErrorCode::NO_ERROR) {
557 IMSA_HILOGE("ListInputMethodByUserId failed, ret = %{public}d", ret);
558 return ret;
559 }
560 if (properties.empty()) {
561 IMSA_HILOGE("InputMethodSystemAbility::SwitchInputMethodType has no ime");
562 return ErrorCode::ERROR_BAD_PARAMETERS;
563 }
564 for (const auto &property : properties) {
565 if (property.name == name) {
566 IMSA_HILOGI("target is installed, start switching");
567 return OnSwitchInputMethod(property.name, property.id);
568 }
569 }
570 IMSA_HILOGE("target is not installed, switch failed");
571 return ErrorCode::ERROR_SWITCH_IME;
572 }
573
SwitchInputMethodSubtype(const std::string & bundleName,const std::string & name)574 int32_t InputMethodSystemAbility::SwitchInputMethodSubtype(const std::string &bundleName, const std::string &name)
575 {
576 IMSA_HILOGI("InputMethodSystemAbility::SwitchInputMethodSubtype");
577 std::vector<SubProperty> subProps = {};
578 auto ret = ListSubtypeByBundleName(userId_, bundleName, subProps);
579 if (ret != ErrorCode::NO_ERROR) {
580 IMSA_HILOGE("ListSubtypeByBundleName failed, ret = %{public}d", ret);
581 return ret;
582 }
583 if (subProps.empty()) {
584 IMSA_HILOGE("InputMethodSystemAbility::SwitchInputMethodSubtype has no ime");
585 return ErrorCode::ERROR_BAD_PARAMETERS;
586 }
587 for (const auto &subProp : subProps) {
588 if (subProp.id == name) {
589 IMSA_HILOGI("target is installed, start switching");
590 return OnSwitchInputMethod(bundleName, name);
591 }
592 }
593 IMSA_HILOGE("target is not installed, switch failed");
594 return ErrorCode::ERROR_SWITCH_IME;
595 }
596
OnSwitchInputMethod(const std::string & bundleName,const std::string & name)597 int32_t InputMethodSystemAbility::OnSwitchInputMethod(const std::string &bundleName, const std::string &name)
598 {
599 IMSA_HILOGI("InputMethodSystemAbility::OnSwitchInputMethod");
600 std::string targetIme = bundleName + "/" + name;
601 auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId_);
602 auto ¤tIme = cfg.currentIme;
603 if (currentIme.empty()) {
604 IMSA_HILOGE("currentIme is empty");
605 return ErrorCode::ERROR_PERSIST_CONFIG;
606 }
607 IMSA_HILOGI("CurrentIme : %{public}s, TargetIme : %{public}s", currentIme.c_str(), targetIme.c_str());
608 if (currentIme == targetIme) {
609 IMSA_HILOGI("currentIme and TargetIme are the same one");
610 return ErrorCode::NO_ERROR;
611 }
612 StopInputService(currentIme);
613 ImeCfgManager::GetInstance().ModifyImeCfg({ userId_, targetIme });
614 if (!StartInputService(targetIme)) {
615 IMSA_HILOGE("start input method failed");
616 return ErrorCode::ERROR_IME_START_FAILED;
617 }
618 auto session = GetUserSession(MAIN_USER_ID);
619 if (session == nullptr) {
620 IMSA_HILOGE("session is nullptr");
621 return ErrorCode::ERROR_NULL_POINTER;
622 }
623 session->OnInputMethodSwitched(FindProperty(bundleName), FindSubProperty(bundleName, name));
624 return ErrorCode::NO_ERROR;
625 }
626
FindProperty(const std::string & name)627 Property InputMethodSystemAbility::FindProperty(const std::string &name)
628 {
629 IMSA_HILOGI("InputMethodSystemAbility::FindProperty");
630 std::vector<Property> props = {};
631 auto ret = ListAllInputMethod(userId_, props);
632 if (ret != ErrorCode::NO_ERROR) {
633 IMSA_HILOGE("ListAllInputMethod failed");
634 return {};
635 }
636 for (const auto &prop : props) {
637 if (prop.name == name) {
638 return prop;
639 }
640 }
641 IMSA_HILOGE("InputMethodSystemAbility::FindProperty failed");
642 return {};
643 }
644
FindSubProperty(const std::string & bundleName,const std::string & name)645 SubProperty InputMethodSystemAbility::FindSubProperty(const std::string &bundleName, const std::string &name)
646 {
647 IMSA_HILOGI("InputMethodSystemAbility::FindSubProperty");
648 std::vector<SubProperty> subProps = {};
649 auto ret = ListSubtypeByBundleName(userId_, bundleName, subProps);
650 if (ret != ErrorCode::NO_ERROR) {
651 IMSA_HILOGE("ListSubtypeByBundleName failed, ret = %{public}d", ret);
652 return {};
653 }
654 for (const auto &subProp : subProps) {
655 if (subProp.id == name) {
656 return subProp;
657 }
658 }
659 IMSA_HILOGE("InputMethodSystemAbility::FindSubProperty failed");
660 return {};
661 }
662
663 // Deprecated because of no permission check, kept for compatibility
HideCurrentInputDeprecated()664 int32_t InputMethodSystemAbility::HideCurrentInputDeprecated()
665 {
666 auto session = GetUserSession(MAIN_USER_ID);
667 if (session == nullptr) {
668 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
669 return ErrorCode::ERROR_NULL_POINTER;
670 }
671 return session->OnHideKeyboardSelf();
672 };
673
ShowCurrentInputDeprecated()674 int32_t InputMethodSystemAbility::ShowCurrentInputDeprecated()
675 {
676 auto session = GetUserSession(MAIN_USER_ID);
677 if (session == nullptr) {
678 IMSA_HILOGE("InputMethodSystemAbility::PrepareInput session is nullptr");
679 return ErrorCode::ERROR_NULL_POINTER;
680 }
681 return session->OnShowKeyboardSelf();
682 };
683
DisplayOptionalInputMethodDeprecated()684 int32_t InputMethodSystemAbility::DisplayOptionalInputMethodDeprecated()
685 {
686 return OnDisplayOptionalInputMethod(userId_);
687 };
688
689 /*! Get all of the input method engine list installed in the system
690 \n Run in binder thread
691 \param[out] properties input method engine list returned to the caller
692 \return ErrorCode::NO_ERROR no error
693 \return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked
694 */
ListInputMethodByUserId(int32_t userId,InputMethodStatus status,std::vector<Property> & props)695 int32_t InputMethodSystemAbility::ListInputMethodByUserId(
696 int32_t userId, InputMethodStatus status, std::vector<Property> &props)
697 {
698 IMSA_HILOGI("InputMethodSystemAbility::ListInputMethodByUserId");
699 if (status == InputMethodStatus::ALL) {
700 return ListAllInputMethod(userId, props);
701 }
702 if (status == InputMethodStatus::ENABLE) {
703 return ListEnabledInputMethod(props);
704 }
705 if (status == InputMethodStatus::DISABLE) {
706 return ListDisabledInputMethod(userId, props);
707 }
708 return ErrorCode::ERROR_BAD_PARAMETERS;
709 }
710
ListInputMethodInfo(int32_t userId)711 std::vector<InputMethodInfo> InputMethodSystemAbility::ListInputMethodInfo(int32_t userId)
712 {
713 IMSA_HILOGI("InputMethodSystemAbility::ListInputMethodInfo userId = %{public}d", userId);
714 std::vector<AppExecFwk::ExtensionAbilityInfo> extensionInfos;
715 if (QueryImeInfos(userId, extensionInfos) != ErrorCode::NO_ERROR) {
716 IMSA_HILOGE("Failed to query inputmethod infos");
717 return {};
718 }
719 std::vector<InputMethodInfo> properties;
720 for (auto extension : extensionInfos) {
721 std::shared_ptr<Global::Resource::ResourceManager> resourceManager(
722 Global::Resource::CreateResourceManager());
723 if (resourceManager == nullptr) {
724 IMSA_HILOGE("InputMethodSystemAbility::ListInputMethodInfo resourcemanager is nullptr");
725 break;
726 }
727 AppExecFwk::ApplicationInfo applicationInfo = extension.applicationInfo;
728 std::string path = extension.hapPath.empty() ? extension.resourcePath : extension.hapPath;
729 resourceManager->AddResource(path.c_str());
730 std::string labelString;
731 resourceManager->GetStringById(applicationInfo.labelId, labelString);
732 std::string descriptionString;
733 resourceManager->GetStringById(applicationInfo.descriptionId, descriptionString);
734 InputMethodInfo property;
735 property.mPackageName = Str8ToStr16(extension.bundleName);
736 property.mAbilityName = Str8ToStr16(extension.name);
737 property.labelId = applicationInfo.labelId;
738 property.descriptionId = applicationInfo.descriptionId;
739 property.label = Str8ToStr16(labelString);
740 property.description = Str8ToStr16(descriptionString);
741 properties.emplace_back(property);
742 }
743 return properties;
744 }
745
ListProperty(int32_t userId,std::vector<Property> & props)746 int32_t InputMethodSystemAbility::ListProperty(int32_t userId, std::vector<Property> &props)
747 {
748 IMSA_HILOGI("InputMethodSystemAbility::ListProperty userId = %{public}d", userId);
749 std::vector<AppExecFwk::ExtensionAbilityInfo> extensionInfos;
750 int32_t ret = QueryImeInfos(userId, extensionInfos);
751 if (ret != ErrorCode::NO_ERROR) {
752 IMSA_HILOGE("Failed to query inputmethod infos");
753 return ret;
754 }
755 for (const auto &extension : extensionInfos) {
756 bool isInVector = false;
757 for (const auto &prop : props) {
758 if (extension.bundleName == prop.name) {
759 isInVector = true;
760 break;
761 }
762 }
763 if (isInVector) {
764 continue;
765 }
766 props.push_back({ .name = extension.bundleName,
767 .id = extension.name,
768 .label = extension.applicationInfo.label,
769 .icon = extension.applicationInfo.icon,
770 .iconId = extension.applicationInfo.iconId });
771 }
772 return ErrorCode::NO_ERROR;
773 }
774
GetCurrentInputMethod()775 std::shared_ptr<Property> InputMethodSystemAbility::GetCurrentInputMethod()
776 {
777 IMSA_HILOGI("InputMethodSystemAbility::GetCurrentInputMethod");
778 auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId_);
779 auto ¤tIme = cfg.currentIme;
780 if (currentIme.empty()) {
781 IMSA_HILOGE("InputMethodSystemAbility::GetCurrentInputMethod currentIme is empty");
782 return nullptr;
783 }
784
785 auto pos = currentIme.find('/');
786 if (pos == std::string::npos) {
787 IMSA_HILOGE("InputMethodSystemAbility::GetCurrentInputMethod currentIme can not find '/'");
788 return nullptr;
789 }
790
791 auto property = std::make_shared<Property>();
792 if (property == nullptr) {
793 IMSA_HILOGE("InputMethodSystemAbility property is nullptr");
794 return nullptr;
795 }
796 property->name = currentIme.substr(0, pos);
797 property->id = currentIme.substr(pos + 1, currentIme.length() - pos - 1);
798 return property;
799 }
800
GetCurrentInputMethodSubtype()801 std::shared_ptr<SubProperty> InputMethodSystemAbility::GetCurrentInputMethodSubtype()
802 {
803 IMSA_HILOGI("InputMethodSystemAbility::GetCurrentInputMethodSubtype");
804 auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId_);
805 auto ¤tIme = cfg.currentIme;
806 if (currentIme.empty()) {
807 IMSA_HILOGE("InputMethodSystemAbility currentIme is empty");
808 return nullptr;
809 }
810 auto pos = currentIme.find('/');
811 if (pos == std::string::npos) {
812 IMSA_HILOGE("InputMethodSystemAbility:: currentIme can not find '/'");
813 return nullptr;
814 }
815 auto property = std::make_shared<SubProperty>(
816 FindSubProperty(currentIme.substr(0, pos), currentIme.substr(pos + 1, currentIme.length() - pos - 1)));
817 if (property == nullptr) {
818 IMSA_HILOGE("property is nullptr");
819 return nullptr;
820 }
821 return property;
822 }
823
824 /*! Get the instance of PerUserSession for the given user
825 \param userId the user id of the given user
826 \return a pointer of the instance if the user is found
827 \return null if the user is not found
828 */
GetUserSession(int32_t userId)829 std::shared_ptr<PerUserSession> InputMethodSystemAbility::GetUserSession(int32_t userId)
830 {
831 auto it = userSessions.find(userId);
832 if (it == userSessions.end()) {
833 IMSA_HILOGE("not found session");
834 return nullptr;
835 }
836 return it->second;
837 }
838
839 /*! Work Thread of input method management service
840 \n Remote commands which may change the state or data in the service will be handled sequentially in this thread.
841 */
WorkThread()842 void InputMethodSystemAbility::WorkThread()
843 {
844 while (1) {
845 Message *msg = MessageHandler::Instance()->GetMessage();
846 switch (msg->msgId_) {
847 case MSG_ID_USER_START : {
848 OnUserStarted(msg);
849 break;
850 }
851 case MSG_ID_USER_REMOVED: {
852 OnUserRemoved(msg);
853 break;
854 }
855 case MSG_ID_PACKAGE_REMOVED: {
856 OnPackageRemoved(msg);
857 break;
858 }
859 case MSG_ID_HIDE_KEYBOARD_SELF:{
860 auto session = GetUserSession(MAIN_USER_ID);
861 if (session == nullptr) {
862 IMSA_HILOGE("session is nullptr");
863 break;
864 }
865 session->OnHideKeyboardSelf();
866 break;
867 }
868 case MSG_ID_START_INPUT_SERVICE: {
869 MessageParcel *data = msg->msgContent_;
870 const auto &ime = data->ReadString();
871 StartInputService(ime);
872 break;
873 }
874 default: {
875 break;
876 }
877 }
878 delete msg;
879 }
880 }
881
IsImeInstalled(int32_t userId,std::string & imeId)882 bool InputMethodSystemAbility::IsImeInstalled(int32_t userId, std::string &imeId)
883 {
884 std::vector<Property> props;
885 ListAllInputMethod(userId, props);
886 for (auto const &prop : props) {
887 std::string ime = prop.name + "/" + prop.id;
888 if (ime == imeId) {
889 IMSA_HILOGI("true");
890 return true;
891 }
892 }
893 IMSA_HILOGI("false");
894 return false;
895 }
896
GetNewUserIme(int32_t userId)897 std::string InputMethodSystemAbility::GetNewUserIme(int32_t userId)
898 {
899 auto defaultIme = ImeCfgManager::GetDefaultIme();
900 if (defaultIme.empty()) {
901 IMSA_HILOGE("InputMethodSystemAbility::defaultIme is empty");
902 return "";
903 }
904 auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId);
905 auto newUserIme = cfg.currentIme;
906 if (newUserIme.empty()) {
907 newUserIme = defaultIme;
908 ImeCfgManager::GetInstance().AddImeCfg({ userId, newUserIme });
909 } else if (!IsImeInstalled(userId, newUserIme)) {
910 newUserIme = defaultIme;
911 ImeCfgManager::GetInstance().ModifyImeCfg({ userId, newUserIme });
912 }
913 return newUserIme;
914 }
915
916 /*! Called when a user is started. (EVENT_USER_STARTED is received)
917 \n Run in work thread of input method management service
918 \param msg the parameters are saved in msg->msgContent_
919 \return ErrorCode
920 */
OnUserStarted(const Message * msg)921 int32_t InputMethodSystemAbility::OnUserStarted(const Message *msg)
922 {
923 if (!msg->msgContent_) {
924 IMSA_HILOGE("InputMethodSystemAbility::Aborted! %s\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS));
925 return ErrorCode::ERROR_BAD_PARAMETERS;
926 }
927 std::string lastUserIme;
928 if (userId_ != INVALID_USER_ID) {
929 auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId_);
930 lastUserIme = cfg.currentIme;
931 if (lastUserIme.empty()) {
932 IMSA_HILOGE("InputMethodSystemAbility::lastUserIme is empty");
933 }
934 }
935 int32_t newUserId = msg->msgContent_->ReadInt32();
936 IMSA_HILOGI("lastUserId: %{public}d, newUserId: %{public}d", userId_, newUserId);
937 userId_ = newUserId;
938 auto it = userSessions.find(MAIN_USER_ID);
939 if (it != userSessions.end()) {
940 it->second->UpdateCurrentUserId(newUserId);
941 }
942 if (!lastUserIme.empty()) {
943 IMSA_HILOGI("service restart or user switch");
944 StopInputService(lastUserIme);
945 }
946 StartInputService(GetNewUserIme(newUserId));
947 return ErrorCode::NO_ERROR;
948 }
949
OnUserRemoved(const Message * msg)950 int32_t InputMethodSystemAbility::OnUserRemoved(const Message *msg)
951 {
952 if (!msg->msgContent_) {
953 IMSA_HILOGE("Aborted! %s", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS));
954 return ErrorCode::ERROR_BAD_PARAMETERS;
955 }
956 auto userId = msg->msgContent_->ReadInt32();
957 IMSA_HILOGI("Start: %{public}d", userId);
958 ImeCfgManager::GetInstance().DeleteImeCfg(userId);
959 return ErrorCode::NO_ERROR;
960 }
961
962 /*! Called when a package is removed.
963 \n Run in work thread of input method management service
964 \param msg the parameters are saved in msg->msgContent_
965 \return ErrorCode::NO_ERROR
966 \return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked
967 \return ErrorCode::ERROR_BAD_PARAMETERS bad parameter
968 */
OnPackageRemoved(const Message * msg)969 int32_t InputMethodSystemAbility::OnPackageRemoved(const Message *msg)
970 {
971 IMSA_HILOGI("Start...\n");
972 MessageParcel *data = msg->msgContent_;
973 if (data == nullptr) {
974 IMSA_HILOGI("InputMethodSystemAbility::OnPackageRemoved data is nullptr");
975 return ErrorCode::ERROR_NULL_POINTER;
976 }
977 int32_t userId = 0;
978 std::string packageName = "";
979 if (!ITypesUtil::Unmarshal(*data, userId, packageName)) {
980 IMSA_HILOGE("Failed to read message parcel");
981 return ErrorCode::ERROR_EX_PARCELABLE;
982 }
983 // This will also be called when a user is removed. Do not process if removed user is not current one.
984 if (userId != userId_) {
985 return ErrorCode::NO_ERROR;
986 }
987 auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId);
988 auto ¤tIme = cfg.currentIme;
989 if (currentIme.empty()) {
990 IMSA_HILOGE("InputMethodSystemAbility::currentIme is empty");
991 return ErrorCode::ERROR_PERSIST_CONFIG;
992 }
993 std::string::size_type pos = currentIme.find("/");
994 std::string currentImeBundle = currentIme.substr(0, pos);
995 if (packageName == currentImeBundle) {
996 std::string defaultIme = ImeCfgManager::GetDefaultIme();
997 if (defaultIme.empty()) {
998 IMSA_HILOGE("InputMethodSystemAbility::defaultIme is empty");
999 return ErrorCode::ERROR_PERSIST_CONFIG;
1000 }
1001 pos = defaultIme.find("/");
1002 int32_t ret =
1003 OnSwitchInputMethod(defaultIme.substr(0, pos), defaultIme.substr(pos + 1, defaultIme.length() - pos - 1));
1004 IMSA_HILOGI("InputMethodSystemAbility::OnPackageRemoved ret = %{public}d", ret);
1005 }
1006 return ErrorCode::NO_ERROR;
1007 }
OnDisplayOptionalInputMethod(int32_t userId)1008 int32_t InputMethodSystemAbility::OnDisplayOptionalInputMethod(int32_t userId)
1009 {
1010 IMSA_HILOGI("InputMethodSystemAbility::OnDisplayOptionalInputMethod");
1011 auto abilityManager = GetAbilityManagerService();
1012 if (abilityManager == nullptr) {
1013 IMSA_HILOGE("InputMethodSystemAbility::get ability manager failed");
1014 return ErrorCode::ERROR_EX_SERVICE_SPECIFIC;
1015 }
1016 AAFwk::Want want;
1017 want.SetAction(SELECT_DIALOG_ACTION);
1018 want.SetElementName(SELECT_DIALOG_HAP, SELECT_DIALOG_ABILITY);
1019 int32_t ret = abilityManager->StartAbility(want);
1020 if (ret == START_SERVICE_ABILITY_ACTIVATING) {
1021 return ErrorCode::NO_ERROR;
1022 }
1023 if (ret != ErrorCode::NO_ERROR) {
1024 IMSA_HILOGE("InputMethodSystemAbility::Start InputMethod ability failed, err = %{public}d", ret);
1025 return ErrorCode::ERROR_EX_SERVICE_SPECIFIC;
1026 }
1027 IMSA_HILOGI("InputMethodSystemAbility::Start InputMethod ability success.");
1028 return ErrorCode::NO_ERROR;
1029 }
GetBundleMgr()1030 sptr<OHOS::AppExecFwk::IBundleMgr> InputMethodSystemAbility::GetBundleMgr()
1031 {
1032 IMSA_HILOGI("InputMethodSystemAbility::GetBundleMgr");
1033 sptr<ISystemAbilityManager> systemAbilityManager =
1034 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
1035 if (!systemAbilityManager) {
1036 IMSA_HILOGI("InputMethodSystemAbility::GetBundleMgr systemAbilityManager is nullptr");
1037 return nullptr;
1038 }
1039 sptr<IRemoteObject> remoteObject =
1040 systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
1041 return iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
1042 }
1043
QueryImeInfos(int32_t userId,std::vector<AppExecFwk::ExtensionAbilityInfo> & infos)1044 int32_t InputMethodSystemAbility::QueryImeInfos(
1045 int32_t userId, std::vector<AppExecFwk::ExtensionAbilityInfo> &infos)
1046 {
1047 IMSA_HILOGI("InputMethodSystemAbility::QueryImeInfos");
1048 auto bundleMgr = GetBundleMgr();
1049 if (bundleMgr == nullptr) {
1050 IMSA_HILOGE("Failed to GetBundleMgr");
1051 return ErrorCode::ERROR_NULL_POINTER;
1052 }
1053 if (!bundleMgr->QueryExtensionAbilityInfos(AbilityType::INPUTMETHOD, userId, infos)) {
1054 IMSA_HILOGE("QueryExtensionAbilityInfos failed");
1055 return ErrorCode::ERROR_PACKAGE_MANAGER;
1056 }
1057 return ErrorCode::NO_ERROR;
1058 }
1059
GetAbilityManagerService()1060 sptr<AAFwk::IAbilityManager> InputMethodSystemAbility::GetAbilityManagerService()
1061 {
1062 IMSA_HILOGD("InputMethodSystemAbility::GetAbilityManagerService start");
1063 auto systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
1064 if (systemAbilityManager == nullptr) {
1065 IMSA_HILOGE("SystemAbilityManager is nullptr.");
1066 return nullptr;
1067 }
1068
1069 auto abilityMsObj = systemAbilityManager->GetSystemAbility(ABILITY_MGR_SERVICE_ID);
1070 if (abilityMsObj == nullptr) {
1071 IMSA_HILOGE("Failed to get ability manager service.");
1072 return nullptr;
1073 }
1074
1075 return iface_cast<AAFwk::IAbilityManager>(abilityMsObj);
1076 }
1077
FindSubPropertyByCompare(const std::string & bundleName,CompareHandler compare)1078 SubProperty InputMethodSystemAbility::FindSubPropertyByCompare(
1079 const std::string &bundleName, CompareHandler compare)
1080 {
1081 IMSA_HILOGI("InputMethodSystemAbility::FindSubPropertyByCompare");
1082 std::vector<SubProperty> subProps = {};
1083 auto ret = ListSubtypeByBundleName(userId_, bundleName, subProps);
1084 if (ret != ErrorCode::NO_ERROR) {
1085 IMSA_HILOGE("ListSubtypeByBundleName failed, ret = %{public}d", ret);
1086 return {};
1087 }
1088 for (const auto &subProp : subProps) {
1089 if (compare(subProp)) {
1090 return subProp;
1091 }
1092 }
1093 IMSA_HILOGE("InputMethodSystemAbility::FindSubPropertyByCompare failed");
1094 return {};
1095 }
1096
SwitchByCombinationKey(uint32_t state)1097 int32_t InputMethodSystemAbility::SwitchByCombinationKey(uint32_t state)
1098 {
1099 IMSA_HILOGI("InputMethodSystemAbility::SwitchByCombinationKey");
1100 auto current = GetCurrentInputMethodSubtype();
1101 if (current == nullptr) {
1102 IMSA_HILOGE("GetCurrentInputMethodSubtype failed");
1103 return ErrorCode::ERROR_EX_NULL_POINTER;
1104 }
1105 if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_MODE, state)) {
1106 IMSA_HILOGI("switch mode");
1107 auto target = current->mode == "upper"
1108 ? FindSubPropertyByCompare(current->name,
1109 [¤t](const SubProperty &property) { return property.mode == "lower"; })
1110 : FindSubPropertyByCompare(current->name,
1111 [¤t](const SubProperty &property) { return property.mode == "upper"; });
1112 return SwitchInputMethodSubtype(target.name, target.id);
1113 }
1114 if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_LANGUAGE, state)) {
1115 IMSA_HILOGI("switch language");
1116 auto target = current->language == "chinese"
1117 ? FindSubPropertyByCompare(current->name,
1118 [¤t](const SubProperty &property) { return property.language == "english"; })
1119 : FindSubPropertyByCompare(current->name,
1120 [¤t](const SubProperty &property) { return property.language == "chinese"; });
1121 return SwitchInputMethodSubtype(target.name, target.id);
1122 }
1123 if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_IME, state)) {
1124 IMSA_HILOGI("switch ime");
1125 std::vector<Property> props = {};
1126 auto ret = ListProperty(userId_, props);
1127 if (ret != ErrorCode::NO_ERROR) {
1128 IMSA_HILOGE("ListProperty failed");
1129 return ret;
1130 }
1131 auto iter = std::find_if(props.begin(), props.end(),
1132 [¤t](const Property &property) { return property.name != current->name; });
1133 if (iter != props.end()) {
1134 return SwitchInputMethodSubtype(iter->name, iter->id);
1135 }
1136 }
1137 IMSA_HILOGD("keycode undefined");
1138 return ErrorCode::ERROR_EX_UNSUPPORTED_OPERATION;
1139 }
1140
InitKeyEventMonitor()1141 int32_t InputMethodSystemAbility::InitKeyEventMonitor()
1142 {
1143 IMSA_HILOGI("InputMethodSystemAbility::InitKeyEventMonitor");
1144 bool ret = ImCommonEventManager::GetInstance()->SubscribeKeyboardEvent(
1145 [this](uint32_t keyCode) { return SwitchByCombinationKey(keyCode); });
1146 return ret ? ErrorCode::NO_ERROR : ErrorCode::ERROR_SERVICE_START_FAILED;
1147 }
1148 } // namespace MiscServices
1149 } // namespace OHOS
1150