• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &currentIme = 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 &params = 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 &currentIme = 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 &currentIme = 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 &currentIme = 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 &currentIme = 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                                   [&current](const SubProperty &property) { return property.mode == "lower"; })
1109                               : FindSubPropertyByCompare(current->name,
1110                                   [&current](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                                   [&current](const SubProperty &property) { return property.language == "english"; })
1118                               : FindSubPropertyByCompare(current->name,
1119                                   [&current](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                 [&current](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