• 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_ability.h"
17 
18 #include <unistd.h>
19 
20 #include "global.h"
21 #include "input_method_agent_proxy.h"
22 #include "input_method_agent_stub.h"
23 #include "input_method_core_proxy.h"
24 #include "input_method_core_stub.h"
25 #include "input_method_utils.h"
26 #include "iservice_registry.h"
27 #include "itypes_util.h"
28 #include "message_parcel.h"
29 #include "string_ex.h"
30 #include "system_ability_definition.h"
31 
32 namespace OHOS {
33 namespace MiscServices {
34     class MessageHandler;
35     using namespace MessageID;
36     sptr<InputMethodAbility> InputMethodAbility::instance_;
37     std::mutex InputMethodAbility::instanceLock_;
InputMethodAbility()38     InputMethodAbility::InputMethodAbility() : stop_(false)
39     {
40         writeInputChannel = nullptr;
41         Initialize();
42     }
43 
~InputMethodAbility()44     InputMethodAbility::~InputMethodAbility()
45     {
46         IMSA_HILOGI("InputMethodAbility::~InputMethodAbility");
47         QuitWorkThread();
48         if (msgHandler) {
49             delete msgHandler;
50             msgHandler = nullptr;
51         }
52     }
53 
GetInstance()54     sptr<InputMethodAbility> InputMethodAbility::GetInstance()
55     {
56         if (!instance_) {
57             std::lock_guard<std::mutex> autoLock(instanceLock_);
58             if (!instance_) {
59                 IMSA_HILOGI("InputMethodAbility::GetInstance need new IMA");
60                 instance_ = new InputMethodAbility();
61             }
62         }
63         return instance_;
64     }
65 
GetImsaProxy()66     sptr<InputMethodSystemAbilityProxy> InputMethodAbility::GetImsaProxy()
67     {
68         IMSA_HILOGI("InputMethodAbility::GetImsaProxy");
69         sptr<ISystemAbilityManager> systemAbilityManager =
70             SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
71         if (systemAbilityManager == nullptr) {
72             IMSA_HILOGI("InputMethodAbility::GetImsaProxy systemAbilityManager is nullptr");
73             return nullptr;
74         }
75 
76         auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, "");
77         if (systemAbility == nullptr) {
78             IMSA_HILOGI("InputMethodAbility::GetImsaProxy systemAbility is nullptr");
79             return nullptr;
80         }
81         if (deathRecipientPtr_ == nullptr) {
82             deathRecipientPtr_ = new (std::nothrow) ServiceDeathRecipient();
83             if (deathRecipientPtr_ == nullptr) {
84                 IMSA_HILOGE("new ServiceDeathRecipient failed");
85                 return nullptr;
86             }
87         }
88         if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipientPtr_))) {
89             IMSA_HILOGE("failed to add death recipient.");
90         }
91 
92         sptr<InputMethodSystemAbilityProxy> iface = new InputMethodSystemAbilityProxy(systemAbility);
93         return iface;
94     }
95 
SetCoreAndAgent()96     int32_t InputMethodAbility::SetCoreAndAgent()
97     {
98         IMSA_HILOGI("InputMethodAbility, run in");
99         if (isBound_.load()) {
100             IMSA_HILOGD("already bound");
101             return ErrorCode::NO_ERROR;
102         }
103         mImms = GetImsaProxy();
104         if (mImms == nullptr) {
105             IMSA_HILOGI("mImms is nullptr");
106             return ErrorCode::ERROR_NULL_POINTER;
107         }
108         sptr<InputMethodCoreStub> stub = new InputMethodCoreStub(0);
109         stub->SetMessageHandler(msgHandler);
110 
111         sptr<InputMethodAgentStub> inputMethodAgentStub(new InputMethodAgentStub());
112         inputMethodAgentStub->SetMessageHandler(msgHandler);
113         sptr<IInputMethodAgent> inputMethodAgent = sptr(new InputMethodAgentProxy(inputMethodAgentStub));
114         int32_t ret = mImms->SetCoreAndAgent(stub, inputMethodAgent);
115         if (ret != ErrorCode::NO_ERROR) {
116             IMSA_HILOGE("set failed, ret: %{public}d", ret);
117             return ret;
118         }
119         isBound_.store(true);
120         IMSA_HILOGD("set successfully");
121         return ErrorCode::NO_ERROR;
122     }
123 
Initialize()124     void InputMethodAbility::Initialize()
125     {
126         IMSA_HILOGI("InputMethodAbility::Initialize");
127         msgHandler = new MessageHandler();
128         workThreadHandler = std::thread([this] {
129             WorkThread();
130         });
131     }
132 
setImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)133     void InputMethodAbility::setImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)
134     {
135         IMSA_HILOGI("InputMethodAbility::setImeListener");
136         if (imeListener_ == nullptr) {
137             imeListener_ = std::move(imeListener);
138         }
139         if (deathRecipientPtr_ != nullptr && deathRecipientPtr_->listener == nullptr) {
140             deathRecipientPtr_->listener = imeListener_;
141         }
142     }
143 
OnImeReady()144     void InputMethodAbility::OnImeReady()
145     {
146         isImeReady_ = true;
147         if (!notifier_.isNotify) {
148             IMSA_HILOGI("InputMethodAbility::Ime Ready, don't need to notify");
149             return;
150         }
151         IMSA_HILOGI("InputMethodAbility::Ime Ready, notify InputStart");
152         ShowInputWindow(notifier_.isShowKeyboard, notifier_.subProperty);
153     }
154 
setKdListener(std::shared_ptr<KeyboardListener> kdListener)155     void InputMethodAbility::setKdListener(std::shared_ptr<KeyboardListener> kdListener)
156     {
157         IMSA_HILOGI("InputMethodAbility::setKdListener");
158         if (kdListener_ == nullptr) {
159             kdListener_ = kdListener;
160         }
161     }
162 
WorkThread()163     void InputMethodAbility::WorkThread()
164     {
165         while (!stop_) {
166             Message *msg = msgHandler->GetMessage();
167             switch (msg->msgId_) {
168                 case MSG_ID_INIT_INPUT_CONTROL_CHANNEL: {
169                     OnInitInputControlChannel(msg);
170                     break;
171                 }
172                 case MSG_ID_SHOW_KEYBOARD: {
173                     OnShowKeyboard(msg);
174                     break;
175                 }
176                 case MSG_ID_HIDE_KEYBOARD: {
177                     OnHideKeyboard(msg);
178                     break;
179                 }
180                 case MSG_ID_ON_CURSOR_UPDATE: {
181                     OnCursorUpdate(msg);
182                     break;
183                 }
184                 case MSG_ID_ON_SELECTION_CHANGE: {
185                     OnSelectionChange(msg);
186                     break;
187                 }
188                 case MSG_ID_STOP_INPUT_SERVICE:{
189                     MessageParcel *data = msg->msgContent_;
190                     std::string imeId = Str16ToStr8(data->ReadString16());
191                     if (imeListener_) {
192                         imeListener_->OnInputStop(imeId);
193                     }
194                     break;
195                 }
196                 case MSG_ID_SET_SUBTYPE: {
197                     OnSetSubtype(msg);
198                     break;
199                 }
200                 default: {
201                     IMSA_HILOGD("the message is %{public}d.", msg->msgId_);
202                     break;
203                 }
204             }
205             delete msg;
206             msg = nullptr;
207         }
208     }
209 
210 
OnInitInputControlChannel(Message * msg)211     void InputMethodAbility::OnInitInputControlChannel(Message *msg)
212     {
213         IMSA_HILOGI("InputMethodAbility::OnInitInputControlChannel");
214         MessageParcel *data = msg->msgContent_;
215         sptr<IRemoteObject> channelObject = data->ReadRemoteObject();
216         if (channelObject == nullptr) {
217             IMSA_HILOGI("InputMethodAbility::OnInitInputControlChannel channelObject is nullptr");
218             return;
219         }
220         if (deathRecipientPtr_ != nullptr) {
221             deathRecipientPtr_->currentIme_ = data->ReadString();
222         }
223         SetInputControlChannel(channelObject);
224     }
225 
226 
OnShowKeyboard(Message * msg)227     void InputMethodAbility::OnShowKeyboard(Message *msg)
228     {
229         IMSA_HILOGI("InputMethodAbility::OnShowKeyboard");
230         MessageParcel *data = msg->msgContent_;
231         sptr<IRemoteObject> channelObject = nullptr;
232         bool isShowKeyboard = false;
233         SubProperty subProperty;
234         if (!ITypesUtil::Unmarshal(*data, channelObject, isShowKeyboard, subProperty)) {
235             IMSA_HILOGE("InputMethodAbility::OnShowKeyboard read message parcel failed");
236             return;
237         }
238         if (channelObject == nullptr) {
239             IMSA_HILOGI("InputMethodAbility::OnShowKeyboard channelObject is nullptr");
240             return;
241         }
242         SetInputDataChannel(channelObject);
243         ShowInputWindow(isShowKeyboard, subProperty);
244     }
245 
OnHideKeyboard(Message * msg)246     void InputMethodAbility::OnHideKeyboard(Message *msg)
247     {
248         IMSA_HILOGI("InputMethodAbility::OnHideKeyboard");
249         DissmissInputWindow();
250     }
251 
OnSetSubtype(Message * msg)252     void InputMethodAbility::OnSetSubtype(Message *msg)
253     {
254         IMSA_HILOGI("InputMethodAbility::OnSetSubtype");
255         auto data = msg->msgContent_;
256         SubProperty subProperty;
257         if (!ITypesUtil::Unmarshal(*data, subProperty)) {
258             IMSA_HILOGE("read message parcel failed");
259             return;
260         }
261         if (imeListener_ == nullptr) {
262             IMSA_HILOGI("InputMethodAbility::OnSetSubtype imeListener_ is nullptr");
263             return;
264         }
265         imeListener_->OnSetSubtype(subProperty);
266     }
267 
DispatchKeyEvent(int32_t keyCode,int32_t keyStatus)268     bool InputMethodAbility::DispatchKeyEvent(int32_t keyCode, int32_t keyStatus)
269     {
270         IMSA_HILOGI("key = %{public}d, status = %{public}d", keyCode, keyStatus);
271         if (!kdListener_) {
272             IMSA_HILOGI("InputMethodAbility::DispatchKeyEvent kdListener_ is nullptr");
273             return false;
274         }
275         return kdListener_->OnKeyEvent(keyCode, keyStatus);
276     }
277 
SetCallingWindow(uint32_t windowId)278     void InputMethodAbility::SetCallingWindow(uint32_t windowId)
279     {
280         IMSA_HILOGI("InputMethodAbility::SetCallingWindow");
281 
282         if (!imeListener_) {
283             IMSA_HILOGI("InputMethodAbility::SetCallingWindow imeListener_ is nullptr");
284             return;
285         }
286         imeListener_->OnSetCallingWindow(windowId);
287     }
288 
289 
OnCursorUpdate(Message * msg)290     void InputMethodAbility::OnCursorUpdate(Message *msg)
291     {
292         IMSA_HILOGI("InputMethodAbility::OnCursorUpdate");
293         MessageParcel *data = msg->msgContent_;
294         int32_t positionX = data->ReadInt32();
295         int32_t positionY = data->ReadInt32();
296         int32_t height = data->ReadInt32();
297         if (!kdListener_) {
298             IMSA_HILOGI("InputMethodAbility::OnCursorUpdate kdListener_ is nullptr");
299             return;
300         }
301         kdListener_->OnCursorUpdate(positionX, positionY, height);
302     }
303 
OnSelectionChange(Message * msg)304     void InputMethodAbility::OnSelectionChange(Message *msg)
305     {
306         IMSA_HILOGI("InputMethodAbility::OnSelectionChange");
307         MessageParcel *data = msg->msgContent_;
308         std::string text = Str16ToStr8(data->ReadString16());
309         int32_t oldBegin = data->ReadInt32();
310         int32_t oldEnd = data->ReadInt32();
311         int32_t newBegin = data->ReadInt32();
312         int32_t newEnd = data->ReadInt32();
313 
314         if (!kdListener_) {
315             IMSA_HILOGI("InputMethodAbility::OnSelectionChange kdListener_ is nullptr");
316             return;
317         }
318         kdListener_->OnTextChange(text);
319 
320         kdListener_->OnSelectionChange(oldBegin, oldEnd, newBegin, newEnd);
321     }
322 
ShowInputWindow(bool isShowKeyboard,const SubProperty & subProperty)323     void InputMethodAbility::ShowInputWindow(bool isShowKeyboard, const SubProperty &subProperty)
324     {
325         IMSA_HILOGI("InputMethodAbility::ShowInputWindow");
326         if (!isImeReady_) {
327             IMSA_HILOGI("InputMethodAbility::ime is unready, store notifier_");
328             notifier_.isNotify = true;
329             notifier_.isShowKeyboard = isShowKeyboard;
330             notifier_.subProperty = subProperty;
331             return;
332         }
333         if (imeListener_ == nullptr) {
334             IMSA_HILOGI("InputMethodAbility::ShowInputWindow imeListener_ is nullptr");
335             return;
336         }
337         imeListener_->OnInputStart();
338         imeListener_->OnSetSubtype(subProperty);
339         if (!isShowKeyboard) {
340             IMSA_HILOGI("InputMethodAbility::ShowInputWindow will not show keyboard");
341             return;
342         }
343         imeListener_->OnKeyboardStatus(true);
344         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
345         if (channel == nullptr) {
346             IMSA_HILOGI("InputMethodAbility::ShowInputWindow channel is nullptr");
347             return;
348         }
349         channel->SendKeyboardStatus(KEYBOARD_SHOW);
350     }
351 
DissmissInputWindow()352     void InputMethodAbility::DissmissInputWindow()
353     {
354         IMSA_HILOGI("InputMethodAbility::DissmissInputWindow");
355         if (!imeListener_) {
356             IMSA_HILOGI("InputMethodAbility::DissmissInputWindow imeListener_ is nullptr");
357             return;
358         }
359         imeListener_->OnKeyboardStatus(false);
360         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
361         if (channel == nullptr) {
362             IMSA_HILOGI("InputMethodAbility::DissmissInputWindow channel is nullptr");
363             return;
364         }
365         channel->SendKeyboardStatus(KEYBOARD_HIDE);
366     }
367 
InsertText(const std::string text)368     int32_t InputMethodAbility::InsertText(const std::string text)
369     {
370         IMSA_HILOGI("InputMethodAbility::InsertText");
371         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
372         if (channel == nullptr) {
373             IMSA_HILOGI("InputMethodAbility::InsertText channel is nullptr");
374             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
375         }
376         return channel->InsertText(Utils::ToStr16(text));
377     }
378 
DeleteForward(int32_t length)379     int32_t InputMethodAbility::DeleteForward(int32_t length)
380     {
381         IMSA_HILOGI("InputMethodAbility::DeleteForward");
382         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
383         if (channel == nullptr) {
384             IMSA_HILOGI("InputMethodAbility::DeleteForward channel is nullptr");
385             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
386         }
387         return channel->DeleteForward(length);
388     }
389 
DeleteBackward(int32_t length)390     int32_t InputMethodAbility::DeleteBackward(int32_t length)
391     {
392         IMSA_HILOGI("InputMethodAbility::DeleteBackward");
393         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
394         if (channel == nullptr) {
395             IMSA_HILOGI("InputMethodAbility::DeleteBackward channel is nullptr");
396             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
397         }
398         return channel->DeleteBackward(length);
399     }
400 
SendFunctionKey(int32_t funcKey)401     int32_t InputMethodAbility::SendFunctionKey(int32_t funcKey)
402     {
403         IMSA_HILOGI("InputMethodAbility::SendFunctionKey");
404         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
405         if (channel == nullptr) {
406             IMSA_HILOGI("InputMethodAbility::SendFunctionKey channel is nullptr");
407             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
408         }
409         return channel->SendFunctionKey(funcKey);
410     }
411 
HideKeyboardSelf()412     int32_t InputMethodAbility::HideKeyboardSelf()
413     {
414         IMSA_HILOGI("InputMethodAbility::HideKeyboardSelf");
415         std::shared_ptr<InputControlChannelProxy> controlChannel = GetInputControlChannel();
416         if (controlChannel == nullptr) {
417             IMSA_HILOGI("InputMethodAbility::HideKeyboardSelf controlChannel is nullptr");
418             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
419         }
420         return controlChannel->HideKeyboardSelf(1);
421     }
422 
GetTextBeforeCursor(int32_t number,std::u16string & text)423     int32_t InputMethodAbility::GetTextBeforeCursor(int32_t number, std::u16string &text)
424     {
425         IMSA_HILOGI("InputMethodAbility::GetTextBeforeCursor");
426         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
427         if (channel == nullptr) {
428             IMSA_HILOGI("InputMethodAbility::GetTextBeforeCursor channel is nullptr");
429             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
430         }
431         return channel->GetTextBeforeCursor(number, text);
432     }
433 
GetTextAfterCursor(int32_t number,std::u16string & text)434     int32_t InputMethodAbility::GetTextAfterCursor(int32_t number, std::u16string &text)
435     {
436         IMSA_HILOGI("InputMethodAbility::GetTextAfterCursor");
437         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
438         if (channel == nullptr) {
439             IMSA_HILOGI("InputMethodAbility::GetTextAfterCursor channel is nullptr");
440             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
441         }
442         return channel->GetTextAfterCursor(number, text);
443     }
444 
MoveCursor(int32_t keyCode)445     int32_t InputMethodAbility::MoveCursor(int32_t keyCode)
446     {
447         IMSA_HILOGI("InputMethodAbility::MoveCursor");
448         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
449         if (channel == nullptr) {
450             IMSA_HILOGI("InputMethodAbility::MoveCursor channel is nullptr");
451             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
452         }
453 
454         return channel->MoveCursor(keyCode);
455     }
456 
GetEnterKeyType(int32_t & keyType)457     int32_t InputMethodAbility::GetEnterKeyType(int32_t &keyType)
458     {
459         IMSA_HILOGI("InputMethodAbility::GetEnterKeyType");
460         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
461         if (channel == nullptr) {
462             IMSA_HILOGI("InputMethodAbility::GetEnterKeyType channel is nullptr");
463             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
464         }
465         return channel->GetEnterKeyType(keyType);
466     }
467 
GetInputPattern(int32_t & inputPattern)468     int32_t InputMethodAbility::GetInputPattern(int32_t &inputPattern)
469     {
470         IMSA_HILOGI("InputMethodAbility::GetInputPattern");
471         std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel();
472         if (channel == nullptr) {
473             IMSA_HILOGI("InputMethodAbility::GetInputPattern channel is nullptr");
474             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
475         }
476         return channel->GetInputPattern(inputPattern);
477     }
478 
479 
SetInputDataChannel(sptr<IRemoteObject> & object)480     void InputMethodAbility::SetInputDataChannel(sptr<IRemoteObject> &object)
481     {
482         IMSA_HILOGI("run in SetInputDataChannel");
483         std::lock_guard<std::mutex> lock(dataChannelLock_);
484         std::shared_ptr<InputDataChannelProxy> channalProxy = std::make_shared<InputDataChannelProxy>(object);
485         if (channalProxy == nullptr) {
486             IMSA_HILOGI("InputMethodAbility::SetInputDataChannel inputDataChannel is nullptr");
487             return;
488         }
489         dataChannel_ = channalProxy;
490     }
491 
GetInputDataChannel()492     std::shared_ptr<InputDataChannelProxy> InputMethodAbility::GetInputDataChannel()
493     {
494         std::lock_guard<std::mutex> lock(dataChannelLock_);
495         return dataChannel_;
496     }
497 
SetInputControlChannel(sptr<IRemoteObject> & object)498     void InputMethodAbility::SetInputControlChannel(sptr<IRemoteObject> &object)
499     {
500         IMSA_HILOGI("run in SetInputControlChannel");
501         std::lock_guard<std::mutex> lock(controlChannelLock_);
502         std::shared_ptr<InputControlChannelProxy> channalProxy = std::make_shared<InputControlChannelProxy>(object);
503         if (channalProxy == nullptr) {
504             IMSA_HILOGI("InputMethodAbility::SetInputControlChannel inputDataChannel is nullptr");
505             return;
506         }
507         controlChannel_ = channalProxy;
508     }
509 
GetInputControlChannel()510     std::shared_ptr<InputControlChannelProxy> InputMethodAbility::GetInputControlChannel()
511     {
512         std::lock_guard<std::mutex> lock(controlChannelLock_);
513         return controlChannel_;
514     }
515 
OnRemoteDied(const wptr<IRemoteObject> & object)516     void InputMethodAbility::ServiceDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
517     {
518         IMSA_HILOGI("ServiceDeathRecipient::OnRemoteDied");
519         if (listener != nullptr) {
520             listener->OnInputStop(currentIme_);
521         }
522     }
523 
QuitWorkThread()524     void InputMethodAbility::QuitWorkThread()
525     {
526         stop_ = true;
527         Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
528         msgHandler->SendMessage(msg);
529         if (workThreadHandler.joinable()) {
530             workThreadHandler.join();
531         }
532     }
533 } // namespace MiscServices
534 } // namespace OHOS
535