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