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