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