• 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_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     int32_t ret = isBindFromClient ? InvokeStartInputCallback(clientInfo.config, clientInfo.isNotifyInputStart)
288                                    : InvokeStartInputCallback(clientInfo.isNotifyInputStart);
289     if (ret != ErrorCode::NO_ERROR) {
290         IMSA_HILOGE("failed to invoke callback, ret: %{public}d!", ret);
291         return ret;
292     }
293     isPendingShowKeyboard_ = clientInfo.isShowKeyboard;
294     if (clientInfo.isShowKeyboard) {
295         auto task = [this, cmdCount]() {
296             std::thread([this, cmdCount]() { ShowKeyboardImplWithLock(cmdCount); }).detach();
297         };
298         if (imeListener_ == nullptr || !imeListener_->PostTaskToEventHandler(task, "ShowKeyboard")) {
299             IMSA_HILOGE("imeListener_ is nullptr, or post task failed!");
300             ShowKeyboardImplWithoutLock(cmdCount);
301         }
302         isImeTerminating_.store(false);
303     }
304     return ErrorCode::NO_ERROR;
305 }
306 
OnSetSubtype(Message * msg)307 void InputMethodAbility::OnSetSubtype(Message *msg)
308 {
309     auto data = msg->msgContent_;
310     SubProperty subProperty;
311     if (!ITypesUtil::Unmarshal(*data, subProperty)) {
312         IMSA_HILOGE("read message parcel failed!");
313         return;
314     }
315     if (imeListener_ == nullptr) {
316         IMSA_HILOGE("imeListener_ is nullptr!");
317         return;
318     }
319     imeListener_->OnSetSubtype(subProperty);
320 }
321 
ClearDataChannel(const sptr<IRemoteObject> & channel)322 void InputMethodAbility::ClearDataChannel(const sptr<IRemoteObject> &channel)
323 {
324     std::lock_guard<std::mutex> lock(dataChannelLock_);
325     if (dataChannelObject_ == nullptr || channel == nullptr) {
326         IMSA_HILOGD("dataChannelObject_ already nullptr.");
327         return;
328     }
329     if (dataChannelObject_.GetRefPtr() == channel.GetRefPtr()) {
330         dataChannelObject_ = nullptr;
331         dataChannelProxy_ = nullptr;
332         IMSA_HILOGD("end.");
333     }
334 }
335 
StopInput(const sptr<IRemoteObject> & channelObject)336 int32_t InputMethodAbility::StopInput(const sptr<IRemoteObject> &channelObject)
337 {
338     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
339     int32_t cmdCount = ++cmdId_;
340     IMSA_HILOGI("IMA");
341     HideKeyboardImplWithoutLock(cmdCount);
342     ClearDataChannel(channelObject);
343     ClearInputAttribute();
344     if (imeListener_ != nullptr) {
345         imeListener_->OnInputFinish();
346     }
347     return ErrorCode::NO_ERROR;
348 }
349 
DispatchKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,sptr<KeyEventConsumerProxy> & consumer)350 int32_t InputMethodAbility::DispatchKeyEvent(
351     const std::shared_ptr<MMI::KeyEvent> &keyEvent, sptr<KeyEventConsumerProxy> &consumer)
352 {
353     if (keyEvent == nullptr) {
354         IMSA_HILOGE("keyEvent is nullptr!");
355         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
356     }
357     if (kdListener_ == nullptr) {
358         IMSA_HILOGE("kdListener_ is nullptr!");
359         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
360     }
361     IMSA_HILOGD("InputMethodAbility, start.");
362 
363     if (!kdListener_->OnDealKeyEvent(keyEvent, consumer)) {
364         IMSA_HILOGE("keyEvent not deal!");
365         return ErrorCode::ERROR_DISPATCH_KEY_EVENT;
366     }
367     return ErrorCode::NO_ERROR;
368 }
369 
SetCallingWindow(uint32_t windowId)370 void InputMethodAbility::SetCallingWindow(uint32_t windowId)
371 {
372     IMSA_HILOGD("InputMethodAbility windowId: %{public}d.", windowId);
373     panels_.ForEach([windowId](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
374         panel->SetCallingWindow(windowId);
375         return false;
376     });
377     if (imeListener_ == nullptr) {
378         IMSA_HILOGD("imeListener_ is nullptr!");
379         return;
380     }
381     imeListener_->OnSetCallingWindow(windowId);
382 }
383 
OnCursorUpdate(Message * msg)384 void InputMethodAbility::OnCursorUpdate(Message *msg)
385 {
386     MessageParcel *data = msg->msgContent_;
387     int32_t positionX = data->ReadInt32();
388     int32_t positionY = data->ReadInt32();
389     int32_t height = data->ReadInt32();
390     if (kdListener_ == nullptr) {
391         IMSA_HILOGE("kdListener_ is nullptr!");
392         return;
393     }
394     IMSA_HILOGD("x: %{public}d, y: %{public}d, height: %{public}d.", positionX, positionY, height);
395     kdListener_->OnCursorUpdate(positionX, positionY, height);
396 }
397 
OnSelectionChange(Message * msg)398 void InputMethodAbility::OnSelectionChange(Message *msg)
399 {
400     MessageParcel *data = msg->msgContent_;
401     std::string text = Str16ToStr8(data->ReadString16());
402     int32_t oldBegin = data->ReadInt32();
403     int32_t oldEnd = data->ReadInt32();
404     int32_t newBegin = data->ReadInt32();
405     int32_t newEnd = data->ReadInt32();
406 
407     if (kdListener_ == nullptr) {
408         IMSA_HILOGE("kdListener_ is nullptr!");
409         return;
410     }
411     kdListener_->OnTextChange(text);
412     kdListener_->OnSelectionChange(oldBegin, oldEnd, newBegin, newEnd);
413 }
414 
OnAttributeChange(Message * msg)415 void InputMethodAbility::OnAttributeChange(Message *msg)
416 {
417     if (kdListener_ == nullptr || msg == nullptr) {
418         IMSA_HILOGE("kdListener_ or msg is nullptr!");
419         return;
420     }
421     MessageParcel *data = msg->msgContent_;
422     InputAttribute attribute;
423     if (!ITypesUtil::Unmarshal(*data, attribute)) {
424         IMSA_HILOGE("failed to read attribute!");
425         return;
426     }
427     IMSA_HILOGD("enterKeyType: %{public}d, inputPattern: %{public}d.", attribute.enterKeyType,
428         attribute.inputPattern);
429     SetInputAttribute(attribute);
430     // add for mod inputPattern when panel show
431     auto panel = GetSoftKeyboardPanel();
432     if (panel != nullptr) {
433         auto keyboardSize = panel->GetKeyboardSize();
434         SysPanelStatus sysPanelStatus = { false, panel->GetPanelFlag(), keyboardSize.width, keyboardSize.height };
435         NotifyPanelStatus(panel, sysPanelStatus);
436     }
437     kdListener_->OnEditorAttributeChange(attribute);
438 }
439 
OnStopInputService(bool isTerminateIme)440 int32_t InputMethodAbility::OnStopInputService(bool isTerminateIme)
441 {
442     IMSA_HILOGI("isTerminateIme: %{public}d.", isTerminateIme);
443     isBound_.store(false);
444     auto imeListener = GetImeListener();
445     if (imeListener == nullptr) {
446         return ErrorCode::ERROR_IME_NOT_STARTED;
447     }
448     if (isTerminateIme) {
449         isImeTerminating_.store(true);
450         return imeListener->OnInputStop();
451     }
452     return ErrorCode::NO_ERROR;
453 }
454 
HideKeyboard()455 int32_t InputMethodAbility::HideKeyboard()
456 {
457     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
458     int32_t cmdCount = ++cmdId_;
459     return HideKeyboardImplWithoutLock(cmdCount);
460 }
461 
HideKeyboardImplWithoutLock(int32_t cmdId)462 int32_t InputMethodAbility::HideKeyboardImplWithoutLock(int32_t cmdId)
463 {
464     if (cmdId != cmdId_) {
465         IMSA_HILOGE("current is not last cmd cur: %{public}d, cmdId_: %{public}d!", cmdId, cmdId_);
466         return ErrorCode::NO_ERROR;
467     }
468     return HideKeyboard(Trigger::IMF);
469 }
470 
ShowKeyboard()471 int32_t InputMethodAbility::ShowKeyboard()
472 {
473     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
474     int32_t cmdCount = ++cmdId_;
475     return ShowKeyboardImplWithoutLock(cmdCount);
476 }
477 
ShowKeyboardImplWithLock(int32_t cmdId)478 int32_t InputMethodAbility::ShowKeyboardImplWithLock(int32_t cmdId)
479 {
480     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
481     return ShowKeyboardImplWithoutLock(cmdId);
482 }
483 
ShowKeyboardImplWithoutLock(int32_t cmdId)484 int32_t InputMethodAbility::ShowKeyboardImplWithoutLock(int32_t cmdId)
485 {
486     if (cmdId != cmdId_) {
487         IMSA_HILOGE("current is not last cmd cur: %{public}d, cmdId_: %{public}d!", cmdId, cmdId_);
488         return ErrorCode::NO_ERROR;
489     }
490     if (imeListener_ == nullptr) {
491         IMSA_HILOGE("imeListener is nullptr!");
492         return ErrorCode::ERROR_IME;
493     }
494     IMSA_HILOGI("IMA start.");
495     if (panels_.Contains(SOFT_KEYBOARD)) {
496         auto panel = GetSoftKeyboardPanel();
497         if (panel == nullptr) {
498             IMSA_HILOGE("panel is nullptr!");
499             return ErrorCode::ERROR_IME;
500         }
501         auto flag = panel->GetPanelFlag();
502         imeListener_->OnKeyboardStatus(true);
503         if (flag == FLG_CANDIDATE_COLUMN) {
504             IMSA_HILOGI("panel flag is candidate, no need to show.");
505             NotifyKeyboardHeight(0, flag);
506             return ErrorCode::NO_ERROR;
507         }
508         return ShowPanel(panel, flag, Trigger::IMF);
509     }
510     IMSA_HILOGI("panel not create.");
511     auto channel = GetInputDataChannelProxy();
512     if (channel != nullptr) {
513         channel->SendKeyboardStatus(KeyboardStatus::SHOW);
514     }
515     imeListener_->OnKeyboardStatus(true);
516     return ErrorCode::NO_ERROR;
517 }
518 
NotifyPanelStatusInfo(const PanelStatusInfo & info)519 void InputMethodAbility::NotifyPanelStatusInfo(const PanelStatusInfo &info)
520 {
521     // CANDIDATE_COLUMN not notify
522     auto channel = GetInputDataChannelProxy();
523     NotifyPanelStatusInfo(info, channel);
524 }
525 
InvokeStartInputCallback(bool isNotifyInputStart)526 int32_t InputMethodAbility::InvokeStartInputCallback(bool isNotifyInputStart)
527 {
528     TextTotalConfig textConfig = {};
529     int32_t ret = GetTextConfig(textConfig);
530     if (ret == ErrorCode::NO_ERROR) {
531         return InvokeStartInputCallback(textConfig, isNotifyInputStart);
532     }
533     IMSA_HILOGW("failed to get text config, ret: %{public}d.", ret);
534     if (imeListener_ == nullptr) {
535         IMSA_HILOGE("imeListener_ is nullptr!");
536         return ErrorCode::ERROR_IME;
537     }
538     if (isNotifyInputStart) {
539         imeListener_->OnInputStart();
540     }
541     return ErrorCode::NO_ERROR;
542 }
543 
InvokeStartInputCallback(const TextTotalConfig & textConfig,bool isNotifyInputStart)544 int32_t InputMethodAbility::InvokeStartInputCallback(const TextTotalConfig &textConfig, bool isNotifyInputStart)
545 {
546     if (imeListener_ == nullptr) {
547         IMSA_HILOGE("imeListener_ is nullptr!");
548         return ErrorCode::ERROR_IME;
549     }
550     positionY_ = textConfig.positionY;
551     height_ = textConfig.height;
552     SetInputAttribute(textConfig.inputAttribute);
553     if (kdListener_ != nullptr) {
554         kdListener_->OnEditorAttributeChange(textConfig.inputAttribute);
555     }
556     if (TextConfig::IsPrivateCommandValid(textConfig.privateCommand) && IsDefaultIme()) {
557         IMSA_HILOGI("notify privateCommand.");
558         imeListener_->ReceivePrivateCommand(textConfig.privateCommand);
559     }
560     if (isNotifyInputStart) {
561         imeListener_->OnInputStart();
562     }
563     if (kdListener_ != nullptr) {
564         if (textConfig.cursorInfo.left != INVALID_CURSOR_VALUE) {
565             kdListener_->OnCursorUpdate(
566                 textConfig.cursorInfo.left, textConfig.cursorInfo.top, textConfig.cursorInfo.height);
567         }
568         if (textConfig.textSelection.newBegin == INVALID_SELECTION_VALUE
569             || (textConfig.textSelection.newBegin == textConfig.textSelection.oldBegin
570                 && textConfig.textSelection.newEnd == textConfig.textSelection.oldEnd)) {
571             IMSA_HILOGD("invalid selection or no selection change");
572         } else {
573             kdListener_->OnSelectionChange(textConfig.textSelection.oldBegin, textConfig.textSelection.oldEnd,
574                 textConfig.textSelection.newBegin, textConfig.textSelection.newEnd);
575         }
576     }
577     auto task = [this, textConfig]() {
578         panels_.ForEach([&textConfig](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
579             panel->SetCallingWindow(textConfig.windowId);
580             return false;
581         });
582     };
583     imeListener_->PostTaskToEventHandler(task, "SetCallingWindow");
584     if (textConfig.windowId != INVALID_WINDOW_ID) {
585         imeListener_->OnSetCallingWindow(textConfig.windowId);
586     }
587     return ErrorCode::NO_ERROR;
588 }
589 
InsertText(const std::string text)590 int32_t InputMethodAbility::InsertText(const std::string text)
591 {
592     InputMethodSyncTrace tracer("IMA_InsertText");
593     IMSA_HILOGD("InputMethodAbility start.");
594     auto channel = GetInputDataChannelProxy();
595     if (channel == nullptr) {
596         IMSA_HILOGE("channel is nullptr!");
597         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
598     }
599     return channel->InsertText(Str8ToStr16(text));
600 }
601 
DeleteForward(int32_t length)602 int32_t InputMethodAbility::DeleteForward(int32_t length)
603 {
604     InputMethodSyncTrace tracer("IMA_DeleteForward");
605     IMSA_HILOGD("InputMethodAbility start, length: %{public}d.", length);
606     auto channel = GetInputDataChannelProxy();
607     if (channel == nullptr) {
608         IMSA_HILOGE("channel is nullptr!");
609         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
610     }
611     return channel->DeleteForward(length);
612 }
613 
DeleteBackward(int32_t length)614 int32_t InputMethodAbility::DeleteBackward(int32_t length)
615 {
616     IMSA_HILOGD("InputMethodAbility start, length: %{public}d.", length);
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->DeleteBackward(length);
623 }
624 
SendFunctionKey(int32_t funcKey)625 int32_t InputMethodAbility::SendFunctionKey(int32_t funcKey)
626 {
627     auto channel = GetInputDataChannelProxy();
628     if (channel == nullptr) {
629         IMSA_HILOGE("channel is nullptr!");
630         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
631     }
632     return channel->SendFunctionKey(funcKey);
633 }
634 
HideKeyboardSelf()635 int32_t InputMethodAbility::HideKeyboardSelf()
636 {
637     // Current Ime is exiting, hide softkeyboard will cause the TextFiled to lose focus.
638     if (isImeTerminating_.load()) {
639         IMSA_HILOGI("Current Ime is terminating, no need to hide keyboard.");
640         return ErrorCode::NO_ERROR;
641     }
642     InputMethodSyncTrace tracer("IMA_HideKeyboardSelf start.");
643     auto ret = HideKeyboard(Trigger::IME_APP);
644     if (ret == ErrorCode::NO_ERROR) {
645         InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_SELF);
646     }
647     return ret == ErrorCode::ERROR_CLIENT_NULL_POINTER ? ret : ErrorCode::NO_ERROR;
648 }
649 
SendExtendAction(int32_t action)650 int32_t InputMethodAbility::SendExtendAction(int32_t action)
651 {
652     IMSA_HILOGD("InputMethodAbility, action: %{public}d.", action);
653     auto channel = GetInputDataChannelProxy();
654     if (channel == nullptr) {
655         IMSA_HILOGE("channel is nullptr!");
656         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
657     }
658     return channel->HandleExtendAction(action);
659 }
660 
GetTextBeforeCursor(int32_t number,std::u16string & text)661 int32_t InputMethodAbility::GetTextBeforeCursor(int32_t number, std::u16string &text)
662 {
663     InputMethodSyncTrace tracer("IMA_GetForward");
664     IMSA_HILOGD("InputMethodAbility, number: %{public}d.", number);
665     auto channel = GetInputDataChannelProxy();
666     if (channel == nullptr) {
667         IMSA_HILOGE("channel is nullptr!");
668         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
669     }
670     return channel->GetTextBeforeCursor(number, text);
671 }
672 
GetTextAfterCursor(int32_t number,std::u16string & text)673 int32_t InputMethodAbility::GetTextAfterCursor(int32_t number, std::u16string &text)
674 {
675     InputMethodSyncTrace tracer("IMA_GetTextAfterCursor");
676     IMSA_HILOGD("InputMethodAbility, number: %{public}d.", number);
677     auto channel = GetInputDataChannelProxy();
678     if (channel == nullptr) {
679         IMSA_HILOGE("channel is nullptr!");
680         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
681     }
682     return channel->GetTextAfterCursor(number, text);
683 }
684 
MoveCursor(int32_t keyCode)685 int32_t InputMethodAbility::MoveCursor(int32_t keyCode)
686 {
687     IMSA_HILOGD("InputMethodAbility, keyCode: %{public}d.", keyCode);
688     auto channel = GetInputDataChannelProxy();
689     if (channel == nullptr) {
690         IMSA_HILOGE("channel is nullptr!");
691         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
692     }
693     return channel->MoveCursor(keyCode);
694 }
695 
SelectByRange(int32_t start,int32_t end)696 int32_t InputMethodAbility::SelectByRange(int32_t start, int32_t end)
697 {
698     IMSA_HILOGD("InputMethodAbility, start: %{public}d, end: %{public}d", start, end);
699     if (start < 0 || end < 0) {
700         IMSA_HILOGE("check parameter failed, start: %{public}d, end: %{public}d!", start, end);
701         return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
702     }
703     auto dataChannel = GetInputDataChannelProxy();
704     if (dataChannel == nullptr) {
705         IMSA_HILOGE("datachannel is nullptr!");
706         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
707     }
708     return dataChannel->SelectByRange(start, end);
709 }
710 
SelectByMovement(int32_t direction)711 int32_t InputMethodAbility::SelectByMovement(int32_t direction)
712 {
713     IMSA_HILOGD("InputMethodAbility, direction: %{public}d.", direction);
714     auto dataChannel = GetInputDataChannelProxy();
715     if (dataChannel == nullptr) {
716         IMSA_HILOGE("datachannel is nullptr!");
717         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
718     }
719     return dataChannel->SelectByMovement(direction, 0);
720 }
721 
GetEnterKeyType(int32_t & keyType)722 int32_t InputMethodAbility::GetEnterKeyType(int32_t &keyType)
723 {
724     IMSA_HILOGD("InputMethodAbility start.");
725     auto channel = GetInputDataChannelProxy();
726     if (channel == nullptr) {
727         IMSA_HILOGE("channel is nullptr!");
728         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
729     }
730     return channel->GetEnterKeyType(keyType);
731 }
732 
GetInputPattern(int32_t & inputPattern)733 int32_t InputMethodAbility::GetInputPattern(int32_t &inputPattern)
734 {
735     IMSA_HILOGD("InputMethodAbility start.");
736     auto channel = GetInputDataChannelProxy();
737     if (channel == nullptr) {
738         IMSA_HILOGE("channel is nullptr!");
739         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
740     }
741     return channel->GetInputPattern(inputPattern);
742 }
743 
GetTextIndexAtCursor(int32_t & index)744 int32_t InputMethodAbility::GetTextIndexAtCursor(int32_t &index)
745 {
746     IMSA_HILOGD("InputMethodAbility start.");
747     auto channel = GetInputDataChannelProxy();
748     if (channel == nullptr) {
749         IMSA_HILOGE("channel is nullptr!");
750         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
751     }
752     return channel->GetTextIndexAtCursor(index);
753 }
754 
GetTextConfig(TextTotalConfig & textConfig)755 int32_t InputMethodAbility::GetTextConfig(TextTotalConfig &textConfig)
756 {
757     IMSA_HILOGD("InputMethodAbility start.");
758     auto channel = GetInputDataChannelProxy();
759     if (channel == nullptr) {
760         IMSA_HILOGE("channel is nullptr!");
761         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
762     }
763     return channel->GetTextConfig(textConfig);
764 }
765 
SetInputDataChannel(const sptr<IRemoteObject> & object)766 void InputMethodAbility::SetInputDataChannel(const sptr<IRemoteObject> &object)
767 {
768     IMSA_HILOGD("SetInputDataChannel start.");
769     std::lock_guard<std::mutex> lock(dataChannelLock_);
770     auto channelProxy = std::make_shared<InputDataChannelProxy>(object);
771     if (channelProxy == nullptr) {
772         IMSA_HILOGE("failed to create channel proxy!");
773         return;
774     }
775     dataChannelObject_ = object;
776     dataChannelProxy_ = channelProxy;
777 }
778 
GetInputDataChannelProxy()779 std::shared_ptr<InputDataChannelProxy> InputMethodAbility::GetInputDataChannelProxy()
780 {
781     std::lock_guard<std::mutex> lock(dataChannelLock_);
782     return dataChannelProxy_;
783 }
784 
SetInputControlChannel(sptr<IRemoteObject> & object)785 void InputMethodAbility::SetInputControlChannel(sptr<IRemoteObject> &object)
786 {
787     IMSA_HILOGD("SetInputControlChannel start.");
788     std::lock_guard<std::mutex> lock(controlChannelLock_);
789     std::shared_ptr<InputControlChannelProxy> channelProxy = std::make_shared<InputControlChannelProxy>(object);
790     if (channelProxy == nullptr) {
791         IMSA_HILOGD("channelProxy is nullptr!");
792         return;
793     }
794     controlChannel_ = channelProxy;
795 }
796 
ClearInputControlChannel()797 void InputMethodAbility::ClearInputControlChannel()
798 {
799     std::lock_guard<std::mutex> lock(controlChannelLock_);
800     controlChannel_ = nullptr;
801 }
802 
GetInputControlChannel()803 std::shared_ptr<InputControlChannelProxy> InputMethodAbility::GetInputControlChannel()
804 {
805     std::lock_guard<std::mutex> lock(controlChannelLock_);
806     return controlChannel_;
807 }
808 
OnRemoteSaDied(const wptr<IRemoteObject> & object)809 void InputMethodAbility::OnRemoteSaDied(const wptr<IRemoteObject> &object)
810 {
811     IMSA_HILOGI("input method service died.");
812     isBound_.store(false);
813     ClearInputControlChannel();
814     ClearSystemCmdChannel();
815     {
816         std::lock_guard<std::mutex> lock(abilityLock_);
817         abilityManager_ = nullptr;
818     }
819     if (imeListener_ != nullptr) {
820         imeListener_->OnInputStop();
821     }
822 }
823 
QuitWorkThread()824 void InputMethodAbility::QuitWorkThread()
825 {
826     stop_ = true;
827     Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
828     msgHandler_->SendMessage(msg);
829     if (workThreadHandler.joinable()) {
830         workThreadHandler.join();
831     }
832 }
833 
GetSecurityMode(int32_t & security)834 int32_t InputMethodAbility::GetSecurityMode(int32_t &security)
835 {
836     IMSA_HILOGI("InputMethodAbility start.");
837     auto proxy = GetImsaProxy();
838     if (proxy == nullptr) {
839         IMSA_HILOGE("failed to get imsa proxy!");
840         return false;
841     }
842     return proxy->GetSecurityMode(security);
843 }
844 
ClearSystemCmdChannel()845 void InputMethodAbility::ClearSystemCmdChannel()
846 {
847     std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
848     if (systemCmdChannelProxy_ == nullptr) {
849         IMSA_HILOGD("systemCmdChannelProxy_ already nullptr.");
850         return;
851     }
852     systemCmdChannelProxy_ = nullptr;
853     IMSA_HILOGD("end.");
854 }
855 
GetSystemCmdChannelProxy()856 sptr<SystemCmdChannelProxy> InputMethodAbility::GetSystemCmdChannelProxy()
857 {
858     std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
859     return systemCmdChannelProxy_;
860 }
861 
OnConnectSystemCmd(const sptr<IRemoteObject> & channel,sptr<IRemoteObject> & agent)862 int32_t InputMethodAbility::OnConnectSystemCmd(const sptr<IRemoteObject> &channel, sptr<IRemoteObject> &agent)
863 {
864     IMSA_HILOGD("InputMethodAbility start.");
865     std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
866     systemCmdChannelProxy_ = new (std::nothrow) SystemCmdChannelProxy(channel);
867     if (systemCmdChannelProxy_ == nullptr) {
868         IMSA_HILOGE("failed to create channel proxy!");
869         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
870     }
871     systemAgentStub_ = new (std::nothrow) InputMethodAgentStub();
872     if (systemAgentStub_ == nullptr) {
873         IMSA_HILOGE("failed to create agent!");
874         systemCmdChannelProxy_ = nullptr;
875         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
876     }
877     agent = systemAgentStub_->AsObject();
878     return ErrorCode::NO_ERROR;
879 }
880 
OnSecurityChange(int32_t security)881 int32_t InputMethodAbility::OnSecurityChange(int32_t security)
882 {
883     IMSA_HILOGI("InputMethodAbility start.");
884     if (imeListener_ == nullptr) {
885         IMSA_HILOGE("imeListener_ is nullptr!");
886         return ErrorCode::ERROR_BAD_PARAMETERS;
887     }
888     imeListener_->OnSecurityChange(security);
889     return ErrorCode::NO_ERROR;
890 }
891 
CreatePanel(const std::shared_ptr<AbilityRuntime::Context> & context,const PanelInfo & panelInfo,std::shared_ptr<InputMethodPanel> & inputMethodPanel)892 int32_t InputMethodAbility::CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context,
893     const PanelInfo &panelInfo, std::shared_ptr<InputMethodPanel> &inputMethodPanel)
894 {
895     IMSA_HILOGI("InputMethodAbility start.");
896     auto panelHeightCallback = [this](uint32_t panelHeight, PanelFlag panelFlag) {
897         NotifyKeyboardHeight(panelHeight, panelFlag);
898     };
899     auto flag = panels_.ComputeIfAbsent(
900         panelInfo.panelType, [panelHeightCallback, &panelInfo, &context, &inputMethodPanel](
901                                  const PanelType &panelType, std::shared_ptr<InputMethodPanel> &panel) {
902             inputMethodPanel = std::make_shared<InputMethodPanel>();
903             inputMethodPanel->SetPanelHeightCallback(panelHeightCallback);
904             auto ret = inputMethodPanel->CreatePanel(context, panelInfo);
905             if (ret == ErrorCode::NO_ERROR) {
906                 panel = inputMethodPanel;
907                 return true;
908             }
909             inputMethodPanel = nullptr;
910             return false;
911         });
912     // Called when creating the input method first time, if the CreatePanel is called later than the ShowKeyboard.
913     if (panelInfo.panelType == SOFT_KEYBOARD && isPendingShowKeyboard_) {
914         ShowKeyboard();
915         isPendingShowKeyboard_ = false;
916     }
917     return flag ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
918 }
919 
DestroyPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)920 int32_t InputMethodAbility::DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
921 {
922     IMSA_HILOGI("InputMethodAbility start.");
923     if (inputMethodPanel == nullptr) {
924         IMSA_HILOGE("panel is nullptr!");
925         return ErrorCode::ERROR_BAD_PARAMETERS;
926     }
927     auto ret = inputMethodPanel->DestroyPanel();
928     if (ret == ErrorCode::NO_ERROR) {
929         PanelType panelType = inputMethodPanel->GetPanelType();
930         panels_.Erase(panelType);
931     }
932     return ret;
933 }
934 
ShowPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)935 int32_t InputMethodAbility::ShowPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
936 {
937     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
938     if (inputMethodPanel == nullptr) {
939         return ErrorCode::ERROR_BAD_PARAMETERS;
940     }
941     return ShowPanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
942 }
943 
HidePanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)944 int32_t InputMethodAbility::HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
945 {
946     if (inputMethodPanel == nullptr) {
947         return ErrorCode::ERROR_BAD_PARAMETERS;
948     }
949 
950     // Current Ime is exiting, hide softkeyboard will cause the TextFiled to lose focus.
951     if (isImeTerminating_.load() && inputMethodPanel->GetPanelType() == PanelType::SOFT_KEYBOARD) {
952         IMSA_HILOGI("Current Ime is terminating, no need to hide keyboard.");
953         return ErrorCode::NO_ERROR;
954     }
955 
956     std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
957     return HidePanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
958 }
959 
ShowPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,PanelFlag flag,Trigger trigger)960 int32_t InputMethodAbility::ShowPanel(
961     const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger)
962 {
963     if (inputMethodPanel == nullptr) {
964         return ErrorCode::ERROR_BAD_PARAMETERS;
965     }
966     if (trigger == Trigger::IME_APP && GetInputDataChannelProxy() == nullptr) {
967         IMSA_HILOGE("channel is nullptr!");
968         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
969     }
970     if (flag == FLG_FIXED && inputMethodPanel->GetPanelType() == SOFT_KEYBOARD) {
971         auto ret = inputMethodPanel->SetTextFieldAvoidInfo(positionY_, height_);
972         if (ret != ErrorCode::NO_ERROR) {
973             IMSA_HILOGE("failed to set keyBoard, ret: %{public}d!", ret);
974         }
975     }
976     auto keyboardSize = inputMethodPanel->GetKeyboardSize();
977     SysPanelStatus sysPanelStatus = { false, flag, keyboardSize.width, keyboardSize.height };
978     NotifyPanelStatus(inputMethodPanel, sysPanelStatus);
979     auto ret = inputMethodPanel->ShowPanel();
980     if (ret == ErrorCode::NO_ERROR) {
981         NotifyPanelStatusInfo({ { inputMethodPanel->GetPanelType(), flag }, true, trigger });
982     }
983     return ret;
984 }
985 
HidePanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,PanelFlag flag,Trigger trigger)986 int32_t InputMethodAbility::HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag,
987                                       Trigger trigger)
988 {
989     if (inputMethodPanel == nullptr) {
990         return ErrorCode::ERROR_BAD_PARAMETERS;
991     }
992     auto ret = inputMethodPanel->HidePanel();
993     if (ret != ErrorCode::NO_ERROR) {
994         IMSA_HILOGD("failed, ret: %{public}d", ret);
995         return ret;
996     }
997     NotifyPanelStatusInfo({ { inputMethodPanel->GetPanelType(), flag }, false, trigger });
998     return ErrorCode::NO_ERROR;
999 }
1000 
NotifyPanelStatus(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,SysPanelStatus & sysPanelStatus)1001 int32_t InputMethodAbility::NotifyPanelStatus(
1002     const std::shared_ptr<InputMethodPanel> &inputMethodPanel, SysPanelStatus &sysPanelStatus)
1003 {
1004     if (inputMethodPanel->GetPanelType() != SOFT_KEYBOARD) {
1005         return ErrorCode::NO_ERROR;
1006     }
1007     // If it is not binding, do not need to notify the panel
1008     auto channel = GetInputDataChannelProxy();
1009     if (channel == nullptr) {
1010         return ErrorCode::NO_ERROR;
1011     }
1012     bool isSecurity = GetInputAttribute().GetSecurityFlag();
1013     sysPanelStatus.isSecurity = isSecurity;
1014     auto systemChannel = GetSystemCmdChannelProxy();
1015     if (systemChannel == nullptr) {
1016         IMSA_HILOGE("channel is nullptr!");
1017         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
1018     }
1019     return systemChannel->NotifyPanelStatus(sysPanelStatus);
1020 }
1021 
SetInputAttribute(const InputAttribute & inputAttribute)1022 void InputMethodAbility::SetInputAttribute(const InputAttribute &inputAttribute)
1023 {
1024     std::lock_guard<std::mutex> lock(inputAttrLock_);
1025     inputAttribute_ = inputAttribute;
1026 }
1027 
ClearInputAttribute()1028 void InputMethodAbility::ClearInputAttribute()
1029 {
1030     std::lock_guard<std::mutex> lock(inputAttrLock_);
1031     inputAttribute_ = {};
1032 }
1033 
GetInputAttribute()1034 InputAttribute InputMethodAbility::GetInputAttribute()
1035 {
1036     std::lock_guard<std::mutex> lock(inputAttrLock_);
1037     return inputAttribute_;
1038 }
1039 
HideKeyboard(Trigger trigger)1040 int32_t InputMethodAbility::HideKeyboard(Trigger trigger)
1041 {
1042     InputMethodSyncTrace tracer("IMA_HideKeyboard");
1043     if (imeListener_ == nullptr) {
1044         IMSA_HILOGE("imeListener_ is nullptr!");
1045         return ErrorCode::ERROR_IME;
1046     }
1047     IMSA_HILOGD("IMA, trigger: %{public}d.", static_cast<int32_t>(trigger));
1048     if (panels_.Contains(SOFT_KEYBOARD)) {
1049         auto panel = GetSoftKeyboardPanel();
1050         if (panel == nullptr) {
1051             IMSA_HILOGE("panel is nullptr!");
1052             return ErrorCode::ERROR_IME;
1053         }
1054         auto flag = panel->GetPanelFlag();
1055         imeListener_->OnKeyboardStatus(false);
1056         if (flag == FLG_CANDIDATE_COLUMN) {
1057             IMSA_HILOGI("panel flag is candidate, no need to hide.");
1058             return ErrorCode::NO_ERROR;
1059         }
1060         return HidePanel(panel, flag, trigger);
1061     }
1062     IMSA_HILOGI("panel is not created.");
1063     imeListener_->OnKeyboardStatus(false);
1064     auto channel = GetInputDataChannelProxy();
1065     if (channel != nullptr) {
1066         channel->SendKeyboardStatus(KeyboardStatus::HIDE);
1067     }
1068     auto controlChannel = GetInputControlChannel();
1069     if (controlChannel != nullptr && trigger == Trigger::IME_APP) {
1070         controlChannel->HideKeyboardSelf();
1071     }
1072     return ErrorCode::NO_ERROR;
1073 }
1074 
GetSoftKeyboardPanel()1075 std::shared_ptr<InputMethodPanel> InputMethodAbility::GetSoftKeyboardPanel()
1076 {
1077     auto result = panels_.Find(SOFT_KEYBOARD);
1078     if (!result.first) {
1079         return nullptr;
1080     }
1081     auto panel = result.second;
1082     if (!BlockRetry(FIND_PANEL_RETRY_INTERVAL, MAX_RETRY_TIMES, [panel]() -> bool {
1083             return panel != nullptr && panel->windowId_ != InputMethodPanel::INVALID_WINDOW_ID;
1084         })) {
1085         return nullptr;
1086     }
1087     return panel;
1088 }
1089 
IsCurrentIme()1090 bool InputMethodAbility::IsCurrentIme()
1091 {
1092     IMSA_HILOGD("InputMethodAbility start.");
1093     if (isCurrentIme_) {
1094         return true;
1095     }
1096     std::lock_guard<std::mutex> lock(imeCheckMutex_);
1097     if (isCurrentIme_) {
1098         return true;
1099     }
1100     auto proxy = GetImsaProxy();
1101     if (proxy == nullptr) {
1102         IMSA_HILOGE("failed to get imsa proxy!");
1103         return false;
1104     }
1105     if (proxy->IsCurrentIme()) {
1106         isCurrentIme_ = true;
1107         return true;
1108     }
1109     return false;
1110 }
1111 
IsDefaultIme()1112 bool InputMethodAbility::IsDefaultIme()
1113 {
1114     IMSA_HILOGD("InputMethodAbility start");
1115     if (isDefaultIme_) {
1116         return true;
1117     }
1118     std::lock_guard<std::mutex> lock(defaultImeCheckMutex_);
1119     if (isDefaultIme_) {
1120         return true;
1121     }
1122     auto proxy = GetImsaProxy();
1123     if (proxy == nullptr) {
1124         IMSA_HILOGE("failed to get imsa proxy!");
1125         return false;
1126     }
1127     auto ret = proxy->IsDefaultIme();
1128     if (ret == ErrorCode::NO_ERROR) {
1129         isDefaultIme_ = true;
1130         return true;
1131     }
1132     IMSA_HILOGE("call IsDefaultIme failed, ret: %{public}d!", ret);
1133     return false;
1134 }
1135 
IsEnable()1136 bool InputMethodAbility::IsEnable()
1137 {
1138     if (imeListener_ == nullptr) {
1139         return false;
1140     }
1141     return imeListener_->IsEnable();
1142 }
1143 
ExitCurrentInputType()1144 int32_t InputMethodAbility::ExitCurrentInputType()
1145 {
1146     IMSA_HILOGD("InputMethodAbility start.");
1147     auto proxy = GetImsaProxy();
1148     if (proxy == nullptr) {
1149         IMSA_HILOGE("failed to get imsa proxy!");
1150         return false;
1151     }
1152     return proxy->ExitCurrentInputType();
1153 }
1154 
IsPanelShown(const PanelInfo & panelInfo,bool & isShown)1155 int32_t InputMethodAbility::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
1156 {
1157     isShown = false;
1158     auto result = panels_.Find(panelInfo.panelType);
1159     if (!result.first) {
1160         IMSA_HILOGI("panel type: %{public}d not found.", static_cast<int32_t>(panelInfo.panelType));
1161         return ErrorCode::NO_ERROR;
1162     }
1163     auto panel = result.second;
1164     if (panel->GetPanelType() == PanelType::SOFT_KEYBOARD && panel->GetPanelFlag() != panelInfo.panelFlag) {
1165         IMSA_HILOGI("queried flag: %{public}d, current flag: %{public}d, panel not found.",
1166             static_cast<int32_t>(panelInfo.panelFlag), static_cast<int32_t>(panel->GetPanelFlag()));
1167         return ErrorCode::NO_ERROR;
1168     }
1169     isShown = panel->IsShowing();
1170     IMSA_HILOGI("type: %{public}d, flag: %{public}d, result: %{public}d.", static_cast<int32_t>(panelInfo.panelType),
1171         static_cast<int32_t>(panelInfo.panelFlag), isShown);
1172     return ErrorCode::NO_ERROR;
1173 }
1174 
OnClientInactive(const sptr<IRemoteObject> & channel)1175 void InputMethodAbility::OnClientInactive(const sptr<IRemoteObject> &channel)
1176 {
1177     IMSA_HILOGI("client inactive.");
1178     if (imeListener_ != nullptr) {
1179         imeListener_->OnInputFinish();
1180     }
1181     auto channelProxy = std::make_shared<InputDataChannelProxy>(channel);
1182     if (channelProxy == nullptr) {
1183         IMSA_HILOGE("failed to create channel proxy!");
1184         return;
1185     }
1186     auto panel = GetSoftKeyboardPanel();
1187     if (imeListener_ != nullptr && panel != nullptr && panel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
1188         imeListener_->OnKeyboardStatus(false);
1189     }
1190     panels_.ForEach([this, &channelProxy](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
1191         if (panelType != PanelType::SOFT_KEYBOARD || panel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
1192             auto ret = panel->HidePanel();
1193             if (ret != ErrorCode::NO_ERROR) {
1194                 IMSA_HILOGE("failed, ret: %{public}d", ret);
1195                 return false;
1196             }
1197             NotifyPanelStatusInfo({ { panel->GetPanelType(), panel->GetPanelFlag() }, false, Trigger::IME_APP },
1198                 channelProxy);
1199             // finish previewing text when soft keyboard hides
1200             if (panel->GetPanelType() == PanelType::SOFT_KEYBOARD) {
1201                 FinishTextPreview(true);
1202             }
1203         }
1204         return false;
1205     });
1206     ClearDataChannel(channel);
1207 }
1208 
NotifyKeyboardHeight(uint32_t panelHeight,PanelFlag panelFlag)1209 void InputMethodAbility::NotifyKeyboardHeight(uint32_t panelHeight, PanelFlag panelFlag)
1210 {
1211     auto channel = GetInputDataChannelProxy();
1212     if (channel == nullptr) {
1213         IMSA_HILOGE("channel is nullptr!");
1214         return;
1215     }
1216     IMSA_HILOGD("notify panel height: %{public}u, flag: %{public}d.", panelHeight, static_cast<int32_t>(panelFlag));
1217     if (panelFlag != PanelFlag::FLG_FIXED) {
1218         channel->NotifyKeyboardHeight(0);
1219         return;
1220     }
1221     channel->NotifyKeyboardHeight(panelHeight);
1222 }
1223 
SendPrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)1224 int32_t InputMethodAbility::SendPrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
1225 {
1226     if (!IsDefaultIme()) {
1227         IMSA_HILOGE("current is not default ime.");
1228         return ErrorCode::ERROR_NOT_DEFAULT_IME;
1229     }
1230     if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
1231         IMSA_HILOGE("privateCommand is limit 32KB, count limit 5!");
1232         return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
1233     }
1234     if (TextConfig::IsSystemPrivateCommand(privateCommand)) {
1235         auto systemChannel = GetSystemCmdChannelProxy();
1236         if (systemChannel == nullptr) {
1237             IMSA_HILOGE("channel is nullptr!");
1238             return ErrorCode::ERROR_SYSTEM_CMD_CHANNEL_ERROR;
1239         }
1240         return systemChannel->SendPrivateCommand(privateCommand);
1241     } else {
1242         auto channel = GetInputDataChannelProxy();
1243         if (channel == nullptr) {
1244             IMSA_HILOGE("channel is nullptr!");
1245             return ErrorCode::ERROR_CLIENT_NULL_POINTER;
1246         }
1247         return channel->SendPrivateCommand(privateCommand);
1248     }
1249 }
1250 
ReceivePrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)1251 int32_t InputMethodAbility::ReceivePrivateCommand(
1252     const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
1253 {
1254     if (!IsDefaultIme()) {
1255         IMSA_HILOGE("current is not default ime!");
1256         return ErrorCode::ERROR_NOT_DEFAULT_IME;
1257     }
1258     if (imeListener_ == nullptr) {
1259         IMSA_HILOGE("imeListener is nullptr!");
1260         return ErrorCode::ERROR_IME;
1261     }
1262     imeListener_->ReceivePrivateCommand(privateCommand);
1263     return ErrorCode::NO_ERROR;
1264 }
1265 
SetPreviewText(const std::string & text,const Range & range)1266 int32_t InputMethodAbility::SetPreviewText(const std::string &text, const Range &range)
1267 {
1268     InputMethodSyncTrace tracer("IMA_SetPreviewText");
1269     auto dataChannel = GetInputDataChannelProxy();
1270     if (dataChannel == nullptr) {
1271         IMSA_HILOGE("dataChannel is nullptr!");
1272         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
1273     }
1274     return dataChannel->SetPreviewText(text, range);
1275 }
1276 
FinishTextPreview(bool isAsync)1277 int32_t InputMethodAbility::FinishTextPreview(bool isAsync)
1278 {
1279     InputMethodSyncTrace tracer("IMA_FinishTextPreview");
1280     auto dataChannel = GetInputDataChannelProxy();
1281     if (dataChannel == nullptr) {
1282         IMSA_HILOGE("dataChannel is nullptr!");
1283         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
1284     }
1285     return dataChannel->FinishTextPreview(isAsync);
1286 }
1287 
GetCallingWindowInfo(CallingWindowInfo & windowInfo)1288 int32_t InputMethodAbility::GetCallingWindowInfo(CallingWindowInfo &windowInfo)
1289 {
1290     IMSA_HILOGD("IMA start.");
1291     auto channel = GetInputDataChannelProxy();
1292     if (channel == nullptr) {
1293         IMSA_HILOGE("channel is nullptr!");
1294         return ErrorCode::ERROR_CLIENT_NOT_FOUND;
1295     }
1296     auto panel = GetSoftKeyboardPanel();
1297     if (panel == nullptr) {
1298         IMSA_HILOGE("panel not found!");
1299         return ErrorCode::ERROR_PANEL_NOT_FOUND;
1300     }
1301     TextTotalConfig textConfig;
1302     int32_t ret = GetTextConfig(textConfig);
1303     if (ret != ErrorCode::NO_ERROR) {
1304         IMSA_HILOGE("failed to get window id, ret: %{public}d!", ret);
1305         return ErrorCode::ERROR_GET_TEXT_CONFIG;
1306     }
1307     ret = panel->SetCallingWindow(textConfig.windowId);
1308     if (ret != ErrorCode::NO_ERROR) {
1309         IMSA_HILOGE("failed to set calling window, ret: %{public}d!", ret);
1310         return ret;
1311     }
1312     ret = panel->GetCallingWindowInfo(windowInfo);
1313     if (ret != ErrorCode::NO_ERROR) {
1314         IMSA_HILOGE("failed to get calling window, ret: %{public}d", ret);
1315     }
1316     return ret;
1317 }
1318 
NotifyPanelStatusInfo(const PanelStatusInfo & info,std::shared_ptr<InputDataChannelProxy> & channelProxy)1319 void InputMethodAbility::NotifyPanelStatusInfo(
1320     const PanelStatusInfo &info, std::shared_ptr<InputDataChannelProxy> &channelProxy)
1321 {
1322     // CANDIDATE_COLUMN not notify
1323     if (info.panelInfo.panelFlag == PanelFlag::FLG_CANDIDATE_COLUMN) {
1324         return;
1325     }
1326     if (channelProxy != nullptr) {
1327         channelProxy->NotifyPanelStatusInfo(info);
1328     }
1329 
1330     auto controlChannel = GetInputControlChannel();
1331     if (controlChannel != nullptr && info.trigger == Trigger::IME_APP && !info.visible) {
1332         controlChannel->HideKeyboardSelf();
1333     }
1334 }
1335 } // namespace MiscServices
1336 } // namespace OHOS
1337