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_stub.h"
24 #include "input_method_core_stub.h"
25 #include "input_method_system_ability_proxy.h"
26 #include "input_method_utils.h"
27 #include "inputmethod_sysevent.h"
28 #include "inputmethod_trace.h"
29 #include "iservice_registry.h"
30 #include "itypes_util.h"
31 #include "message_parcel.h"
32 #include "string_ex.h"
33 #include "sys/prctl.h"
34 #include "system_ability_definition.h"
35 
36 namespace OHOS {
37 namespace MiscServices {
38 class MessageHandler;
39 using namespace MessageID;
40 sptr<InputMethodAbility> InputMethodAbility::instance_;
41 std::mutex InputMethodAbility::instanceLock_;
42 constexpr double INVALID_CURSOR_VALUE = -1.0;
43 constexpr int32_t INVALID_SELECTION_VALUE = -1;
44 constexpr uint32_t FIND_PANEL_RETRY_INTERVAL = 10;
45 constexpr uint32_t MAX_RETRY_TIMES = 100;
InputMethodAbility()46 InputMethodAbility::InputMethodAbility() : msgHandler_(nullptr), stop_(false)
47 {
48 }
49 
~InputMethodAbility()50 InputMethodAbility::~InputMethodAbility()
51 {
52     IMSA_HILOGI("InputMethodAbility::~InputMethodAbility.");
53     QuitWorkThread();
54     if (msgHandler_ != nullptr) {
55         delete msgHandler_;
56         msgHandler_ = nullptr;
57     }
58 }
59 
GetInstance()60 sptr<InputMethodAbility> InputMethodAbility::GetInstance()
61 {
62     if (instance_ == nullptr) {
63         std::lock_guard<std::mutex> autoLock(instanceLock_);
64         if (instance_ == nullptr) {
65             IMSA_HILOGI("InputMethodAbility need new IMA.");
66             instance_ = new (std::nothrow) InputMethodAbility();
67             if (instance_ == nullptr) {
68                 IMSA_HILOGE("instance is nullptr!");
69                 return instance_;
70             }
71             instance_->Initialize();
72         }
73     }
74     return instance_;
75 }
76 
GetImsaProxy()77 sptr<IInputMethodSystemAbility> InputMethodAbility::GetImsaProxy()
78 {
79     std::lock_guard<std::mutex> lock(abilityLock_);
80     if (abilityManager_ != nullptr) {
81         return abilityManager_;
82     }
83     IMSA_HILOGI("InputMethodAbility get imsa proxy.");
84     sptr<ISystemAbilityManager> systemAbilityManager =
85         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
86     if (systemAbilityManager == nullptr) {
87         IMSA_HILOGE("systemAbilityManager is nullptr!");
88         return nullptr;
89     }
90     auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, "");
91     if (systemAbility == nullptr) {
92         IMSA_HILOGE("systemAbility is nullptr!");
93         return nullptr;
94     }
95     if (deathRecipient_ == nullptr) {
96         deathRecipient_ = new (std::nothrow) InputDeathRecipient();
97         if (deathRecipient_ == nullptr) {
98             IMSA_HILOGE("failed to new death recipient!");
99             return nullptr;
100         }
101     }
102     deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) { OnRemoteSaDied(remote); });
103     if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
104         IMSA_HILOGE("failed to add death recipient!");
105         return nullptr;
106     }
107     abilityManager_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
108     return abilityManager_;
109 }
110 
SetCoreAndAgentAsync()111 void InputMethodAbility::SetCoreAndAgentAsync()
112 {
113     if (msgHandler_ == nullptr) {
114         IMSA_HILOGE("msgHandler_ is nullptr");
115         SetCoreAndAgent();
116         return;
117     }
118     Message *msg = new Message(MessageID::MSG_ID_SET_COREANDANGENT, nullptr);
119     msgHandler_->SendMessage(msg);
120 }
121 
SetCoreAndAgent()122 int32_t InputMethodAbility::SetCoreAndAgent()
123 {
124     IMSA_HILOGD("InputMethodAbility, start.");
125     if (isBound_.load()) {
126         IMSA_HILOGD("already bound.");
127         return ErrorCode::NO_ERROR;
128     }
129     auto proxy = GetImsaProxy();
130     if (proxy == nullptr) {
131         IMSA_HILOGE("imsa proxy is nullptr!");
132         return ErrorCode::ERROR_NULL_POINTER;
133     }
134     int32_t ret = proxy->SetCoreAndAgent(coreStub_, agentStub_->AsObject());
135     if (ret != ErrorCode::NO_ERROR) {
136         IMSA_HILOGE("set failed, ret: %{public}d!", ret);
137         return ret;
138     }
139     isBound_.store(true);
140     IMSA_HILOGD("set successfully.");
141     return ErrorCode::NO_ERROR;
142 }
143 
InitConnect()144 int32_t InputMethodAbility::InitConnect()
145 {
146     IMSA_HILOGD("InputMethodAbility, init connect.");
147     auto proxy = GetImsaProxy();
148     if (proxy == nullptr) {
149         IMSA_HILOGE("imsa proxy is nullptr!");
150         return ErrorCode::ERROR_NULL_POINTER;
151     }
152     int32_t ret = proxy->InitConnect();
153     if (ret != ErrorCode::NO_ERROR) {
154         IMSA_HILOGE("set failed, ret: %{public}d!", ret);
155         return ret;
156     }
157     return ErrorCode::NO_ERROR;
158 }
159 
UnRegisteredProxyIme(UnRegisteredType type)160 int32_t InputMethodAbility::UnRegisteredProxyIme(UnRegisteredType type)
161 {
162     isBound_.store(false);
163     auto proxy = GetImsaProxy();
164     if (proxy == nullptr) {
165         IMSA_HILOGE("imsa proxy is nullptr!");
166         return ErrorCode::ERROR_NULL_POINTER;
167     }
168     return proxy->UnRegisteredProxyIme(type, coreStub_);
169 }
170 
Initialize()171 void InputMethodAbility::Initialize()
172 {
173     IMSA_HILOGD("IMA init.");
174     sptr<InputMethodCoreStub> coreStub = new (std::nothrow) InputMethodCoreStub();
175     if (coreStub == nullptr) {
176         IMSA_HILOGE("failed to create core!");
177         return;
178     }
179     sptr<InputMethodAgentStub> agentStub = new (std::nothrow) InputMethodAgentStub();
180     if (agentStub == nullptr) {
181         IMSA_HILOGE("failed to create agent!");
182         return;
183     }
184     msgHandler_ = new (std::nothrow) MessageHandler();
185     if (msgHandler_ == nullptr) {
186         IMSA_HILOGE("failed to create message handler!");
187         return;
188     }
189     coreStub->SetMessageHandler(msgHandler_);
190     agentStub->SetMessageHandler(msgHandler_);
191     agentStub_ = agentStub;
192     coreStub_ = coreStub;
193     workThreadHandler = std::thread([this] { this->WorkThread(); });
194 }
195 
SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)196 void InputMethodAbility::SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)
197 {
198     IMSA_HILOGD("InputMethodAbility start.");
199     if (imeListener_ == nullptr) {
200         imeListener_ = std::move(imeListener);
201     }
202 }
203 
GetImeListener()204 std::shared_ptr<InputMethodEngineListener> InputMethodAbility::GetImeListener()
205 {
206     return imeListener_;
207 }
208 
SetKdListener(std::shared_ptr<KeyboardListener> kdListener)209 void InputMethodAbility::SetKdListener(std::shared_ptr<KeyboardListener> kdListener)
210 {
211     IMSA_HILOGD("InputMethodAbility start.");
212     if (kdListener_ == nullptr) {
213         kdListener_ = std::move(kdListener);
214     }
215 }
216 
WorkThread()217 void InputMethodAbility::WorkThread()
218 {
219     prctl(PR_SET_NAME, "OS_IMAWorkThread start.");
220     while (!stop_) {
221         Message *msg = msgHandler_->GetMessage();
222         switch (msg->msgId_) {
223             case MSG_ID_INIT_INPUT_CONTROL_CHANNEL: {
224                 OnInitInputControlChannel(msg);
225                 break;
226             }
227             case MSG_ID_ON_CURSOR_UPDATE: {
228                 OnCursorUpdate(msg);
229                 break;
230             }
231             case MSG_ID_ON_SELECTION_CHANGE: {
232                 OnSelectionChange(msg);
233                 break;
234             }
235             case MSG_ID_ON_ATTRIBUTE_CHANGE: {
236                 OnAttributeChange(msg);
237                 break;
238             }
239             case MSG_ID_SET_SUBTYPE: {
240                 OnSetSubtype(msg);
241                 break;
242             }
243             case MSG_ID_SET_COREANDANGENT: {
244                 SetCoreAndAgent();
245                 break;
246             }
247             default: {
248                 IMSA_HILOGD("the message is %{public}d.", msg->msgId_);
249                 break;
250             }
251         }
252         delete msg;
253         msg = nullptr;
254     }
255 }
256 
OnInitInputControlChannel(Message * msg)257 void InputMethodAbility::OnInitInputControlChannel(Message *msg)
258 {
259     IMSA_HILOGD("InputMethodAbility::OnInitInputControlChannel start.");
260     MessageParcel *data = msg->msgContent_;
261     sptr<IRemoteObject> channelObject = data->ReadRemoteObject();
262     if (channelObject == nullptr) {
263         IMSA_HILOGE("channelObject is nullptr!");
264         return;
265     }
266     SetInputControlChannel(channelObject);
267 }
268 
StartInput(const InputClientInfo & clientInfo,bool isBindFromClient)269 int32_t InputMethodAbility::StartInput(const InputClientInfo &clientInfo, bool isBindFromClient)
270 {
271     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
272     int32_t cmdCount = ++cmdId_;
273     if (clientInfo.channel == nullptr) {
274         IMSA_HILOGE("channelObject is nullptr!");
275         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
276     }
277     IMSA_HILOGI("IMA isShowKeyboard: %{public}d, isBindFromClient: %{public}d.", clientInfo.isShowKeyboard,
278         isBindFromClient);
279     SetInputDataChannel(clientInfo.channel);
280     if (clientInfo.needHide) {
281         IMSA_HILOGD("pwd or normal input pattern changed, need hide panel first.");
282         auto panel = GetSoftKeyboardPanel();
283         if (panel != nullptr) {
284             panel->HidePanel();
285         }
286     }
287     {
288         std::lock_guard<std::mutex> lock(inputAttrLock_);
289         inputAttribute_.bundleName = clientInfo.config.inputAttribute.bundleName;
290     }
291     int32_t ret = isBindFromClient ? InvokeStartInputCallback(clientInfo.config, clientInfo.isNotifyInputStart)
292                                    : InvokeStartInputCallback(clientInfo.isNotifyInputStart);
293     if (ret != ErrorCode::NO_ERROR) {
294         IMSA_HILOGE("failed to invoke callback, ret: %{public}d!", ret);
295         return ret;
296     }
297     isPendingShowKeyboard_ = clientInfo.isShowKeyboard;
298     if (clientInfo.isShowKeyboard) {
299         auto task = [this, cmdCount]() {
300             std::thread([this, cmdCount]() { ShowKeyboardImplWithLock(cmdCount); }).detach();
301         };
302         if (imeListener_ == nullptr || !imeListener_->PostTaskToEventHandler(task, "ShowKeyboard")) {
303             IMSA_HILOGE("imeListener_ is nullptr, or post task failed!");
304             ShowKeyboardImplWithoutLock(cmdCount);
305         }
306         isImeTerminating_.store(false);
307     }
308     return ErrorCode::NO_ERROR;
309 }
310 
OnSetSubtype(Message * msg)311 void InputMethodAbility::OnSetSubtype(Message *msg)
312 {
313     auto data = msg->msgContent_;
314     SubProperty subProperty;
315     if (!ITypesUtil::Unmarshal(*data, subProperty)) {
316         IMSA_HILOGE("read message parcel failed!");
317         return;
318     }
319     if (imeListener_ == nullptr) {
320         IMSA_HILOGE("imeListener_ is nullptr!");
321         return;
322     }
323     imeListener_->OnSetSubtype(subProperty);
324 }
325 
ClearDataChannel(const sptr<IRemoteObject> & channel)326 void InputMethodAbility::ClearDataChannel(const sptr<IRemoteObject> &channel)
327 {
328     std::lock_guard<std::mutex> lock(dataChannelLock_);
329     if (dataChannelObject_ == nullptr || channel == nullptr) {
330         IMSA_HILOGD("dataChannelObject_ already nullptr.");
331         return;
332     }
333     if (dataChannelObject_.GetRefPtr() == channel.GetRefPtr()) {
334         dataChannelObject_ = nullptr;
335         dataChannelProxy_ = nullptr;
336         IMSA_HILOGD("end.");
337     }
338 }
339 
StopInput(const sptr<IRemoteObject> & channelObject)340 int32_t InputMethodAbility::StopInput(const sptr<IRemoteObject> &channelObject)
341 {
342     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
343     int32_t cmdCount = ++cmdId_;
344     IMSA_HILOGI("IMA");
345     HideKeyboardImplWithoutLock(cmdCount);
346     ClearDataChannel(channelObject);
347     ClearInputAttribute();
348     if (imeListener_ != nullptr) {
349         imeListener_->OnInputFinish();
350     }
351     return ErrorCode::NO_ERROR;
352 }
353 
DispatchKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,sptr<KeyEventConsumerProxy> & consumer)354 int32_t InputMethodAbility::DispatchKeyEvent(
355     const std::shared_ptr<MMI::KeyEvent> &keyEvent, sptr<KeyEventConsumerProxy> &consumer)
356 {
357     if (keyEvent == nullptr) {
358         IMSA_HILOGE("keyEvent is nullptr!");
359         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
360     }
361     if (kdListener_ == nullptr) {
362         IMSA_HILOGE("kdListener_ is nullptr!");
363         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
364     }
365     IMSA_HILOGD("InputMethodAbility, start.");
366 
367     if (!kdListener_->OnDealKeyEvent(keyEvent, consumer)) {
368         IMSA_HILOGE("keyEvent not deal!");
369         return ErrorCode::ERROR_DISPATCH_KEY_EVENT;
370     }
371     return ErrorCode::NO_ERROR;
372 }
373 
SetCallingWindow(uint32_t windowId)374 void InputMethodAbility::SetCallingWindow(uint32_t windowId)
375 {
376     IMSA_HILOGD("InputMethodAbility windowId: %{public}d.", windowId);
377     panels_.ForEach([windowId](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
378         panel->SetCallingWindow(windowId);
379         return false;
380     });
381     if (imeListener_ == nullptr) {
382         IMSA_HILOGD("imeListener_ is nullptr!");
383         return;
384     }
385     imeListener_->OnSetCallingWindow(windowId);
386 }
387 
OnCursorUpdate(Message * msg)388 void InputMethodAbility::OnCursorUpdate(Message *msg)
389 {
390     MessageParcel *data = msg->msgContent_;
391     int32_t positionX = data->ReadInt32();
392     int32_t positionY = data->ReadInt32();
393     int32_t height = data->ReadInt32();
394     if (kdListener_ == nullptr) {
395         IMSA_HILOGE("kdListener_ is nullptr!");
396         return;
397     }
398     IMSA_HILOGD("x: %{public}d, y: %{public}d, height: %{public}d.", positionX, positionY, height);
399     kdListener_->OnCursorUpdate(positionX, positionY, height);
400 }
401 
OnSelectionChange(Message * msg)402 void InputMethodAbility::OnSelectionChange(Message *msg)
403 {
404     MessageParcel *data = msg->msgContent_;
405     std::string text = Str16ToStr8(data->ReadString16());
406     int32_t oldBegin = data->ReadInt32();
407     int32_t oldEnd = data->ReadInt32();
408     int32_t newBegin = data->ReadInt32();
409     int32_t newEnd = data->ReadInt32();
410 
411     if (kdListener_ == nullptr) {
412         IMSA_HILOGE("kdListener_ is nullptr!");
413         return;
414     }
415     kdListener_->OnTextChange(text);
416     kdListener_->OnSelectionChange(oldBegin, oldEnd, newBegin, newEnd);
417 }
418 
OnAttributeChange(Message * msg)419 void InputMethodAbility::OnAttributeChange(Message *msg)
420 {
421     if (kdListener_ == nullptr || msg == nullptr) {
422         IMSA_HILOGE("kdListener_ or msg is nullptr!");
423         return;
424     }
425     MessageParcel *data = msg->msgContent_;
426     InputAttribute attribute;
427     if (!ITypesUtil::Unmarshal(*data, attribute)) {
428         IMSA_HILOGE("failed to read attribute!");
429         return;
430     }
431     IMSA_HILOGD("enterKeyType: %{public}d, inputPattern: %{public}d.", attribute.enterKeyType,
432         attribute.inputPattern);
433     attribute.bundleName = GetInputAttribute().bundleName;
434     SetInputAttribute(attribute);
435     // add for mod inputPattern when panel show
436     auto panel = GetSoftKeyboardPanel();
437     if (panel != nullptr) {
438         auto keyboardSize = panel->GetKeyboardSize();
439         SysPanelStatus sysPanelStatus = { false, panel->GetPanelFlag(), keyboardSize.width, keyboardSize.height };
440         NotifyPanelStatus(panel, sysPanelStatus);
441     }
442     kdListener_->OnEditorAttributeChange(attribute);
443 }
444 
OnStopInputService(bool isTerminateIme)445 int32_t InputMethodAbility::OnStopInputService(bool isTerminateIme)
446 {
447     IMSA_HILOGI("isTerminateIme: %{public}d.", isTerminateIme);
448     isBound_.store(false);
449     auto imeListener = GetImeListener();
450     if (imeListener == nullptr) {
451         return ErrorCode::ERROR_IME_NOT_STARTED;
452     }
453     if (isTerminateIme) {
454         isImeTerminating_.store(true);
455         return imeListener->OnInputStop();
456     }
457     return ErrorCode::NO_ERROR;
458 }
459 
HideKeyboard()460 int32_t InputMethodAbility::HideKeyboard()
461 {
462     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
463     int32_t cmdCount = ++cmdId_;
464     return HideKeyboardImplWithoutLock(cmdCount);
465 }
466 
HideKeyboardImplWithoutLock(int32_t cmdId)467 int32_t InputMethodAbility::HideKeyboardImplWithoutLock(int32_t cmdId)
468 {
469     if (cmdId != cmdId_) {
470         IMSA_HILOGE("current is not last cmd cur: %{public}d, cmdId_: %{public}d!", cmdId, cmdId_);
471         return ErrorCode::NO_ERROR;
472     }
473     return HideKeyboard(Trigger::IMF);
474 }
475 
ShowKeyboard()476 int32_t InputMethodAbility::ShowKeyboard()
477 {
478     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
479     int32_t cmdCount = ++cmdId_;
480     return ShowKeyboardImplWithoutLock(cmdCount);
481 }
482 
ShowKeyboardImplWithLock(int32_t cmdId)483 int32_t InputMethodAbility::ShowKeyboardImplWithLock(int32_t cmdId)
484 {
485     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
486     return ShowKeyboardImplWithoutLock(cmdId);
487 }
488 
ShowKeyboardImplWithoutLock(int32_t cmdId)489 int32_t InputMethodAbility::ShowKeyboardImplWithoutLock(int32_t cmdId)
490 {
491     if (cmdId != cmdId_) {
492         IMSA_HILOGE("current is not last cmd cur: %{public}d, cmdId_: %{public}d!", cmdId, cmdId_);
493         return ErrorCode::NO_ERROR;
494     }
495     if (imeListener_ == nullptr) {
496         IMSA_HILOGE("imeListener is nullptr!");
497         return ErrorCode::ERROR_IME;
498     }
499     IMSA_HILOGI("IMA start.");
500     if (panels_.Contains(SOFT_KEYBOARD)) {
501         auto panel = GetSoftKeyboardPanel();
502         if (panel == nullptr) {
503             IMSA_HILOGE("panel is nullptr!");
504             return ErrorCode::ERROR_IME;
505         }
506         auto flag = panel->GetPanelFlag();
507         imeListener_->OnKeyboardStatus(true);
508         if (flag == FLG_CANDIDATE_COLUMN) {
509             IMSA_HILOGI("panel flag is candidate, no need to show.");
510             NotifyKeyboardHeight(0, flag);
511             return ErrorCode::NO_ERROR;
512         }
513         return ShowPanel(panel, flag, Trigger::IMF);
514     }
515     IMSA_HILOGI("panel not create.");
516     auto channel = GetInputDataChannelProxy();
517     if (channel != nullptr) {
518         channel->SendKeyboardStatus(KeyboardStatus::SHOW);
519     }
520     imeListener_->OnKeyboardStatus(true);
521     return ErrorCode::NO_ERROR;
522 }
523 
NotifyPanelStatusInfo(const PanelStatusInfo & info)524 void InputMethodAbility::NotifyPanelStatusInfo(const PanelStatusInfo &info)
525 {
526     // CANDIDATE_COLUMN not notify
527     auto channel = GetInputDataChannelProxy();
528     NotifyPanelStatusInfo(info, channel);
529 }
530 
InvokeStartInputCallback(bool isNotifyInputStart)531 int32_t InputMethodAbility::InvokeStartInputCallback(bool isNotifyInputStart)
532 {
533     TextTotalConfig textConfig = {};
534     int32_t ret = GetTextConfig(textConfig);
535     if (ret == ErrorCode::NO_ERROR) {
536         textConfig.inputAttribute.bundleName = GetInputAttribute().bundleName;
537         return InvokeStartInputCallback(textConfig, isNotifyInputStart);
538     }
539     IMSA_HILOGW("failed to get text config, ret: %{public}d.", ret);
540     if (imeListener_ == nullptr) {
541         IMSA_HILOGE("imeListener_ is nullptr!");
542         return ErrorCode::ERROR_IME;
543     }
544     if (isNotifyInputStart) {
545         imeListener_->OnInputStart();
546     }
547     return ErrorCode::NO_ERROR;
548 }
549 
InvokeStartInputCallback(const TextTotalConfig & textConfig,bool isNotifyInputStart)550 int32_t InputMethodAbility::InvokeStartInputCallback(const TextTotalConfig &textConfig, bool isNotifyInputStart)
551 {
552     if (imeListener_ == nullptr) {
553         IMSA_HILOGE("imeListener_ is nullptr!");
554         return ErrorCode::ERROR_IME;
555     }
556     positionY_ = textConfig.positionY;
557     height_ = textConfig.height;
558     SetInputAttribute(textConfig.inputAttribute);
559     if (kdListener_ != nullptr) {
560         kdListener_->OnEditorAttributeChange(textConfig.inputAttribute);
561     }
562     if (TextConfig::IsPrivateCommandValid(textConfig.privateCommand) && IsDefaultIme()) {
563         IMSA_HILOGI("notify privateCommand.");
564         imeListener_->ReceivePrivateCommand(textConfig.privateCommand);
565     }
566     if (isNotifyInputStart) {
567         imeListener_->OnInputStart();
568     }
569     if (kdListener_ != nullptr) {
570         if (textConfig.cursorInfo.left != INVALID_CURSOR_VALUE) {
571             kdListener_->OnCursorUpdate(
572                 textConfig.cursorInfo.left, textConfig.cursorInfo.top, textConfig.cursorInfo.height);
573         }
574         if (textConfig.textSelection.newBegin == INVALID_SELECTION_VALUE
575             || (textConfig.textSelection.newBegin == textConfig.textSelection.oldBegin
576                 && textConfig.textSelection.newEnd == textConfig.textSelection.oldEnd)) {
577             IMSA_HILOGD("invalid selection or no selection change");
578         } else {
579             kdListener_->OnSelectionChange(textConfig.textSelection.oldBegin, textConfig.textSelection.oldEnd,
580                 textConfig.textSelection.newBegin, textConfig.textSelection.newEnd);
581         }
582     }
583     auto task = [this, textConfig]() {
584         panels_.ForEach([&textConfig](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
585             panel->SetCallingWindow(textConfig.windowId);
586             return false;
587         });
588     };
589     imeListener_->PostTaskToEventHandler(task, "SetCallingWindow");
590     if (textConfig.windowId != INVALID_WINDOW_ID) {
591         imeListener_->OnSetCallingWindow(textConfig.windowId);
592     }
593     return ErrorCode::NO_ERROR;
594 }
595 
InsertText(const std::string text)596 int32_t InputMethodAbility::InsertText(const std::string text)
597 {
598     InputMethodSyncTrace tracer("IMA_InsertText");
599     IMSA_HILOGD("InputMethodAbility start.");
600     auto channel = GetInputDataChannelProxy();
601     if (channel == nullptr) {
602         IMSA_HILOGE("channel is nullptr!");
603         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
604     }
605     return channel->InsertText(Str8ToStr16(text));
606 }
607 
DeleteForward(int32_t length)608 int32_t InputMethodAbility::DeleteForward(int32_t length)
609 {
610     InputMethodSyncTrace tracer("IMA_DeleteForward");
611     IMSA_HILOGD("InputMethodAbility start, length: %{public}d.", length);
612     auto channel = GetInputDataChannelProxy();
613     if (channel == nullptr) {
614         IMSA_HILOGE("channel is nullptr!");
615         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
616     }
617     return channel->DeleteForward(length);
618 }
619 
DeleteBackward(int32_t length)620 int32_t InputMethodAbility::DeleteBackward(int32_t length)
621 {
622     IMSA_HILOGD("InputMethodAbility start, length: %{public}d.", length);
623     auto channel = GetInputDataChannelProxy();
624     if (channel == nullptr) {
625         IMSA_HILOGE("channel is nullptr!");
626         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
627     }
628     return channel->DeleteBackward(length);
629 }
630 
SendFunctionKey(int32_t funcKey)631 int32_t InputMethodAbility::SendFunctionKey(int32_t funcKey)
632 {
633     auto channel = GetInputDataChannelProxy();
634     if (channel == nullptr) {
635         IMSA_HILOGE("channel is nullptr!");
636         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
637     }
638     return channel->SendFunctionKey(funcKey);
639 }
640 
HideKeyboardSelf()641 int32_t InputMethodAbility::HideKeyboardSelf()
642 {
643     // Current Ime is exiting, hide softkeyboard will cause the TextFiled to lose focus.
644     if (isImeTerminating_.load()) {
645         IMSA_HILOGI("Current Ime is terminating, no need to hide keyboard.");
646         return ErrorCode::NO_ERROR;
647     }
648     InputMethodSyncTrace tracer("IMA_HideKeyboardSelf start.");
649     auto ret = HideKeyboard(Trigger::IME_APP);
650     if (ret == ErrorCode::NO_ERROR) {
651         InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_SELF);
652     }
653     return ret == ErrorCode::ERROR_CLIENT_NULL_POINTER ? ret : ErrorCode::NO_ERROR;
654 }
655 
SendExtendAction(int32_t action)656 int32_t InputMethodAbility::SendExtendAction(int32_t action)
657 {
658     IMSA_HILOGD("InputMethodAbility, action: %{public}d.", action);
659     auto channel = GetInputDataChannelProxy();
660     if (channel == nullptr) {
661         IMSA_HILOGE("channel is nullptr!");
662         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
663     }
664     return channel->HandleExtendAction(action);
665 }
666 
GetTextBeforeCursor(int32_t number,std::u16string & text)667 int32_t InputMethodAbility::GetTextBeforeCursor(int32_t number, std::u16string &text)
668 {
669     InputMethodSyncTrace tracer("IMA_GetForward");
670     IMSA_HILOGD("InputMethodAbility, number: %{public}d.", number);
671     auto channel = GetInputDataChannelProxy();
672     if (channel == nullptr) {
673         IMSA_HILOGE("channel is nullptr!");
674         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
675     }
676     return channel->GetTextBeforeCursor(number, text);
677 }
678 
GetTextAfterCursor(int32_t number,std::u16string & text)679 int32_t InputMethodAbility::GetTextAfterCursor(int32_t number, std::u16string &text)
680 {
681     InputMethodSyncTrace tracer("IMA_GetTextAfterCursor");
682     IMSA_HILOGD("InputMethodAbility, number: %{public}d.", number);
683     auto channel = GetInputDataChannelProxy();
684     if (channel == nullptr) {
685         IMSA_HILOGE("channel is nullptr!");
686         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
687     }
688     return channel->GetTextAfterCursor(number, text);
689 }
690 
MoveCursor(int32_t keyCode)691 int32_t InputMethodAbility::MoveCursor(int32_t keyCode)
692 {
693     IMSA_HILOGD("InputMethodAbility, keyCode: %{public}d.", keyCode);
694     auto channel = GetInputDataChannelProxy();
695     if (channel == nullptr) {
696         IMSA_HILOGE("channel is nullptr!");
697         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
698     }
699     return channel->MoveCursor(keyCode);
700 }
701 
SelectByRange(int32_t start,int32_t end)702 int32_t InputMethodAbility::SelectByRange(int32_t start, int32_t end)
703 {
704     IMSA_HILOGD("InputMethodAbility, start: %{public}d, end: %{public}d", start, end);
705     if (start < 0 || end < 0) {
706         IMSA_HILOGE("check parameter failed, start: %{public}d, end: %{public}d!", start, end);
707         return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
708     }
709     auto dataChannel = GetInputDataChannelProxy();
710     if (dataChannel == nullptr) {
711         IMSA_HILOGE("datachannel is nullptr!");
712         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
713     }
714     return dataChannel->SelectByRange(start, end);
715 }
716 
SelectByMovement(int32_t direction)717 int32_t InputMethodAbility::SelectByMovement(int32_t direction)
718 {
719     IMSA_HILOGD("InputMethodAbility, direction: %{public}d.", direction);
720     auto dataChannel = GetInputDataChannelProxy();
721     if (dataChannel == nullptr) {
722         IMSA_HILOGE("datachannel is nullptr!");
723         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
724     }
725     return dataChannel->SelectByMovement(direction, 0);
726 }
727 
GetEnterKeyType(int32_t & keyType)728 int32_t InputMethodAbility::GetEnterKeyType(int32_t &keyType)
729 {
730     IMSA_HILOGD("InputMethodAbility start.");
731     auto channel = GetInputDataChannelProxy();
732     if (channel == nullptr) {
733         IMSA_HILOGE("channel is nullptr!");
734         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
735     }
736     return channel->GetEnterKeyType(keyType);
737 }
738 
GetInputPattern(int32_t & inputPattern)739 int32_t InputMethodAbility::GetInputPattern(int32_t &inputPattern)
740 {
741     IMSA_HILOGD("InputMethodAbility start.");
742     auto channel = GetInputDataChannelProxy();
743     if (channel == nullptr) {
744         IMSA_HILOGE("channel is nullptr!");
745         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
746     }
747     return channel->GetInputPattern(inputPattern);
748 }
749 
GetTextIndexAtCursor(int32_t & index)750 int32_t InputMethodAbility::GetTextIndexAtCursor(int32_t &index)
751 {
752     IMSA_HILOGD("InputMethodAbility start.");
753     auto channel = GetInputDataChannelProxy();
754     if (channel == nullptr) {
755         IMSA_HILOGE("channel is nullptr!");
756         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
757     }
758     return channel->GetTextIndexAtCursor(index);
759 }
760 
GetTextConfig(TextTotalConfig & textConfig)761 int32_t InputMethodAbility::GetTextConfig(TextTotalConfig &textConfig)
762 {
763     IMSA_HILOGD("InputMethodAbility start.");
764     auto channel = GetInputDataChannelProxy();
765     if (channel == nullptr) {
766         IMSA_HILOGE("channel is nullptr!");
767         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
768     }
769     auto ret = channel->GetTextConfig(textConfig);
770     if (ret == ErrorCode::NO_ERROR) {
771         textConfig.inputAttribute.bundleName = GetInputAttribute().bundleName;
772     }
773     return ret;
774 }
775 
SetInputDataChannel(const sptr<IRemoteObject> & object)776 void InputMethodAbility::SetInputDataChannel(const sptr<IRemoteObject> &object)
777 {
778     IMSA_HILOGD("SetInputDataChannel start.");
779     std::lock_guard<std::mutex> lock(dataChannelLock_);
780     auto channelProxy = std::make_shared<InputDataChannelProxy>(object);
781     if (channelProxy == nullptr) {
782         IMSA_HILOGE("failed to create channel proxy!");
783         return;
784     }
785     dataChannelObject_ = object;
786     dataChannelProxy_ = channelProxy;
787 }
788 
GetInputDataChannelProxy()789 std::shared_ptr<InputDataChannelProxy> InputMethodAbility::GetInputDataChannelProxy()
790 {
791     std::lock_guard<std::mutex> lock(dataChannelLock_);
792     return dataChannelProxy_;
793 }
794 
SetInputControlChannel(sptr<IRemoteObject> & object)795 void InputMethodAbility::SetInputControlChannel(sptr<IRemoteObject> &object)
796 {
797     IMSA_HILOGD("SetInputControlChannel start.");
798     std::lock_guard<std::mutex> lock(controlChannelLock_);
799     std::shared_ptr<InputControlChannelProxy> channelProxy = std::make_shared<InputControlChannelProxy>(object);
800     if (channelProxy == nullptr) {
801         IMSA_HILOGD("channelProxy is nullptr!");
802         return;
803     }
804     controlChannel_ = channelProxy;
805 }
806 
ClearInputControlChannel()807 void InputMethodAbility::ClearInputControlChannel()
808 {
809     std::lock_guard<std::mutex> lock(controlChannelLock_);
810     controlChannel_ = nullptr;
811 }
812 
GetInputControlChannel()813 std::shared_ptr<InputControlChannelProxy> InputMethodAbility::GetInputControlChannel()
814 {
815     std::lock_guard<std::mutex> lock(controlChannelLock_);
816     return controlChannel_;
817 }
818 
OnRemoteSaDied(const wptr<IRemoteObject> & object)819 void InputMethodAbility::OnRemoteSaDied(const wptr<IRemoteObject> &object)
820 {
821     IMSA_HILOGI("input method service died.");
822     isBound_.store(false);
823     ClearInputControlChannel();
824     ClearSystemCmdChannel();
825     {
826         std::lock_guard<std::mutex> lock(abilityLock_);
827         abilityManager_ = nullptr;
828     }
829     if (imeListener_ != nullptr) {
830         imeListener_->OnInputStop();
831     }
832 }
833 
QuitWorkThread()834 void InputMethodAbility::QuitWorkThread()
835 {
836     stop_ = true;
837     Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
838     msgHandler_->SendMessage(msg);
839     if (workThreadHandler.joinable()) {
840         workThreadHandler.join();
841     }
842 }
843 
GetSecurityMode(int32_t & security)844 int32_t InputMethodAbility::GetSecurityMode(int32_t &security)
845 {
846     IMSA_HILOGI("InputMethodAbility start.");
847     auto proxy = GetImsaProxy();
848     if (proxy == nullptr) {
849         IMSA_HILOGE("failed to get imsa proxy!");
850         return false;
851     }
852     return proxy->GetSecurityMode(security);
853 }
854 
ClearSystemCmdChannel()855 void InputMethodAbility::ClearSystemCmdChannel()
856 {
857     std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
858     if (systemCmdChannelProxy_ == nullptr) {
859         IMSA_HILOGD("systemCmdChannelProxy_ already nullptr.");
860         return;
861     }
862     systemCmdChannelProxy_ = nullptr;
863     IMSA_HILOGD("end.");
864 }
865 
GetSystemCmdChannelProxy()866 sptr<SystemCmdChannelProxy> InputMethodAbility::GetSystemCmdChannelProxy()
867 {
868     std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
869     return systemCmdChannelProxy_;
870 }
871 
OnConnectSystemCmd(const sptr<IRemoteObject> & channel,sptr<IRemoteObject> & agent)872 int32_t InputMethodAbility::OnConnectSystemCmd(const sptr<IRemoteObject> &channel, sptr<IRemoteObject> &agent)
873 {
874     IMSA_HILOGD("InputMethodAbility start.");
875     std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
876     systemCmdChannelProxy_ = new (std::nothrow) SystemCmdChannelProxy(channel);
877     if (systemCmdChannelProxy_ == nullptr) {
878         IMSA_HILOGE("failed to create channel proxy!");
879         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
880     }
881     systemAgentStub_ = new (std::nothrow) InputMethodAgentStub();
882     if (systemAgentStub_ == nullptr) {
883         IMSA_HILOGE("failed to create agent!");
884         systemCmdChannelProxy_ = nullptr;
885         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
886     }
887     agent = systemAgentStub_->AsObject();
888     return ErrorCode::NO_ERROR;
889 }
890 
OnSecurityChange(int32_t security)891 int32_t InputMethodAbility::OnSecurityChange(int32_t security)
892 {
893     IMSA_HILOGI("InputMethodAbility start.");
894     if (imeListener_ == nullptr) {
895         IMSA_HILOGE("imeListener_ is nullptr!");
896         return ErrorCode::ERROR_BAD_PARAMETERS;
897     }
898     imeListener_->OnSecurityChange(security);
899     return ErrorCode::NO_ERROR;
900 }
901 
CreatePanel(const std::shared_ptr<AbilityRuntime::Context> & context,const PanelInfo & panelInfo,std::shared_ptr<InputMethodPanel> & inputMethodPanel)902 int32_t InputMethodAbility::CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context,
903     const PanelInfo &panelInfo, std::shared_ptr<InputMethodPanel> &inputMethodPanel)
904 {
905     IMSA_HILOGI("InputMethodAbility start.");
906     auto panelHeightCallback = [this](uint32_t panelHeight, PanelFlag panelFlag) {
907         NotifyKeyboardHeight(panelHeight, panelFlag);
908     };
909     auto flag = panels_.ComputeIfAbsent(
910         panelInfo.panelType, [panelHeightCallback, &panelInfo, &context, &inputMethodPanel](
911                                  const PanelType &panelType, std::shared_ptr<InputMethodPanel> &panel) {
912             inputMethodPanel = std::make_shared<InputMethodPanel>();
913             inputMethodPanel->SetPanelHeightCallback(panelHeightCallback);
914             auto ret = inputMethodPanel->CreatePanel(context, panelInfo);
915             if (ret == ErrorCode::NO_ERROR) {
916                 panel = inputMethodPanel;
917                 return true;
918             }
919             inputMethodPanel = nullptr;
920             return false;
921         });
922     // Called when creating the input method first time, if the CreatePanel is called later than the ShowKeyboard.
923     if (panelInfo.panelType == SOFT_KEYBOARD && isPendingShowKeyboard_) {
924         ShowKeyboard();
925         isPendingShowKeyboard_ = false;
926     }
927     return flag ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
928 }
929 
DestroyPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)930 int32_t InputMethodAbility::DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
931 {
932     IMSA_HILOGI("InputMethodAbility start.");
933     if (inputMethodPanel == nullptr) {
934         IMSA_HILOGE("panel is nullptr!");
935         return ErrorCode::ERROR_BAD_PARAMETERS;
936     }
937     auto ret = inputMethodPanel->DestroyPanel();
938     if (ret == ErrorCode::NO_ERROR) {
939         PanelType panelType = inputMethodPanel->GetPanelType();
940         panels_.Erase(panelType);
941     }
942     return ret;
943 }
944 
ShowPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)945 int32_t InputMethodAbility::ShowPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
946 {
947     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
948     if (inputMethodPanel == nullptr) {
949         return ErrorCode::ERROR_BAD_PARAMETERS;
950     }
951     return ShowPanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
952 }
953 
HidePanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)954 int32_t InputMethodAbility::HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
955 {
956     if (inputMethodPanel == nullptr) {
957         return ErrorCode::ERROR_BAD_PARAMETERS;
958     }
959 
960     // Current Ime is exiting, hide softkeyboard will cause the TextFiled to lose focus.
961     if (isImeTerminating_.load() && inputMethodPanel->GetPanelType() == PanelType::SOFT_KEYBOARD) {
962         IMSA_HILOGI("Current Ime is terminating, no need to hide keyboard.");
963         return ErrorCode::NO_ERROR;
964     }
965 
966     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
967     return HidePanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
968 }
969 
ShowPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,PanelFlag flag,Trigger trigger)970 int32_t InputMethodAbility::ShowPanel(
971     const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger)
972 {
973     if (inputMethodPanel == nullptr) {
974         return ErrorCode::ERROR_BAD_PARAMETERS;
975     }
976     if (trigger == Trigger::IME_APP && GetInputDataChannelProxy() == nullptr) {
977         IMSA_HILOGE("channel is nullptr!");
978         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
979     }
980     if (flag == FLG_FIXED && inputMethodPanel->GetPanelType() == SOFT_KEYBOARD) {
981         auto ret = inputMethodPanel->SetTextFieldAvoidInfo(positionY_, height_);
982         if (ret != ErrorCode::NO_ERROR) {
983             IMSA_HILOGE("failed to set keyBoard, ret: %{public}d!", ret);
984         }
985     }
986     auto keyboardSize = inputMethodPanel->GetKeyboardSize();
987     SysPanelStatus sysPanelStatus = { false, flag, keyboardSize.width, keyboardSize.height };
988     NotifyPanelStatus(inputMethodPanel, sysPanelStatus);
989     auto ret = inputMethodPanel->ShowPanel();
990     if (ret == ErrorCode::NO_ERROR) {
991         NotifyPanelStatusInfo({ { inputMethodPanel->GetPanelType(), flag }, true, trigger });
992     }
993     return ret;
994 }
995 
HidePanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,PanelFlag flag,Trigger trigger)996 int32_t InputMethodAbility::HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag,
997                                       Trigger trigger)
998 {
999     if (inputMethodPanel == nullptr) {
1000         return ErrorCode::ERROR_BAD_PARAMETERS;
1001     }
1002     auto ret = inputMethodPanel->HidePanel();
1003     if (ret != ErrorCode::NO_ERROR) {
1004         IMSA_HILOGD("failed, ret: %{public}d", ret);
1005         return ret;
1006     }
1007     NotifyPanelStatusInfo({ { inputMethodPanel->GetPanelType(), flag }, false, trigger });
1008     return ErrorCode::NO_ERROR;
1009 }
1010 
NotifyPanelStatus(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,SysPanelStatus & sysPanelStatus)1011 int32_t InputMethodAbility::NotifyPanelStatus(
1012     const std::shared_ptr<InputMethodPanel> &inputMethodPanel, SysPanelStatus &sysPanelStatus)
1013 {
1014     if (inputMethodPanel->GetPanelType() != SOFT_KEYBOARD) {
1015         return ErrorCode::NO_ERROR;
1016     }
1017     // If it is not binding, do not need to notify the panel
1018     auto channel = GetInputDataChannelProxy();
1019     if (channel == nullptr) {
1020         return ErrorCode::NO_ERROR;
1021     }
1022     bool isSecurity = GetInputAttribute().GetSecurityFlag();
1023     sysPanelStatus.isSecurity = isSecurity;
1024     auto systemChannel = GetSystemCmdChannelProxy();
1025     if (systemChannel == nullptr) {
1026         IMSA_HILOGE("channel is nullptr!");
1027         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
1028     }
1029     return systemChannel->NotifyPanelStatus(sysPanelStatus);
1030 }
1031 
SetInputAttribute(const InputAttribute & inputAttribute)1032 void InputMethodAbility::SetInputAttribute(const InputAttribute &inputAttribute)
1033 {
1034     std::lock_guard<std::mutex> lock(inputAttrLock_);
1035     inputAttribute_ = inputAttribute;
1036 }
1037 
ClearInputAttribute()1038 void InputMethodAbility::ClearInputAttribute()
1039 {
1040     std::lock_guard<std::mutex> lock(inputAttrLock_);
1041     inputAttribute_ = {};
1042 }
1043 
GetInputAttribute()1044 InputAttribute InputMethodAbility::GetInputAttribute()
1045 {
1046     std::lock_guard<std::mutex> lock(inputAttrLock_);
1047     return inputAttribute_;
1048 }
1049 
HideKeyboard(Trigger trigger)1050 int32_t InputMethodAbility::HideKeyboard(Trigger trigger)
1051 {
1052     InputMethodSyncTrace tracer("IMA_HideKeyboard");
1053     if (imeListener_ == nullptr) {
1054         IMSA_HILOGE("imeListener_ is nullptr!");
1055         return ErrorCode::ERROR_IME;
1056     }
1057     IMSA_HILOGD("IMA, trigger: %{public}d.", static_cast<int32_t>(trigger));
1058     if (panels_.Contains(SOFT_KEYBOARD)) {
1059         auto panel = GetSoftKeyboardPanel();
1060         if (panel == nullptr) {
1061             IMSA_HILOGE("panel is nullptr!");
1062             return ErrorCode::ERROR_IME;
1063         }
1064         auto flag = panel->GetPanelFlag();
1065         imeListener_->OnKeyboardStatus(false);
1066         if (flag == FLG_CANDIDATE_COLUMN) {
1067             IMSA_HILOGI("panel flag is candidate, no need to hide.");
1068             return ErrorCode::NO_ERROR;
1069         }
1070         return HidePanel(panel, flag, trigger);
1071     }
1072     IMSA_HILOGI("panel is not created.");
1073     imeListener_->OnKeyboardStatus(false);
1074     auto channel = GetInputDataChannelProxy();
1075     if (channel != nullptr) {
1076         channel->SendKeyboardStatus(KeyboardStatus::HIDE);
1077     }
1078     auto controlChannel = GetInputControlChannel();
1079     if (controlChannel != nullptr && trigger == Trigger::IME_APP) {
1080         controlChannel->HideKeyboardSelf();
1081     }
1082     return ErrorCode::NO_ERROR;
1083 }
1084 
GetSoftKeyboardPanel()1085 std::shared_ptr<InputMethodPanel> InputMethodAbility::GetSoftKeyboardPanel()
1086 {
1087     auto result = panels_.Find(SOFT_KEYBOARD);
1088     if (!result.first) {
1089         return nullptr;
1090     }
1091     auto panel = result.second;
1092     if (!BlockRetry(FIND_PANEL_RETRY_INTERVAL, MAX_RETRY_TIMES, [panel]() -> bool {
1093             return panel != nullptr && panel->windowId_ != InputMethodPanel::INVALID_WINDOW_ID;
1094         })) {
1095         return nullptr;
1096     }
1097     return panel;
1098 }
1099 
IsCurrentIme()1100 bool InputMethodAbility::IsCurrentIme()
1101 {
1102     IMSA_HILOGD("InputMethodAbility start.");
1103     if (isCurrentIme_) {
1104         return true;
1105     }
1106     std::lock_guard<std::mutex> lock(imeCheckMutex_);
1107     if (isCurrentIme_) {
1108         return true;
1109     }
1110     auto proxy = GetImsaProxy();
1111     if (proxy == nullptr) {
1112         IMSA_HILOGE("failed to get imsa proxy!");
1113         return false;
1114     }
1115     if (proxy->IsCurrentIme()) {
1116         isCurrentIme_ = true;
1117         return true;
1118     }
1119     return false;
1120 }
1121 
IsDefaultIme()1122 bool InputMethodAbility::IsDefaultIme()
1123 {
1124     IMSA_HILOGD("InputMethodAbility start");
1125     if (isDefaultIme_) {
1126         return true;
1127     }
1128     std::lock_guard<std::mutex> lock(defaultImeCheckMutex_);
1129     if (isDefaultIme_) {
1130         return true;
1131     }
1132     auto proxy = GetImsaProxy();
1133     if (proxy == nullptr) {
1134         IMSA_HILOGE("failed to get imsa proxy!");
1135         return false;
1136     }
1137     auto ret = proxy->IsDefaultIme();
1138     if (ret == ErrorCode::NO_ERROR) {
1139         isDefaultIme_ = true;
1140         return true;
1141     }
1142     IMSA_HILOGE("call IsDefaultIme failed, ret: %{public}d!", ret);
1143     return false;
1144 }
1145 
IsEnable()1146 bool InputMethodAbility::IsEnable()
1147 {
1148     if (imeListener_ == nullptr) {
1149         return false;
1150     }
1151     return imeListener_->IsEnable();
1152 }
1153 
ExitCurrentInputType()1154 int32_t InputMethodAbility::ExitCurrentInputType()
1155 {
1156     IMSA_HILOGD("InputMethodAbility start.");
1157     auto proxy = GetImsaProxy();
1158     if (proxy == nullptr) {
1159         IMSA_HILOGE("failed to get imsa proxy!");
1160         return false;
1161     }
1162     return proxy->ExitCurrentInputType();
1163 }
1164 
IsPanelShown(const PanelInfo & panelInfo,bool & isShown)1165 int32_t InputMethodAbility::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
1166 {
1167     isShown = false;
1168     auto result = panels_.Find(panelInfo.panelType);
1169     if (!result.first) {
1170         IMSA_HILOGI("panel type: %{public}d not found.", static_cast<int32_t>(panelInfo.panelType));
1171         return ErrorCode::NO_ERROR;
1172     }
1173     auto panel = result.second;
1174     if (panel->GetPanelType() == PanelType::SOFT_KEYBOARD && panel->GetPanelFlag() != panelInfo.panelFlag) {
1175         IMSA_HILOGI("queried flag: %{public}d, current flag: %{public}d, panel not found.",
1176             static_cast<int32_t>(panelInfo.panelFlag), static_cast<int32_t>(panel->GetPanelFlag()));
1177         return ErrorCode::NO_ERROR;
1178     }
1179     isShown = panel->IsShowing();
1180     IMSA_HILOGI("type: %{public}d, flag: %{public}d, result: %{public}d.", static_cast<int32_t>(panelInfo.panelType),
1181         static_cast<int32_t>(panelInfo.panelFlag), isShown);
1182     return ErrorCode::NO_ERROR;
1183 }
1184 
OnClientInactive(const sptr<IRemoteObject> & channel)1185 void InputMethodAbility::OnClientInactive(const sptr<IRemoteObject> &channel)
1186 {
1187     IMSA_HILOGI("client inactive.");
1188     if (imeListener_ != nullptr) {
1189         imeListener_->OnInputFinish();
1190     }
1191     auto channelProxy = std::make_shared<InputDataChannelProxy>(channel);
1192     if (channelProxy == nullptr) {
1193         IMSA_HILOGE("failed to create channel proxy!");
1194         return;
1195     }
1196     auto panel = GetSoftKeyboardPanel();
1197     if (imeListener_ != nullptr && panel != nullptr && panel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
1198         imeListener_->OnKeyboardStatus(false);
1199     }
1200     panels_.ForEach([this, &channelProxy](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
1201         if (panelType != PanelType::SOFT_KEYBOARD || panel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
1202             auto ret = panel->HidePanel();
1203             if (ret != ErrorCode::NO_ERROR) {
1204                 IMSA_HILOGE("failed, ret: %{public}d", ret);
1205                 return false;
1206             }
1207             NotifyPanelStatusInfo({ { panel->GetPanelType(), panel->GetPanelFlag() }, false, Trigger::IME_APP },
1208                 channelProxy);
1209             // finish previewing text when soft keyboard hides
1210             if (panel->GetPanelType() == PanelType::SOFT_KEYBOARD) {
1211                 FinishTextPreview(true);
1212             }
1213         }
1214         return false;
1215     });
1216     ClearDataChannel(channel);
1217 }
1218 
NotifyKeyboardHeight(uint32_t panelHeight,PanelFlag panelFlag)1219 void InputMethodAbility::NotifyKeyboardHeight(uint32_t panelHeight, PanelFlag panelFlag)
1220 {
1221     auto channel = GetInputDataChannelProxy();
1222     if (channel == nullptr) {
1223         IMSA_HILOGE("channel is nullptr!");
1224         return;
1225     }
1226     IMSA_HILOGD("notify panel height: %{public}u, flag: %{public}d.", panelHeight, static_cast<int32_t>(panelFlag));
1227     if (panelFlag != PanelFlag::FLG_FIXED) {
1228         channel->NotifyKeyboardHeight(0);
1229         return;
1230     }
1231     channel->NotifyKeyboardHeight(panelHeight);
1232 }
1233 
SendPrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)1234 int32_t InputMethodAbility::SendPrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
1235 {
1236     if (!IsDefaultIme()) {
1237         IMSA_HILOGE("current is not default ime.");
1238         return ErrorCode::ERROR_NOT_DEFAULT_IME;
1239     }
1240     if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
1241         IMSA_HILOGE("privateCommand is limit 32KB, count limit 5!");
1242         return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
1243     }
1244     if (TextConfig::IsSystemPrivateCommand(privateCommand)) {
1245         auto systemChannel = GetSystemCmdChannelProxy();
1246         if (systemChannel == nullptr) {
1247             IMSA_HILOGE("channel is nullptr!");
1248             return ErrorCode::ERROR_SYSTEM_CMD_CHANNEL_ERROR;
1249         }
1250         return systemChannel->SendPrivateCommand(privateCommand);
1251     } else {
1252         auto channel = GetInputDataChannelProxy();
1253         if (channel == nullptr) {
1254             IMSA_HILOGE("channel is nullptr!");
1255             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
1256         }
1257         return channel->SendPrivateCommand(privateCommand);
1258     }
1259 }
1260 
ReceivePrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)1261 int32_t InputMethodAbility::ReceivePrivateCommand(
1262     const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
1263 {
1264     if (!IsDefaultIme()) {
1265         IMSA_HILOGE("current is not default ime!");
1266         return ErrorCode::ERROR_NOT_DEFAULT_IME;
1267     }
1268     if (imeListener_ == nullptr) {
1269         IMSA_HILOGE("imeListener is nullptr!");
1270         return ErrorCode::ERROR_IME;
1271     }
1272     imeListener_->ReceivePrivateCommand(privateCommand);
1273     return ErrorCode::NO_ERROR;
1274 }
1275 
SetPreviewText(const std::string & text,const Range & range)1276 int32_t InputMethodAbility::SetPreviewText(const std::string &text, const Range &range)
1277 {
1278     InputMethodSyncTrace tracer("IMA_SetPreviewText");
1279     auto dataChannel = GetInputDataChannelProxy();
1280     if (dataChannel == nullptr) {
1281         IMSA_HILOGE("dataChannel is nullptr!");
1282         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
1283     }
1284     return dataChannel->SetPreviewText(text, range);
1285 }
1286 
FinishTextPreview(bool isAsync)1287 int32_t InputMethodAbility::FinishTextPreview(bool isAsync)
1288 {
1289     InputMethodSyncTrace tracer("IMA_FinishTextPreview");
1290     auto dataChannel = GetInputDataChannelProxy();
1291     if (dataChannel == nullptr) {
1292         IMSA_HILOGE("dataChannel is nullptr!");
1293         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
1294     }
1295     return dataChannel->FinishTextPreview(isAsync);
1296 }
1297 
GetCallingWindowInfo(CallingWindowInfo & windowInfo)1298 int32_t InputMethodAbility::GetCallingWindowInfo(CallingWindowInfo &windowInfo)
1299 {
1300     IMSA_HILOGD("IMA start.");
1301     auto channel = GetInputDataChannelProxy();
1302     if (channel == nullptr) {
1303         IMSA_HILOGE("channel is nullptr!");
1304         return ErrorCode::ERROR_CLIENT_NOT_FOUND;
1305     }
1306     auto panel = GetSoftKeyboardPanel();
1307     if (panel == nullptr) {
1308         IMSA_HILOGE("panel not found!");
1309         return ErrorCode::ERROR_PANEL_NOT_FOUND;
1310     }
1311     TextTotalConfig textConfig;
1312     int32_t ret = GetTextConfig(textConfig);
1313     if (ret != ErrorCode::NO_ERROR) {
1314         IMSA_HILOGE("failed to get window id, ret: %{public}d!", ret);
1315         return ErrorCode::ERROR_GET_TEXT_CONFIG;
1316     }
1317     ret = panel->SetCallingWindow(textConfig.windowId);
1318     if (ret != ErrorCode::NO_ERROR) {
1319         IMSA_HILOGE("failed to set calling window, ret: %{public}d!", ret);
1320         return ret;
1321     }
1322     ret = panel->GetCallingWindowInfo(windowInfo);
1323     if (ret != ErrorCode::NO_ERROR) {
1324         IMSA_HILOGE("failed to get calling window, ret: %{public}d", ret);
1325     }
1326     return ret;
1327 }
1328 
NotifyPanelStatusInfo(const PanelStatusInfo & info,std::shared_ptr<InputDataChannelProxy> & channelProxy)1329 void InputMethodAbility::NotifyPanelStatusInfo(
1330     const PanelStatusInfo &info, std::shared_ptr<InputDataChannelProxy> &channelProxy)
1331 {
1332     // CANDIDATE_COLUMN not notify
1333     if (info.panelInfo.panelFlag == PanelFlag::FLG_CANDIDATE_COLUMN) {
1334         return;
1335     }
1336     if (channelProxy != nullptr) {
1337         channelProxy->NotifyPanelStatusInfo(info);
1338     }
1339 
1340     auto controlChannel = GetInputControlChannel();
1341     if (controlChannel != nullptr && info.trigger == Trigger::IME_APP && !info.visible) {
1342         controlChannel->HideKeyboardSelf();
1343     }
1344 }
1345 } // namespace MiscServices
1346 } // namespace OHOS
1347