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