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