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