• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2023 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 <utility>
21 
22 #include "global.h"
23 #include "input_method_agent_proxy.h"
24 #include "input_method_core_proxy.h"
25 #include "input_method_utils.h"
26 #include "inputmethod_sysevent.h"
27 #include "inputmethod_trace.h"
28 #include "iservice_registry.h"
29 #include "itypes_util.h"
30 #include "message_parcel.h"
31 #include "string_ex.h"
32 #include "sys/prctl.h"
33 #include "system_ability_definition.h"
34 
35 namespace OHOS {
36 namespace MiscServices {
37 class MessageHandler;
38 using namespace MessageID;
39 sptr<InputMethodAbility> InputMethodAbility::instance_;
40 std::mutex InputMethodAbility::instanceLock_;
41 constexpr double INVALID_CURSOR_VALUE = -1.0;
42 constexpr int32_t INVALID_SELECTION_VALUE = -1;
43 constexpr uint32_t FIND_PANEL_RETRY_INTERVAL = 10;
44 constexpr uint32_t MAX_RETRY_TIMES = 100;
InputMethodAbility()45 InputMethodAbility::InputMethodAbility() : msgHandler_(nullptr), stop_(false)
46 {
47 }
48 
~InputMethodAbility()49 InputMethodAbility::~InputMethodAbility()
50 {
51     IMSA_HILOGI("InputMethodAbility::~InputMethodAbility");
52     QuitWorkThread();
53     if (msgHandler_ != nullptr) {
54         delete msgHandler_;
55         msgHandler_ = nullptr;
56     }
57 }
58 
GetInstance()59 sptr<InputMethodAbility> InputMethodAbility::GetInstance()
60 {
61     if (instance_ == nullptr) {
62         std::lock_guard<std::mutex> autoLock(instanceLock_);
63         if (instance_ == nullptr) {
64             IMSA_HILOGI("InputMethodAbility need new IMA");
65             instance_ = new (std::nothrow) InputMethodAbility();
66             if (instance_ == nullptr) {
67                 IMSA_HILOGE("instance is nullptr.");
68                 return instance_;
69             }
70             instance_->Initialize();
71         }
72     }
73     return instance_;
74 }
75 
GetImsaProxy()76 sptr<IInputMethodSystemAbility> InputMethodAbility::GetImsaProxy()
77 {
78     std::lock_guard<std::mutex> lock(abilityLock_);
79     if (abilityManager_ != nullptr) {
80         return abilityManager_;
81     }
82     IMSA_HILOGI("InputMethodAbility get imsa proxy");
83     sptr<ISystemAbilityManager> systemAbilityManager =
84         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
85     if (systemAbilityManager == nullptr) {
86         IMSA_HILOGE("systemAbilityManager is nullptr");
87         return nullptr;
88     }
89     auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, "");
90     if (systemAbility == nullptr) {
91         IMSA_HILOGE("systemAbility is nullptr");
92         return nullptr;
93     }
94     if (deathRecipient_ == nullptr) {
95         deathRecipient_ = new (std::nothrow) InputDeathRecipient();
96         if (deathRecipient_ == nullptr) {
97             IMSA_HILOGE("failed to new death recipient");
98             return nullptr;
99         }
100     }
101     deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) { OnRemoteSaDied(remote); });
102     if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
103         IMSA_HILOGE("failed to add death recipient.");
104         return nullptr;
105     }
106     abilityManager_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
107     return abilityManager_;
108 }
109 
SetCoreAndAgent()110 int32_t InputMethodAbility::SetCoreAndAgent()
111 {
112     IMSA_HILOGD("InputMethodAbility, run in");
113     if (isBound_.load()) {
114         IMSA_HILOGD("already bound");
115         return ErrorCode::NO_ERROR;
116     }
117     auto proxy = GetImsaProxy();
118     if (proxy == nullptr) {
119         IMSA_HILOGE("imsa proxy is nullptr");
120         return ErrorCode::ERROR_NULL_POINTER;
121     }
122     int32_t ret = proxy->SetCoreAndAgent(coreStub_, agentStub_);
123     if (ret != ErrorCode::NO_ERROR) {
124         IMSA_HILOGE("set failed, ret: %{public}d", ret);
125         return ret;
126     }
127     isBound_.store(true);
128     IMSA_HILOGD("set successfully");
129     return ErrorCode::NO_ERROR;
130 }
131 
UnRegisteredProxyIme(UnRegisteredType type)132 int32_t InputMethodAbility::UnRegisteredProxyIme(UnRegisteredType type)
133 {
134     isBound_.store(false);
135     auto proxy = GetImsaProxy();
136     if (proxy == nullptr) {
137         IMSA_HILOGE("imsa proxy is nullptr");
138         return ErrorCode::ERROR_NULL_POINTER;
139     }
140     return proxy->UnRegisteredProxyIme(type, coreStub_);
141 }
142 
Initialize()143 void InputMethodAbility::Initialize()
144 {
145     IMSA_HILOGD("IMA");
146     coreStub_ = new (std::nothrow) InputMethodCoreStub();
147     if (coreStub_ == nullptr) {
148         IMSA_HILOGE("failed to create core");
149         return;
150     }
151     agentStub_ = new (std::nothrow) InputMethodAgentStub();
152     if (agentStub_ == nullptr) {
153         IMSA_HILOGE("failed to create agent");
154         return;
155     }
156     msgHandler_ = new (std::nothrow) MessageHandler();
157     if (msgHandler_ == nullptr) {
158         IMSA_HILOGE("failed to create message handler");
159         return;
160     }
161     coreStub_->SetMessageHandler(msgHandler_);
162     agentStub_->SetMessageHandler(msgHandler_);
163     workThreadHandler = std::thread([this] { WorkThread(); });
164 }
165 
SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)166 void InputMethodAbility::SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)
167 {
168     IMSA_HILOGD("InputMethodAbility");
169     if (imeListener_ == nullptr) {
170         imeListener_ = std::move(imeListener);
171     }
172 }
173 
SetKdListener(std::shared_ptr<KeyboardListener> kdListener)174 void InputMethodAbility::SetKdListener(std::shared_ptr<KeyboardListener> kdListener)
175 {
176     IMSA_HILOGD("InputMethodAbility.");
177     if (kdListener_ == nullptr) {
178         kdListener_ = std::move(kdListener);
179     }
180 }
181 
WorkThread()182 void InputMethodAbility::WorkThread()
183 {
184     prctl(PR_SET_NAME, "OS_IMAWorkThread");
185     while (!stop_) {
186         Message *msg = msgHandler_->GetMessage();
187         switch (msg->msgId_) {
188             case MSG_ID_INIT_INPUT_CONTROL_CHANNEL: {
189                 OnInitInputControlChannel(msg);
190                 break;
191             }
192             case MSG_ID_ON_CURSOR_UPDATE: {
193                 OnCursorUpdate(msg);
194                 break;
195             }
196             case MSG_ID_ON_SELECTION_CHANGE: {
197                 OnSelectionChange(msg);
198                 break;
199             }
200             case MSG_ID_ON_CONFIGURATION_CHANGE: {
201                 OnConfigurationChange(msg);
202                 break;
203             }
204             case MSG_ID_STOP_INPUT_SERVICE: {
205                 OnStopInputService(msg);
206                 break;
207             }
208             case MSG_ID_SET_SUBTYPE: {
209                 OnSetSubtype(msg);
210                 break;
211             }
212             default: {
213                 IMSA_HILOGD("the message is %{public}d.", msg->msgId_);
214                 break;
215             }
216         }
217         delete msg;
218         msg = nullptr;
219     }
220 }
221 
OnInitInputControlChannel(Message * msg)222 void InputMethodAbility::OnInitInputControlChannel(Message *msg)
223 {
224     IMSA_HILOGD("InputMethodAbility::OnInitInputControlChannel");
225     MessageParcel *data = msg->msgContent_;
226     sptr<IRemoteObject> channelObject = data->ReadRemoteObject();
227     if (channelObject == nullptr) {
228         IMSA_HILOGE("channelObject is nullptr");
229         return;
230     }
231     SetInputControlChannel(channelObject);
232 }
233 
StartInput(const InputClientInfo & clientInfo,bool isBindFromClient)234 int32_t InputMethodAbility::StartInput(const InputClientInfo &clientInfo, bool isBindFromClient)
235 {
236     if (clientInfo.channel->AsObject() == nullptr) {
237         IMSA_HILOGE("channelObject is nullptr");
238         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
239     }
240     IMSA_HILOGI(
241         "IMA isShowKeyboard: %{public}d, isBindFromClient: %{public}d", clientInfo.isShowKeyboard, isBindFromClient);
242     SetInputDataChannel(clientInfo.channel->AsObject());
243     isBindFromClient ? InvokeTextChangeCallback(clientInfo.config) : NotifyAllTextConfig();
244     if (imeListener_ == nullptr) {
245         IMSA_HILOGE("imeListener is nullptr");
246         return ErrorCode::ERROR_IME;
247     }
248     if (clientInfo.isNotifyInputStart) {
249         imeListener_->OnInputStart();
250     }
251     isPendingShowKeyboard_ = clientInfo.isShowKeyboard;
252     return clientInfo.isShowKeyboard ? ShowKeyboard() : ErrorCode::NO_ERROR;
253 }
254 
OnSetSubtype(Message * msg)255 void InputMethodAbility::OnSetSubtype(Message *msg)
256 {
257     auto data = msg->msgContent_;
258     SubProperty subProperty;
259     if (!ITypesUtil::Unmarshal(*data, subProperty)) {
260         IMSA_HILOGE("read message parcel failed");
261         return;
262     }
263     if (imeListener_ == nullptr) {
264         IMSA_HILOGE("imeListener_ is nullptr");
265         return;
266     }
267     imeListener_->OnSetSubtype(subProperty);
268 }
269 
ClearDataChannel(const sptr<IRemoteObject> & channel)270 void InputMethodAbility::ClearDataChannel(const sptr<IRemoteObject> &channel)
271 {
272     std::lock_guard<std::mutex> lock(dataChannelLock_);
273     if (dataChannelObject_ == nullptr || channel == nullptr) {
274         IMSA_HILOGD("dataChannelObject_ already nullptr");
275         return;
276     }
277     if (dataChannelObject_.GetRefPtr() == channel.GetRefPtr()) {
278         dataChannelObject_ = nullptr;
279         dataChannelProxy_ = nullptr;
280         IMSA_HILOGD("end");
281     }
282 }
283 
StopInput(const sptr<IRemoteObject> & channelObject)284 int32_t InputMethodAbility::StopInput(const sptr<IRemoteObject> &channelObject)
285 {
286     IMSA_HILOGI("IMA");
287     HideKeyboard();
288     ClearDataChannel(channelObject);
289     if (imeListener_ != nullptr) {
290         imeListener_->OnInputFinish();
291     }
292     return ErrorCode::NO_ERROR;
293 }
294 
DispatchKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,sptr<KeyEventConsumerProxy> & consumer)295 int32_t InputMethodAbility::DispatchKeyEvent(
296     const std::shared_ptr<MMI::KeyEvent> &keyEvent, sptr<KeyEventConsumerProxy> &consumer)
297 {
298     if (keyEvent == nullptr) {
299         IMSA_HILOGE("keyEvent is nullptr");
300         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
301     }
302     if (kdListener_ == nullptr) {
303         IMSA_HILOGE("kdListener_ is nullptr");
304         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
305     }
306     IMSA_HILOGD("InputMethodAbility, run in");
307 
308     if (!kdListener_->OnDealKeyEvent(keyEvent, consumer)) {
309         IMSA_HILOGE("keyEvent not deal");
310         return ErrorCode::ERROR_DISPATCH_KEY_EVENT;
311     }
312     return ErrorCode::NO_ERROR;
313 }
314 
SetCallingWindow(uint32_t windowId)315 void InputMethodAbility::SetCallingWindow(uint32_t windowId)
316 {
317     if (imeListener_ == nullptr) {
318         IMSA_HILOGE("imeListener_ is nullptr");
319         return;
320     }
321     IMSA_HILOGD("InputMethodAbility windowId: %{public}d", windowId);
322     panels_.ForEach([windowId](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
323         panel->SetCallingWindow(windowId);
324         return false;
325     });
326     imeListener_->OnSetCallingWindow(windowId);
327 }
328 
OnCursorUpdate(Message * msg)329 void InputMethodAbility::OnCursorUpdate(Message *msg)
330 {
331     MessageParcel *data = msg->msgContent_;
332     int32_t positionX = data->ReadInt32();
333     int32_t positionY = data->ReadInt32();
334     int32_t height = data->ReadInt32();
335     if (kdListener_ == nullptr) {
336         IMSA_HILOGE("kdListener_ is nullptr");
337         return;
338     }
339     IMSA_HILOGD("InputMethodAbility, x: %{public}d, y: %{public}d, height: %{public}d", positionX, positionY, height);
340     kdListener_->OnCursorUpdate(positionX, positionY, height);
341 }
342 
OnSelectionChange(Message * msg)343 void InputMethodAbility::OnSelectionChange(Message *msg)
344 {
345     MessageParcel *data = msg->msgContent_;
346     std::string text = Str16ToStr8(data->ReadString16());
347     int32_t oldBegin = data->ReadInt32();
348     int32_t oldEnd = data->ReadInt32();
349     int32_t newBegin = data->ReadInt32();
350     int32_t newEnd = data->ReadInt32();
351 
352     if (kdListener_ == nullptr) {
353         IMSA_HILOGE("kdListener_ is nullptr");
354         return;
355     }
356     kdListener_->OnTextChange(text);
357     kdListener_->OnSelectionChange(oldBegin, oldEnd, newBegin, newEnd);
358 }
359 
OnConfigurationChange(Message * msg)360 void InputMethodAbility::OnConfigurationChange(Message *msg)
361 {
362     if (kdListener_ == nullptr) {
363         IMSA_HILOGE("in, kdListener_ is nullptr");
364         return;
365     }
366     MessageParcel *data = msg->msgContent_;
367     InputAttribute attribute;
368     attribute.enterKeyType = data->ReadInt32();
369     attribute.inputPattern = data->ReadInt32();
370     IMSA_HILOGD("InputMethodAbility, enterKeyType: %{public}d, inputPattern: %{public}d", attribute.enterKeyType,
371         attribute.inputPattern);
372     kdListener_->OnEditorAttributeChange(attribute);
373 }
374 
OnStopInputService(Message * msg)375 void InputMethodAbility::OnStopInputService(Message *msg)
376 {
377     MessageParcel *data = msg->msgContent_;
378     bool isTerminateIme = data->ReadBool();
379     IMSA_HILOGI("isTerminateIme: %{public}d", isTerminateIme);
380     if (isTerminateIme && imeListener_ != nullptr) {
381         imeListener_->OnInputStop();
382     }
383     isBound_.store(false);
384 }
385 
ShowKeyboard()386 int32_t InputMethodAbility::ShowKeyboard()
387 {
388     if (imeListener_ == nullptr) {
389         IMSA_HILOGE("imeListener is nullptr");
390         return ErrorCode::ERROR_IME;
391     }
392     IMSA_HILOGI("IMA start");
393     if (panels_.Contains(SOFT_KEYBOARD)) {
394         auto panel = GetSoftKeyboardPanel();
395         if (panel == nullptr) {
396             IMSA_HILOGE("panel is nullptr.");
397             return ErrorCode::ERROR_IME;
398         }
399         NotifyKeyboardHeight(panel);
400         auto flag = panel->GetPanelFlag();
401         imeListener_->OnKeyboardStatus(true);
402         if (flag == FLG_CANDIDATE_COLUMN) {
403             IMSA_HILOGI("panel flag is candidate, no need to show.");
404             return ErrorCode::NO_ERROR;
405         }
406         return ShowPanel(panel, flag, Trigger::IMF);
407     }
408     IMSA_HILOGI("panel not create");
409     auto channel = GetInputDataChannelProxy();
410     if (channel != nullptr) {
411         channel->SendKeyboardStatus(KeyboardStatus::SHOW);
412     }
413     imeListener_->OnKeyboardStatus(true);
414     return ErrorCode::NO_ERROR;
415 }
416 
NotifyPanelStatusInfo(const PanelStatusInfo & info)417 void InputMethodAbility::NotifyPanelStatusInfo(const PanelStatusInfo &info)
418 {
419     // CANDIDATE_COLUMN not notify
420     if (info.panelInfo.panelFlag == PanelFlag::FLG_CANDIDATE_COLUMN) {
421         return;
422     }
423     auto channel = GetInputDataChannelProxy();
424     if (channel != nullptr) {
425         if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD) {
426             info.visible ? channel->SendKeyboardStatus(KeyboardStatus::SHOW)
427                          : channel->SendKeyboardStatus(KeyboardStatus::HIDE);
428         }
429         channel->NotifyPanelStatusInfo(info);
430     }
431 
432     auto controlChannel = GetInputControlChannel();
433     if (controlChannel != nullptr && info.trigger == Trigger::IME_APP && !info.visible) {
434         controlChannel->HideKeyboardSelf();
435     }
436 }
437 
NotifyAllTextConfig()438 void InputMethodAbility::NotifyAllTextConfig()
439 {
440     TextTotalConfig textConfig = {};
441     int32_t ret = GetTextConfig(textConfig);
442     if (ret != ErrorCode::NO_ERROR) {
443         IMSA_HILOGE("get text config failed, ret is %{public}d", ret);
444         return;
445     }
446     InvokeTextChangeCallback(textConfig);
447 }
448 
InvokeTextChangeCallback(const TextTotalConfig & textConfig)449 void InputMethodAbility::InvokeTextChangeCallback(const TextTotalConfig &textConfig)
450 {
451     if (kdListener_ == nullptr) {
452         IMSA_HILOGD("kdListener_ is nullptr.");
453     } else {
454         IMSA_HILOGD("start to invoke callbacks");
455         kdListener_->OnEditorAttributeChange(textConfig.inputAttribute);
456         if (textConfig.cursorInfo.left != INVALID_CURSOR_VALUE) {
457             IMSA_HILOGD("callback cursorUpdate");
458             kdListener_->OnCursorUpdate(
459                 textConfig.cursorInfo.left, textConfig.cursorInfo.top, textConfig.cursorInfo.height);
460         }
461         if (textConfig.textSelection.newBegin != INVALID_SELECTION_VALUE) {
462             IMSA_HILOGD("callback selectionChange");
463             kdListener_->OnSelectionChange(textConfig.textSelection.oldBegin, textConfig.textSelection.oldEnd,
464                 textConfig.textSelection.newBegin, textConfig.textSelection.newEnd);
465         }
466     }
467     if (textConfig.windowId == INVALID_WINDOW_ID) {
468         IMSA_HILOGD("invalid window id");
469         return;
470     }
471     panels_.ForEach([&textConfig](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
472         panel->SetCallingWindow(textConfig.windowId);
473         return false;
474     });
475     positionY_ = textConfig.positionY;
476     height_ = textConfig.height;
477     if (imeListener_ == nullptr) {
478         IMSA_HILOGD("imeListener_ is nullptr");
479         return;
480     }
481     imeListener_->OnSetCallingWindow(textConfig.windowId);
482 }
483 
HideKeyboard()484 int32_t InputMethodAbility::HideKeyboard()
485 {
486     return HideKeyboard(Trigger::IMF);
487 }
488 
InsertText(const std::string text)489 int32_t InputMethodAbility::InsertText(const std::string text)
490 {
491     InputMethodSyncTrace tracer("IMA_InsertText");
492     IMSA_HILOGD("InputMethodAbility, in");
493     auto channel = GetInputDataChannelProxy();
494     if (channel == nullptr) {
495         IMSA_HILOGE("channel is nullptr");
496         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
497     }
498     return channel->InsertText(Str8ToStr16(text));
499 }
500 
DeleteForward(int32_t length)501 int32_t InputMethodAbility::DeleteForward(int32_t length)
502 {
503     InputMethodSyncTrace tracer("IMA_DeleteForward");
504     IMSA_HILOGD("InputMethodAbility, length = %{public}d", length);
505     auto channel = GetInputDataChannelProxy();
506     if (channel == nullptr) {
507         IMSA_HILOGE("channel is nullptr");
508         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
509     }
510     return channel->DeleteForward(length);
511 }
512 
DeleteBackward(int32_t length)513 int32_t InputMethodAbility::DeleteBackward(int32_t length)
514 {
515     IMSA_HILOGD("InputMethodAbility, length = %{public}d", length);
516     auto channel = GetInputDataChannelProxy();
517     if (channel == nullptr) {
518         IMSA_HILOGE("channel is nullptr");
519         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
520     }
521     return channel->DeleteBackward(length);
522 }
523 
SendFunctionKey(int32_t funcKey)524 int32_t InputMethodAbility::SendFunctionKey(int32_t funcKey)
525 {
526     auto channel = GetInputDataChannelProxy();
527     if (channel == nullptr) {
528         IMSA_HILOGE("channel is nullptr");
529         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
530     }
531     return channel->SendFunctionKey(funcKey);
532 }
533 
HideKeyboardSelf()534 int32_t InputMethodAbility::HideKeyboardSelf()
535 {
536     auto ret = HideKeyboard(Trigger::IME_APP);
537     if (ret == ErrorCode::NO_ERROR) {
538         InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_SELF);
539     }
540     return ret == ErrorCode::ERROR_CLIENT_NULL_POINTER ? ret : ErrorCode::NO_ERROR;
541 }
542 
SendExtendAction(int32_t action)543 int32_t InputMethodAbility::SendExtendAction(int32_t action)
544 {
545     IMSA_HILOGD("InputMethodAbility, action: %{public}d", action);
546     auto channel = GetInputDataChannelProxy();
547     if (channel == nullptr) {
548         IMSA_HILOGE("channel is nullptr");
549         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
550     }
551     return channel->HandleExtendAction(action);
552 }
553 
GetTextBeforeCursor(int32_t number,std::u16string & text)554 int32_t InputMethodAbility::GetTextBeforeCursor(int32_t number, std::u16string &text)
555 {
556     InputMethodSyncTrace tracer("IMA_GetForward");
557     IMSA_HILOGD("InputMethodAbility, number: %{public}d", number);
558     auto channel = GetInputDataChannelProxy();
559     if (channel == nullptr) {
560         IMSA_HILOGE("channel is nullptr");
561         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
562     }
563     return channel->GetTextBeforeCursor(number, text);
564 }
565 
GetTextAfterCursor(int32_t number,std::u16string & text)566 int32_t InputMethodAbility::GetTextAfterCursor(int32_t number, std::u16string &text)
567 {
568     IMSA_HILOGD("InputMethodAbility, number: %{public}d", number);
569     auto channel = GetInputDataChannelProxy();
570     if (channel == nullptr) {
571         IMSA_HILOGE("channel is nullptr");
572         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
573     }
574     return channel->GetTextAfterCursor(number, text);
575 }
576 
MoveCursor(int32_t keyCode)577 int32_t InputMethodAbility::MoveCursor(int32_t keyCode)
578 {
579     IMSA_HILOGD("InputMethodAbility, keyCode = %{public}d", keyCode);
580     auto channel = GetInputDataChannelProxy();
581     if (channel == nullptr) {
582         IMSA_HILOGE("channel is nullptr");
583         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
584     }
585     return channel->MoveCursor(keyCode);
586 }
587 
SelectByRange(int32_t start,int32_t end)588 int32_t InputMethodAbility::SelectByRange(int32_t start, int32_t end)
589 {
590     IMSA_HILOGD("InputMethodAbility, start = %{public}d, end = %{public}d", start, end);
591     if (start < 0 || end < 0) {
592         IMSA_HILOGE("check parameter failed, start: %{public}d, end: %{public}d", start, end);
593         return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
594     }
595     auto dataChannel = GetInputDataChannelProxy();
596     if (dataChannel == nullptr) {
597         IMSA_HILOGE("datachannel is nullptr");
598         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
599     }
600     return dataChannel->SelectByRange(start, end);
601 }
602 
SelectByMovement(int32_t direction)603 int32_t InputMethodAbility::SelectByMovement(int32_t direction)
604 {
605     IMSA_HILOGD("InputMethodAbility, direction = %{public}d", direction);
606     auto dataChannel = GetInputDataChannelProxy();
607     if (dataChannel == nullptr) {
608         IMSA_HILOGE("datachannel is nullptr");
609         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
610     }
611     return dataChannel->SelectByMovement(direction, 0);
612 }
613 
GetEnterKeyType(int32_t & keyType)614 int32_t InputMethodAbility::GetEnterKeyType(int32_t &keyType)
615 {
616     IMSA_HILOGD("InputMethodAbility, run in");
617     auto channel = GetInputDataChannelProxy();
618     if (channel == nullptr) {
619         IMSA_HILOGE("channel is nullptr");
620         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
621     }
622     return channel->GetEnterKeyType(keyType);
623 }
624 
GetInputPattern(int32_t & inputPattern)625 int32_t InputMethodAbility::GetInputPattern(int32_t &inputPattern)
626 {
627     IMSA_HILOGD("InputMethodAbility, run in");
628     auto channel = GetInputDataChannelProxy();
629     if (channel == nullptr) {
630         IMSA_HILOGE("channel is nullptr");
631         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
632     }
633     return channel->GetInputPattern(inputPattern);
634 }
635 
GetTextIndexAtCursor(int32_t & index)636 int32_t InputMethodAbility::GetTextIndexAtCursor(int32_t &index)
637 {
638     IMSA_HILOGD("InputMethodAbility, run in");
639     auto channel = GetInputDataChannelProxy();
640     if (channel == nullptr) {
641         IMSA_HILOGE("channel is nullptr");
642         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
643     }
644     return channel->GetTextIndexAtCursor(index);
645 }
646 
GetTextConfig(TextTotalConfig & textConfig)647 int32_t InputMethodAbility::GetTextConfig(TextTotalConfig &textConfig)
648 {
649     IMSA_HILOGD("InputMethodAbility, run in.");
650     auto channel = GetInputDataChannelProxy();
651     if (channel == nullptr) {
652         IMSA_HILOGE("channel is nullptr");
653         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
654     }
655     return channel->GetTextConfig(textConfig);
656 }
657 
SetInputDataChannel(const sptr<IRemoteObject> & object)658 void InputMethodAbility::SetInputDataChannel(const sptr<IRemoteObject> &object)
659 {
660     IMSA_HILOGD("run in SetInputDataChannel");
661     std::lock_guard<std::mutex> lock(dataChannelLock_);
662     auto channelProxy = std::make_shared<InputDataChannelProxy>(object);
663     if (channelProxy == nullptr) {
664         IMSA_HILOGE("failed to new data channel proxy");
665         return;
666     }
667     dataChannelObject_ = object;
668     dataChannelProxy_ = channelProxy;
669 }
670 
GetInputDataChannelProxy()671 std::shared_ptr<InputDataChannelProxy> InputMethodAbility::GetInputDataChannelProxy()
672 {
673     std::lock_guard<std::mutex> lock(dataChannelLock_);
674     return dataChannelProxy_;
675 }
676 
SetInputControlChannel(sptr<IRemoteObject> & object)677 void InputMethodAbility::SetInputControlChannel(sptr<IRemoteObject> &object)
678 {
679     IMSA_HILOGD("run in SetInputControlChannel");
680     std::lock_guard<std::mutex> lock(controlChannelLock_);
681     std::shared_ptr<InputControlChannelProxy> channelProxy = std::make_shared<InputControlChannelProxy>(object);
682     if (channelProxy == nullptr) {
683         IMSA_HILOGD("InputMethodAbility inputDataChannel is nullptr");
684         return;
685     }
686     controlChannel_ = channelProxy;
687 }
688 
ClearInputControlChannel()689 void InputMethodAbility::ClearInputControlChannel()
690 {
691     std::lock_guard<std::mutex> lock(controlChannelLock_);
692     controlChannel_ = nullptr;
693 }
694 
GetInputControlChannel()695 std::shared_ptr<InputControlChannelProxy> InputMethodAbility::GetInputControlChannel()
696 {
697     std::lock_guard<std::mutex> lock(controlChannelLock_);
698     return controlChannel_;
699 }
700 
OnRemoteSaDied(const wptr<IRemoteObject> & object)701 void InputMethodAbility::OnRemoteSaDied(const wptr<IRemoteObject> &object)
702 {
703     IMSA_HILOGI("input method service died");
704     isBound_.store(false);
705     ClearInputControlChannel();
706     {
707         std::lock_guard<std::mutex> lock(abilityLock_);
708         abilityManager_ = nullptr;
709     }
710     if (imeListener_ != nullptr) {
711         imeListener_->OnInputStop();
712     }
713 }
714 
QuitWorkThread()715 void InputMethodAbility::QuitWorkThread()
716 {
717     stop_ = true;
718     Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
719     msgHandler_->SendMessage(msg);
720     if (workThreadHandler.joinable()) {
721         workThreadHandler.join();
722     }
723 }
724 
GetSecurityMode(int32_t & security)725 int32_t InputMethodAbility::GetSecurityMode(int32_t &security)
726 {
727     IMSA_HILOGI("InputMethodAbility start.");
728     auto proxy = GetImsaProxy();
729     if (proxy == nullptr) {
730         IMSA_HILOGE("failed to get imsa proxy.");
731         return false;
732     }
733     return proxy->GetSecurityMode(security);
734 }
735 
OnSecurityChange(int32_t security)736 int32_t InputMethodAbility::OnSecurityChange(int32_t security)
737 {
738     IMSA_HILOGI("InputMethodAbility start.");
739     if (imeListener_ == nullptr) {
740         IMSA_HILOGE("InputMethodAbility, imeListener is nullptr");
741         return ErrorCode::ERROR_BAD_PARAMETERS;
742     }
743     imeListener_->OnSecurityChange(security);
744     return ErrorCode::NO_ERROR;
745 }
746 
CreatePanel(const std::shared_ptr<AbilityRuntime::Context> & context,const PanelInfo & panelInfo,std::shared_ptr<InputMethodPanel> & inputMethodPanel)747 int32_t InputMethodAbility::CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context,
748     const PanelInfo &panelInfo, std::shared_ptr<InputMethodPanel> &inputMethodPanel)
749 {
750     IMSA_HILOGI("IMA");
751     auto flag = panels_.ComputeIfAbsent(panelInfo.panelType,
752         [&panelInfo, &context, &inputMethodPanel](const PanelType &panelType,
753             std::shared_ptr<InputMethodPanel> &panel) {
754             inputMethodPanel = std::make_shared<InputMethodPanel>();
755             auto ret = inputMethodPanel->CreatePanel(context, panelInfo);
756             if (ret == ErrorCode::NO_ERROR) {
757                 panel = inputMethodPanel;
758                 return true;
759             }
760             inputMethodPanel = nullptr;
761             return false;
762         });
763     // Called when creating the input method first time, if the CreatePanel is called later than the ShowKeyboard.
764     if (panelInfo.panelType == SOFT_KEYBOARD && isPendingShowKeyboard_) {
765         ShowKeyboard();
766         isPendingShowKeyboard_ = false;
767     }
768     return flag ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
769 }
770 
DestroyPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)771 int32_t InputMethodAbility::DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
772 {
773     IMSA_HILOGI("IMA");
774     if (inputMethodPanel == nullptr) {
775         IMSA_HILOGE("panel is nullptr");
776         return ErrorCode::ERROR_BAD_PARAMETERS;
777     }
778     auto ret = inputMethodPanel->DestroyPanel();
779     if (ret == ErrorCode::NO_ERROR) {
780         PanelType panelType = inputMethodPanel->GetPanelType();
781         panels_.Erase(panelType);
782     }
783     return ret;
784 }
785 
ShowPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)786 int32_t InputMethodAbility::ShowPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
787 {
788     if (inputMethodPanel == nullptr) {
789         return ErrorCode::ERROR_BAD_PARAMETERS;
790     }
791     return ShowPanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
792 }
793 
HidePanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)794 int32_t InputMethodAbility::HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
795 {
796     if (inputMethodPanel == nullptr) {
797         return ErrorCode::ERROR_BAD_PARAMETERS;
798     }
799     return HidePanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
800 }
801 
ShowPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,PanelFlag flag,Trigger trigger)802 int32_t InputMethodAbility::ShowPanel(
803     const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger)
804 {
805     if (inputMethodPanel == nullptr) {
806         return ErrorCode::ERROR_BAD_PARAMETERS;
807     }
808     if (trigger == Trigger::IME_APP && GetInputDataChannelProxy() == nullptr) {
809         IMSA_HILOGE("channel is nullptr");
810         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
811     }
812     if (flag == FLG_FIXED && inputMethodPanel->GetPanelType() == SOFT_KEYBOARD) {
813         auto ret = inputMethodPanel->SetTextFieldAvoidInfo(positionY_, height_);
814         if (ret != ErrorCode::NO_ERROR) {
815             IMSA_HILOGE("Set Keyboard failed, ret = %{public}d", ret);
816         }
817     }
818     auto ret = inputMethodPanel->ShowPanel();
819     if (ret == ErrorCode::NO_ERROR) {
820         NotifyPanelStatusInfo({ { inputMethodPanel->GetPanelType(), flag }, true, trigger });
821     }
822     return ret;
823 }
824 
HidePanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,PanelFlag flag,Trigger trigger)825 int32_t InputMethodAbility::HidePanel(
826     const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger)
827 {
828     if (inputMethodPanel == nullptr) {
829         return ErrorCode::ERROR_BAD_PARAMETERS;
830     }
831     auto ret = inputMethodPanel->HidePanel();
832     if (ret == ErrorCode::NO_ERROR) {
833         NotifyPanelStatusInfo({ { inputMethodPanel->GetPanelType(), flag }, false, trigger });
834     }
835     return ret;
836 }
837 
HideKeyboard(Trigger trigger)838 int32_t InputMethodAbility::HideKeyboard(Trigger trigger)
839 {
840     if (imeListener_ == nullptr) {
841         IMSA_HILOGE("imeListener_ is nullptr");
842         return ErrorCode::ERROR_IME;
843     }
844     IMSA_HILOGD("IMA, trigger: %{public}d", static_cast<int32_t>(trigger));
845     if (panels_.Contains(SOFT_KEYBOARD)) {
846         auto panel = GetSoftKeyboardPanel();
847         if (panel == nullptr) {
848             IMSA_HILOGE("panel is nullptr.");
849             return ErrorCode::ERROR_IME;
850         }
851         auto flag = panel->GetPanelFlag();
852         imeListener_->OnKeyboardStatus(false);
853         if (flag == FLG_CANDIDATE_COLUMN) {
854             IMSA_HILOGI("panel flag is candidate, no need to hide.");
855             return ErrorCode::NO_ERROR;
856         }
857         return HidePanel(panel, flag, trigger);
858     }
859     IMSA_HILOGI("panel not create");
860     imeListener_->OnKeyboardStatus(false);
861     auto channel = GetInputDataChannelProxy();
862     if (channel != nullptr) {
863         channel->SendKeyboardStatus(KeyboardStatus::HIDE);
864     }
865     auto controlChannel = GetInputControlChannel();
866     if (controlChannel != nullptr && trigger == Trigger::IME_APP) {
867         controlChannel->HideKeyboardSelf();
868     }
869     return ErrorCode::NO_ERROR;
870 }
871 
GetSoftKeyboardPanel()872 std::shared_ptr<InputMethodPanel> InputMethodAbility::GetSoftKeyboardPanel()
873 {
874     auto result = panels_.Find(SOFT_KEYBOARD);
875     if (!result.first) {
876         return nullptr;
877     }
878     auto panel = result.second;
879     if (!BlockRetry(FIND_PANEL_RETRY_INTERVAL, MAX_RETRY_TIMES, [panel]() -> bool {
880             return panel != nullptr && panel->windowId_ != InputMethodPanel::INVALID_WINDOW_ID;
881         })) {
882         return nullptr;
883     }
884     return panel;
885 }
886 
IsCurrentIme()887 bool InputMethodAbility::IsCurrentIme()
888 {
889     IMSA_HILOGD("InputMethodAbility, in");
890     if (isCurrentIme_) {
891         return true;
892     }
893     std::lock_guard<std::mutex> lock(imeCheckMutex_);
894     if (isCurrentIme_) {
895         return true;
896     }
897     auto proxy = GetImsaProxy();
898     if (proxy == nullptr) {
899         IMSA_HILOGE("failed to get imsa proxy");
900         return false;
901     }
902     if (proxy->IsCurrentIme()) {
903         isCurrentIme_ = true;
904         return true;
905     }
906     return false;
907 }
908 
IsEnable()909 bool InputMethodAbility::IsEnable()
910 {
911     if (imeListener_ == nullptr) {
912         return false;
913     }
914     return imeListener_->IsEnable();
915 }
916 
ExitCurrentInputType()917 int32_t InputMethodAbility::ExitCurrentInputType()
918 {
919     IMSA_HILOGD("InputMethodAbility, in");
920     auto proxy = GetImsaProxy();
921     if (proxy == nullptr) {
922         IMSA_HILOGE("failed to get imsa proxy");
923         return false;
924     }
925     return proxy->ExitCurrentInputType();
926 }
927 
IsPanelShown(const PanelInfo & panelInfo,bool & isShown)928 int32_t InputMethodAbility::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
929 {
930     isShown = false;
931     auto result = panels_.Find(panelInfo.panelType);
932     if (!result.first) {
933         IMSA_HILOGI("panel type: %{public}d not found", static_cast<int32_t>(panelInfo.panelType));
934         return ErrorCode::NO_ERROR;
935     }
936     auto panel = result.second;
937     if (panel->GetPanelType() == PanelType::SOFT_KEYBOARD && panel->GetPanelFlag() != panelInfo.panelFlag) {
938         IMSA_HILOGI("queried flag: %{public}d, current flag: %{public}d, panel not found",
939             static_cast<int32_t>(panelInfo.panelFlag), static_cast<int32_t>(panel->GetPanelFlag()));
940         return ErrorCode::NO_ERROR;
941     }
942     isShown = panel->IsShowing();
943     IMSA_HILOGI("type: %{public}d, flag: %{public}d, result: %{public}d", static_cast<int32_t>(panelInfo.panelType),
944         static_cast<int32_t>(panelInfo.panelFlag), isShown);
945     return ErrorCode::NO_ERROR;
946 }
947 
OnClientInactive(const sptr<IRemoteObject> & channel)948 void InputMethodAbility::OnClientInactive(const sptr<IRemoteObject> &channel)
949 {
950     IMSA_HILOGI("client inactive");
951     ClearDataChannel(channel);
952     panels_.ForEach([](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
953         if (panelType != PanelType::SOFT_KEYBOARD || panel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
954             panel->HidePanel();
955         }
956         return false;
957     });
958 }
959 
OnTextConfigChange(const InputClientInfo & clientInfo)960 int32_t InputMethodAbility::OnTextConfigChange(const InputClientInfo &clientInfo)
961 {
962     if (clientInfo.channel != nullptr) {
963         SetInputDataChannel(clientInfo.channel->AsObject());
964     }
965     InvokeTextChangeCallback(clientInfo.config);
966     return clientInfo.isShowKeyboard ? ShowKeyboard() : ErrorCode::NO_ERROR;
967 }
968 
NotifyKeyboardHeight(const std::shared_ptr<InputMethodPanel> inputMethodPanel)969 void InputMethodAbility::NotifyKeyboardHeight(const std::shared_ptr<InputMethodPanel> inputMethodPanel)
970 {
971     if (inputMethodPanel == nullptr) {
972         IMSA_HILOGE("inputMethodPanel is nullptr");
973         return;
974     }
975     if (inputMethodPanel->GetPanelType() != PanelType::SOFT_KEYBOARD) {
976         IMSA_HILOGW("current panel is not soft keyboard");
977         return;
978     }
979     auto channel = GetInputDataChannelProxy();
980     if (channel == nullptr) {
981         IMSA_HILOGE("channel is nullptr");
982         return;
983     }
984     if (inputMethodPanel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
985         channel->NotifyKeyboardHeight(0);
986         return;
987     }
988     channel->NotifyKeyboardHeight(inputMethodPanel->GetHeight());
989 }
990 } // namespace MiscServices
991 } // namespace OHOS
992