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_proxy.h"
24 #include "input_method_core_proxy.h"
25 #include "input_method_utils.h"
26 #include "inputmethod_sysevent.h"
27 #include "inputmethod_trace.h"
28 #include "iservice_registry.h"
29 #include "itypes_util.h"
30 #include "message_parcel.h"
31 #include "string_ex.h"
32 #include "sys/prctl.h"
33 #include "system_ability_definition.h"
34
35 namespace OHOS {
36 namespace MiscServices {
37 class MessageHandler;
38 using namespace MessageID;
39 sptr<InputMethodAbility> InputMethodAbility::instance_;
40 std::mutex InputMethodAbility::instanceLock_;
41 constexpr double INVALID_CURSOR_VALUE = -1.0;
42 constexpr int32_t INVALID_SELECTION_VALUE = -1;
43 constexpr uint32_t FIND_PANEL_RETRY_INTERVAL = 10;
44 constexpr uint32_t MAX_RETRY_TIMES = 100;
InputMethodAbility()45 InputMethodAbility::InputMethodAbility() : msgHandler_(nullptr), stop_(false)
46 {
47 }
48
~InputMethodAbility()49 InputMethodAbility::~InputMethodAbility()
50 {
51 IMSA_HILOGI("InputMethodAbility::~InputMethodAbility");
52 QuitWorkThread();
53 if (msgHandler_ != nullptr) {
54 delete msgHandler_;
55 msgHandler_ = nullptr;
56 }
57 }
58
GetInstance()59 sptr<InputMethodAbility> InputMethodAbility::GetInstance()
60 {
61 if (instance_ == nullptr) {
62 std::lock_guard<std::mutex> autoLock(instanceLock_);
63 if (instance_ == nullptr) {
64 IMSA_HILOGI("InputMethodAbility need new IMA");
65 instance_ = new (std::nothrow) InputMethodAbility();
66 if (instance_ == nullptr) {
67 IMSA_HILOGE("instance is nullptr.");
68 return instance_;
69 }
70 instance_->Initialize();
71 }
72 }
73 return instance_;
74 }
75
GetImsaProxy()76 sptr<IInputMethodSystemAbility> InputMethodAbility::GetImsaProxy()
77 {
78 std::lock_guard<std::mutex> lock(abilityLock_);
79 if (abilityManager_ != nullptr) {
80 return abilityManager_;
81 }
82 IMSA_HILOGI("InputMethodAbility get imsa proxy");
83 sptr<ISystemAbilityManager> systemAbilityManager =
84 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
85 if (systemAbilityManager == nullptr) {
86 IMSA_HILOGE("systemAbilityManager is nullptr");
87 return nullptr;
88 }
89 auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, "");
90 if (systemAbility == nullptr) {
91 IMSA_HILOGE("systemAbility is nullptr");
92 return nullptr;
93 }
94 if (deathRecipient_ == nullptr) {
95 deathRecipient_ = new (std::nothrow) InputDeathRecipient();
96 if (deathRecipient_ == nullptr) {
97 IMSA_HILOGE("failed to new death recipient");
98 return nullptr;
99 }
100 }
101 deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) { OnRemoteSaDied(remote); });
102 if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
103 IMSA_HILOGE("failed to add death recipient.");
104 return nullptr;
105 }
106 abilityManager_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
107 return abilityManager_;
108 }
109
SetCoreAndAgent()110 int32_t InputMethodAbility::SetCoreAndAgent()
111 {
112 IMSA_HILOGD("InputMethodAbility, run in");
113 if (isBound_.load()) {
114 IMSA_HILOGD("already bound");
115 return ErrorCode::NO_ERROR;
116 }
117 auto proxy = GetImsaProxy();
118 if (proxy == nullptr) {
119 IMSA_HILOGE("imsa proxy is nullptr");
120 return ErrorCode::ERROR_NULL_POINTER;
121 }
122 int32_t ret = proxy->SetCoreAndAgent(coreStub_, agentStub_);
123 if (ret != ErrorCode::NO_ERROR) {
124 IMSA_HILOGE("set failed, ret: %{public}d", ret);
125 return ret;
126 }
127 isBound_.store(true);
128 IMSA_HILOGD("set successfully");
129 return ErrorCode::NO_ERROR;
130 }
131
UnRegisteredProxyIme(UnRegisteredType type)132 int32_t InputMethodAbility::UnRegisteredProxyIme(UnRegisteredType type)
133 {
134 isBound_.store(false);
135 auto proxy = GetImsaProxy();
136 if (proxy == nullptr) {
137 IMSA_HILOGE("imsa proxy is nullptr");
138 return ErrorCode::ERROR_NULL_POINTER;
139 }
140 return proxy->UnRegisteredProxyIme(type, coreStub_);
141 }
142
Initialize()143 void InputMethodAbility::Initialize()
144 {
145 IMSA_HILOGD("IMA");
146 coreStub_ = new (std::nothrow) InputMethodCoreStub();
147 if (coreStub_ == nullptr) {
148 IMSA_HILOGE("failed to create core");
149 return;
150 }
151 agentStub_ = new (std::nothrow) InputMethodAgentStub();
152 if (agentStub_ == nullptr) {
153 IMSA_HILOGE("failed to create agent");
154 return;
155 }
156 msgHandler_ = new (std::nothrow) MessageHandler();
157 if (msgHandler_ == nullptr) {
158 IMSA_HILOGE("failed to create message handler");
159 return;
160 }
161 coreStub_->SetMessageHandler(msgHandler_);
162 agentStub_->SetMessageHandler(msgHandler_);
163 workThreadHandler = std::thread([this] { WorkThread(); });
164 }
165
SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)166 void InputMethodAbility::SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)
167 {
168 IMSA_HILOGD("InputMethodAbility");
169 if (imeListener_ == nullptr) {
170 imeListener_ = std::move(imeListener);
171 }
172 }
173
SetKdListener(std::shared_ptr<KeyboardListener> kdListener)174 void InputMethodAbility::SetKdListener(std::shared_ptr<KeyboardListener> kdListener)
175 {
176 IMSA_HILOGD("InputMethodAbility.");
177 if (kdListener_ == nullptr) {
178 kdListener_ = std::move(kdListener);
179 }
180 }
181
WorkThread()182 void InputMethodAbility::WorkThread()
183 {
184 prctl(PR_SET_NAME, "OS_IMAWorkThread");
185 while (!stop_) {
186 Message *msg = msgHandler_->GetMessage();
187 switch (msg->msgId_) {
188 case MSG_ID_INIT_INPUT_CONTROL_CHANNEL: {
189 OnInitInputControlChannel(msg);
190 break;
191 }
192 case MSG_ID_ON_CURSOR_UPDATE: {
193 OnCursorUpdate(msg);
194 break;
195 }
196 case MSG_ID_ON_SELECTION_CHANGE: {
197 OnSelectionChange(msg);
198 break;
199 }
200 case MSG_ID_ON_CONFIGURATION_CHANGE: {
201 OnConfigurationChange(msg);
202 break;
203 }
204 case MSG_ID_STOP_INPUT_SERVICE: {
205 OnStopInputService(msg);
206 break;
207 }
208 case MSG_ID_SET_SUBTYPE: {
209 OnSetSubtype(msg);
210 break;
211 }
212 default: {
213 IMSA_HILOGD("the message is %{public}d.", msg->msgId_);
214 break;
215 }
216 }
217 delete msg;
218 msg = nullptr;
219 }
220 }
221
OnInitInputControlChannel(Message * msg)222 void InputMethodAbility::OnInitInputControlChannel(Message *msg)
223 {
224 IMSA_HILOGD("InputMethodAbility::OnInitInputControlChannel");
225 MessageParcel *data = msg->msgContent_;
226 sptr<IRemoteObject> channelObject = data->ReadRemoteObject();
227 if (channelObject == nullptr) {
228 IMSA_HILOGE("channelObject is nullptr");
229 return;
230 }
231 SetInputControlChannel(channelObject);
232 }
233
StartInput(const InputClientInfo & clientInfo,bool isBindFromClient)234 int32_t InputMethodAbility::StartInput(const InputClientInfo &clientInfo, bool isBindFromClient)
235 {
236 if (clientInfo.channel->AsObject() == nullptr) {
237 IMSA_HILOGE("channelObject is nullptr");
238 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
239 }
240 IMSA_HILOGI(
241 "IMA isShowKeyboard: %{public}d, isBindFromClient: %{public}d", clientInfo.isShowKeyboard, isBindFromClient);
242 SetInputDataChannel(clientInfo.channel->AsObject());
243 isBindFromClient ? InvokeTextChangeCallback(clientInfo.config) : NotifyAllTextConfig();
244 if (imeListener_ == nullptr) {
245 IMSA_HILOGE("imeListener is nullptr");
246 return ErrorCode::ERROR_IME;
247 }
248 if (clientInfo.isNotifyInputStart) {
249 imeListener_->OnInputStart();
250 }
251 isPendingShowKeyboard_ = clientInfo.isShowKeyboard;
252 return clientInfo.isShowKeyboard ? ShowKeyboard() : ErrorCode::NO_ERROR;
253 }
254
OnSetSubtype(Message * msg)255 void InputMethodAbility::OnSetSubtype(Message *msg)
256 {
257 auto data = msg->msgContent_;
258 SubProperty subProperty;
259 if (!ITypesUtil::Unmarshal(*data, subProperty)) {
260 IMSA_HILOGE("read message parcel failed");
261 return;
262 }
263 if (imeListener_ == nullptr) {
264 IMSA_HILOGE("imeListener_ is nullptr");
265 return;
266 }
267 imeListener_->OnSetSubtype(subProperty);
268 }
269
ClearDataChannel(const sptr<IRemoteObject> & channel)270 void InputMethodAbility::ClearDataChannel(const sptr<IRemoteObject> &channel)
271 {
272 std::lock_guard<std::mutex> lock(dataChannelLock_);
273 if (dataChannelObject_ == nullptr || channel == nullptr) {
274 IMSA_HILOGD("dataChannelObject_ already nullptr");
275 return;
276 }
277 if (dataChannelObject_.GetRefPtr() == channel.GetRefPtr()) {
278 dataChannelObject_ = nullptr;
279 dataChannelProxy_ = nullptr;
280 IMSA_HILOGD("end");
281 }
282 }
283
StopInput(const sptr<IRemoteObject> & channelObject)284 int32_t InputMethodAbility::StopInput(const sptr<IRemoteObject> &channelObject)
285 {
286 IMSA_HILOGI("IMA");
287 HideKeyboard();
288 ClearDataChannel(channelObject);
289 if (imeListener_ != nullptr) {
290 imeListener_->OnInputFinish();
291 }
292 return ErrorCode::NO_ERROR;
293 }
294
DispatchKeyEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent,sptr<KeyEventConsumerProxy> & consumer)295 int32_t InputMethodAbility::DispatchKeyEvent(
296 const std::shared_ptr<MMI::KeyEvent> &keyEvent, sptr<KeyEventConsumerProxy> &consumer)
297 {
298 if (keyEvent == nullptr) {
299 IMSA_HILOGE("keyEvent is nullptr");
300 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
301 }
302 if (kdListener_ == nullptr) {
303 IMSA_HILOGE("kdListener_ is nullptr");
304 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
305 }
306 IMSA_HILOGD("InputMethodAbility, run in");
307
308 if (!kdListener_->OnDealKeyEvent(keyEvent, consumer)) {
309 IMSA_HILOGE("keyEvent not deal");
310 return ErrorCode::ERROR_DISPATCH_KEY_EVENT;
311 }
312 return ErrorCode::NO_ERROR;
313 }
314
SetCallingWindow(uint32_t windowId)315 void InputMethodAbility::SetCallingWindow(uint32_t windowId)
316 {
317 if (imeListener_ == nullptr) {
318 IMSA_HILOGE("imeListener_ is nullptr");
319 return;
320 }
321 IMSA_HILOGD("InputMethodAbility windowId: %{public}d", windowId);
322 panels_.ForEach([windowId](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
323 panel->SetCallingWindow(windowId);
324 return false;
325 });
326 imeListener_->OnSetCallingWindow(windowId);
327 }
328
OnCursorUpdate(Message * msg)329 void InputMethodAbility::OnCursorUpdate(Message *msg)
330 {
331 MessageParcel *data = msg->msgContent_;
332 int32_t positionX = data->ReadInt32();
333 int32_t positionY = data->ReadInt32();
334 int32_t height = data->ReadInt32();
335 if (kdListener_ == nullptr) {
336 IMSA_HILOGE("kdListener_ is nullptr");
337 return;
338 }
339 IMSA_HILOGD("InputMethodAbility, x: %{public}d, y: %{public}d, height: %{public}d", positionX, positionY, height);
340 kdListener_->OnCursorUpdate(positionX, positionY, height);
341 }
342
OnSelectionChange(Message * msg)343 void InputMethodAbility::OnSelectionChange(Message *msg)
344 {
345 MessageParcel *data = msg->msgContent_;
346 std::string text = Str16ToStr8(data->ReadString16());
347 int32_t oldBegin = data->ReadInt32();
348 int32_t oldEnd = data->ReadInt32();
349 int32_t newBegin = data->ReadInt32();
350 int32_t newEnd = data->ReadInt32();
351
352 if (kdListener_ == nullptr) {
353 IMSA_HILOGE("kdListener_ is nullptr");
354 return;
355 }
356 kdListener_->OnTextChange(text);
357 kdListener_->OnSelectionChange(oldBegin, oldEnd, newBegin, newEnd);
358 }
359
OnConfigurationChange(Message * msg)360 void InputMethodAbility::OnConfigurationChange(Message *msg)
361 {
362 if (kdListener_ == nullptr) {
363 IMSA_HILOGE("in, kdListener_ is nullptr");
364 return;
365 }
366 MessageParcel *data = msg->msgContent_;
367 InputAttribute attribute;
368 attribute.enterKeyType = data->ReadInt32();
369 attribute.inputPattern = data->ReadInt32();
370 IMSA_HILOGD("InputMethodAbility, enterKeyType: %{public}d, inputPattern: %{public}d", attribute.enterKeyType,
371 attribute.inputPattern);
372 kdListener_->OnEditorAttributeChange(attribute);
373 }
374
OnStopInputService(Message * msg)375 void InputMethodAbility::OnStopInputService(Message *msg)
376 {
377 MessageParcel *data = msg->msgContent_;
378 bool isTerminateIme = data->ReadBool();
379 IMSA_HILOGI("isTerminateIme: %{public}d", isTerminateIme);
380 if (isTerminateIme && imeListener_ != nullptr) {
381 imeListener_->OnInputStop();
382 }
383 isBound_.store(false);
384 }
385
ShowKeyboard()386 int32_t InputMethodAbility::ShowKeyboard()
387 {
388 if (imeListener_ == nullptr) {
389 IMSA_HILOGE("imeListener is nullptr");
390 return ErrorCode::ERROR_IME;
391 }
392 IMSA_HILOGI("IMA start");
393 if (panels_.Contains(SOFT_KEYBOARD)) {
394 auto panel = GetSoftKeyboardPanel();
395 if (panel == nullptr) {
396 IMSA_HILOGE("panel is nullptr.");
397 return ErrorCode::ERROR_IME;
398 }
399 NotifyKeyboardHeight(panel);
400 auto flag = panel->GetPanelFlag();
401 imeListener_->OnKeyboardStatus(true);
402 if (flag == FLG_CANDIDATE_COLUMN) {
403 IMSA_HILOGI("panel flag is candidate, no need to show.");
404 return ErrorCode::NO_ERROR;
405 }
406 return ShowPanel(panel, flag, Trigger::IMF);
407 }
408 IMSA_HILOGI("panel not create");
409 auto channel = GetInputDataChannelProxy();
410 if (channel != nullptr) {
411 channel->SendKeyboardStatus(KeyboardStatus::SHOW);
412 }
413 imeListener_->OnKeyboardStatus(true);
414 return ErrorCode::NO_ERROR;
415 }
416
NotifyPanelStatusInfo(const PanelStatusInfo & info)417 void InputMethodAbility::NotifyPanelStatusInfo(const PanelStatusInfo &info)
418 {
419 // CANDIDATE_COLUMN not notify
420 if (info.panelInfo.panelFlag == PanelFlag::FLG_CANDIDATE_COLUMN) {
421 return;
422 }
423 auto channel = GetInputDataChannelProxy();
424 if (channel != nullptr) {
425 if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD) {
426 info.visible ? channel->SendKeyboardStatus(KeyboardStatus::SHOW)
427 : channel->SendKeyboardStatus(KeyboardStatus::HIDE);
428 }
429 channel->NotifyPanelStatusInfo(info);
430 }
431
432 auto controlChannel = GetInputControlChannel();
433 if (controlChannel != nullptr && info.trigger == Trigger::IME_APP && !info.visible) {
434 controlChannel->HideKeyboardSelf();
435 }
436 }
437
NotifyAllTextConfig()438 void InputMethodAbility::NotifyAllTextConfig()
439 {
440 TextTotalConfig textConfig = {};
441 int32_t ret = GetTextConfig(textConfig);
442 if (ret != ErrorCode::NO_ERROR) {
443 IMSA_HILOGE("get text config failed, ret is %{public}d", ret);
444 return;
445 }
446 InvokeTextChangeCallback(textConfig);
447 }
448
InvokeTextChangeCallback(const TextTotalConfig & textConfig)449 void InputMethodAbility::InvokeTextChangeCallback(const TextTotalConfig &textConfig)
450 {
451 if (kdListener_ == nullptr) {
452 IMSA_HILOGD("kdListener_ is nullptr.");
453 } else {
454 IMSA_HILOGD("start to invoke callbacks");
455 kdListener_->OnEditorAttributeChange(textConfig.inputAttribute);
456 if (textConfig.cursorInfo.left != INVALID_CURSOR_VALUE) {
457 IMSA_HILOGD("callback cursorUpdate");
458 kdListener_->OnCursorUpdate(
459 textConfig.cursorInfo.left, textConfig.cursorInfo.top, textConfig.cursorInfo.height);
460 }
461 if (textConfig.textSelection.newBegin != INVALID_SELECTION_VALUE) {
462 IMSA_HILOGD("callback selectionChange");
463 kdListener_->OnSelectionChange(textConfig.textSelection.oldBegin, textConfig.textSelection.oldEnd,
464 textConfig.textSelection.newBegin, textConfig.textSelection.newEnd);
465 }
466 }
467 if (textConfig.windowId == INVALID_WINDOW_ID) {
468 IMSA_HILOGD("invalid window id");
469 return;
470 }
471 panels_.ForEach([&textConfig](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
472 panel->SetCallingWindow(textConfig.windowId);
473 return false;
474 });
475 positionY_ = textConfig.positionY;
476 height_ = textConfig.height;
477 if (imeListener_ == nullptr) {
478 IMSA_HILOGD("imeListener_ is nullptr");
479 return;
480 }
481 imeListener_->OnSetCallingWindow(textConfig.windowId);
482 }
483
HideKeyboard()484 int32_t InputMethodAbility::HideKeyboard()
485 {
486 return HideKeyboard(Trigger::IMF);
487 }
488
InsertText(const std::string text)489 int32_t InputMethodAbility::InsertText(const std::string text)
490 {
491 InputMethodSyncTrace tracer("IMA_InsertText");
492 IMSA_HILOGD("InputMethodAbility, in");
493 auto channel = GetInputDataChannelProxy();
494 if (channel == nullptr) {
495 IMSA_HILOGE("channel is nullptr");
496 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
497 }
498 return channel->InsertText(Str8ToStr16(text));
499 }
500
DeleteForward(int32_t length)501 int32_t InputMethodAbility::DeleteForward(int32_t length)
502 {
503 InputMethodSyncTrace tracer("IMA_DeleteForward");
504 IMSA_HILOGD("InputMethodAbility, length = %{public}d", length);
505 auto channel = GetInputDataChannelProxy();
506 if (channel == nullptr) {
507 IMSA_HILOGE("channel is nullptr");
508 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
509 }
510 return channel->DeleteForward(length);
511 }
512
DeleteBackward(int32_t length)513 int32_t InputMethodAbility::DeleteBackward(int32_t length)
514 {
515 IMSA_HILOGD("InputMethodAbility, length = %{public}d", length);
516 auto channel = GetInputDataChannelProxy();
517 if (channel == nullptr) {
518 IMSA_HILOGE("channel is nullptr");
519 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
520 }
521 return channel->DeleteBackward(length);
522 }
523
SendFunctionKey(int32_t funcKey)524 int32_t InputMethodAbility::SendFunctionKey(int32_t funcKey)
525 {
526 auto channel = GetInputDataChannelProxy();
527 if (channel == nullptr) {
528 IMSA_HILOGE("channel is nullptr");
529 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
530 }
531 return channel->SendFunctionKey(funcKey);
532 }
533
HideKeyboardSelf()534 int32_t InputMethodAbility::HideKeyboardSelf()
535 {
536 auto ret = HideKeyboard(Trigger::IME_APP);
537 if (ret == ErrorCode::NO_ERROR) {
538 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_SELF);
539 }
540 return ret == ErrorCode::ERROR_CLIENT_NULL_POINTER ? ret : ErrorCode::NO_ERROR;
541 }
542
SendExtendAction(int32_t action)543 int32_t InputMethodAbility::SendExtendAction(int32_t action)
544 {
545 IMSA_HILOGD("InputMethodAbility, action: %{public}d", action);
546 auto channel = GetInputDataChannelProxy();
547 if (channel == nullptr) {
548 IMSA_HILOGE("channel is nullptr");
549 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
550 }
551 return channel->HandleExtendAction(action);
552 }
553
GetTextBeforeCursor(int32_t number,std::u16string & text)554 int32_t InputMethodAbility::GetTextBeforeCursor(int32_t number, std::u16string &text)
555 {
556 InputMethodSyncTrace tracer("IMA_GetForward");
557 IMSA_HILOGD("InputMethodAbility, number: %{public}d", number);
558 auto channel = GetInputDataChannelProxy();
559 if (channel == nullptr) {
560 IMSA_HILOGE("channel is nullptr");
561 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
562 }
563 return channel->GetTextBeforeCursor(number, text);
564 }
565
GetTextAfterCursor(int32_t number,std::u16string & text)566 int32_t InputMethodAbility::GetTextAfterCursor(int32_t number, std::u16string &text)
567 {
568 IMSA_HILOGD("InputMethodAbility, number: %{public}d", number);
569 auto channel = GetInputDataChannelProxy();
570 if (channel == nullptr) {
571 IMSA_HILOGE("channel is nullptr");
572 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
573 }
574 return channel->GetTextAfterCursor(number, text);
575 }
576
MoveCursor(int32_t keyCode)577 int32_t InputMethodAbility::MoveCursor(int32_t keyCode)
578 {
579 IMSA_HILOGD("InputMethodAbility, keyCode = %{public}d", keyCode);
580 auto channel = GetInputDataChannelProxy();
581 if (channel == nullptr) {
582 IMSA_HILOGE("channel is nullptr");
583 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
584 }
585 return channel->MoveCursor(keyCode);
586 }
587
SelectByRange(int32_t start,int32_t end)588 int32_t InputMethodAbility::SelectByRange(int32_t start, int32_t end)
589 {
590 IMSA_HILOGD("InputMethodAbility, start = %{public}d, end = %{public}d", start, end);
591 if (start < 0 || end < 0) {
592 IMSA_HILOGE("check parameter failed, start: %{public}d, end: %{public}d", start, end);
593 return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
594 }
595 auto dataChannel = GetInputDataChannelProxy();
596 if (dataChannel == nullptr) {
597 IMSA_HILOGE("datachannel is nullptr");
598 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
599 }
600 return dataChannel->SelectByRange(start, end);
601 }
602
SelectByMovement(int32_t direction)603 int32_t InputMethodAbility::SelectByMovement(int32_t direction)
604 {
605 IMSA_HILOGD("InputMethodAbility, direction = %{public}d", direction);
606 auto dataChannel = GetInputDataChannelProxy();
607 if (dataChannel == nullptr) {
608 IMSA_HILOGE("datachannel is nullptr");
609 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
610 }
611 return dataChannel->SelectByMovement(direction, 0);
612 }
613
GetEnterKeyType(int32_t & keyType)614 int32_t InputMethodAbility::GetEnterKeyType(int32_t &keyType)
615 {
616 IMSA_HILOGD("InputMethodAbility, run in");
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->GetEnterKeyType(keyType);
623 }
624
GetInputPattern(int32_t & inputPattern)625 int32_t InputMethodAbility::GetInputPattern(int32_t &inputPattern)
626 {
627 IMSA_HILOGD("InputMethodAbility, run in");
628 auto channel = GetInputDataChannelProxy();
629 if (channel == nullptr) {
630 IMSA_HILOGE("channel is nullptr");
631 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
632 }
633 return channel->GetInputPattern(inputPattern);
634 }
635
GetTextIndexAtCursor(int32_t & index)636 int32_t InputMethodAbility::GetTextIndexAtCursor(int32_t &index)
637 {
638 IMSA_HILOGD("InputMethodAbility, run in");
639 auto channel = GetInputDataChannelProxy();
640 if (channel == nullptr) {
641 IMSA_HILOGE("channel is nullptr");
642 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
643 }
644 return channel->GetTextIndexAtCursor(index);
645 }
646
GetTextConfig(TextTotalConfig & textConfig)647 int32_t InputMethodAbility::GetTextConfig(TextTotalConfig &textConfig)
648 {
649 IMSA_HILOGD("InputMethodAbility, run in.");
650 auto channel = GetInputDataChannelProxy();
651 if (channel == nullptr) {
652 IMSA_HILOGE("channel is nullptr");
653 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
654 }
655 return channel->GetTextConfig(textConfig);
656 }
657
SetInputDataChannel(const sptr<IRemoteObject> & object)658 void InputMethodAbility::SetInputDataChannel(const sptr<IRemoteObject> &object)
659 {
660 IMSA_HILOGD("run in SetInputDataChannel");
661 std::lock_guard<std::mutex> lock(dataChannelLock_);
662 auto channelProxy = std::make_shared<InputDataChannelProxy>(object);
663 if (channelProxy == nullptr) {
664 IMSA_HILOGE("failed to new data channel proxy");
665 return;
666 }
667 dataChannelObject_ = object;
668 dataChannelProxy_ = channelProxy;
669 }
670
GetInputDataChannelProxy()671 std::shared_ptr<InputDataChannelProxy> InputMethodAbility::GetInputDataChannelProxy()
672 {
673 std::lock_guard<std::mutex> lock(dataChannelLock_);
674 return dataChannelProxy_;
675 }
676
SetInputControlChannel(sptr<IRemoteObject> & object)677 void InputMethodAbility::SetInputControlChannel(sptr<IRemoteObject> &object)
678 {
679 IMSA_HILOGD("run in SetInputControlChannel");
680 std::lock_guard<std::mutex> lock(controlChannelLock_);
681 std::shared_ptr<InputControlChannelProxy> channelProxy = std::make_shared<InputControlChannelProxy>(object);
682 if (channelProxy == nullptr) {
683 IMSA_HILOGD("InputMethodAbility inputDataChannel is nullptr");
684 return;
685 }
686 controlChannel_ = channelProxy;
687 }
688
ClearInputControlChannel()689 void InputMethodAbility::ClearInputControlChannel()
690 {
691 std::lock_guard<std::mutex> lock(controlChannelLock_);
692 controlChannel_ = nullptr;
693 }
694
GetInputControlChannel()695 std::shared_ptr<InputControlChannelProxy> InputMethodAbility::GetInputControlChannel()
696 {
697 std::lock_guard<std::mutex> lock(controlChannelLock_);
698 return controlChannel_;
699 }
700
OnRemoteSaDied(const wptr<IRemoteObject> & object)701 void InputMethodAbility::OnRemoteSaDied(const wptr<IRemoteObject> &object)
702 {
703 IMSA_HILOGI("input method service died");
704 isBound_.store(false);
705 ClearInputControlChannel();
706 {
707 std::lock_guard<std::mutex> lock(abilityLock_);
708 abilityManager_ = nullptr;
709 }
710 if (imeListener_ != nullptr) {
711 imeListener_->OnInputStop();
712 }
713 }
714
QuitWorkThread()715 void InputMethodAbility::QuitWorkThread()
716 {
717 stop_ = true;
718 Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
719 msgHandler_->SendMessage(msg);
720 if (workThreadHandler.joinable()) {
721 workThreadHandler.join();
722 }
723 }
724
GetSecurityMode(int32_t & security)725 int32_t InputMethodAbility::GetSecurityMode(int32_t &security)
726 {
727 IMSA_HILOGI("InputMethodAbility start.");
728 auto proxy = GetImsaProxy();
729 if (proxy == nullptr) {
730 IMSA_HILOGE("failed to get imsa proxy.");
731 return false;
732 }
733 return proxy->GetSecurityMode(security);
734 }
735
OnSecurityChange(int32_t security)736 int32_t InputMethodAbility::OnSecurityChange(int32_t security)
737 {
738 IMSA_HILOGI("InputMethodAbility start.");
739 if (imeListener_ == nullptr) {
740 IMSA_HILOGE("InputMethodAbility, imeListener is nullptr");
741 return ErrorCode::ERROR_BAD_PARAMETERS;
742 }
743 imeListener_->OnSecurityChange(security);
744 return ErrorCode::NO_ERROR;
745 }
746
CreatePanel(const std::shared_ptr<AbilityRuntime::Context> & context,const PanelInfo & panelInfo,std::shared_ptr<InputMethodPanel> & inputMethodPanel)747 int32_t InputMethodAbility::CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context,
748 const PanelInfo &panelInfo, std::shared_ptr<InputMethodPanel> &inputMethodPanel)
749 {
750 IMSA_HILOGI("IMA");
751 auto flag = panels_.ComputeIfAbsent(panelInfo.panelType,
752 [&panelInfo, &context, &inputMethodPanel](const PanelType &panelType,
753 std::shared_ptr<InputMethodPanel> &panel) {
754 inputMethodPanel = std::make_shared<InputMethodPanel>();
755 auto ret = inputMethodPanel->CreatePanel(context, panelInfo);
756 if (ret == ErrorCode::NO_ERROR) {
757 panel = inputMethodPanel;
758 return true;
759 }
760 inputMethodPanel = nullptr;
761 return false;
762 });
763 // Called when creating the input method first time, if the CreatePanel is called later than the ShowKeyboard.
764 if (panelInfo.panelType == SOFT_KEYBOARD && isPendingShowKeyboard_) {
765 ShowKeyboard();
766 isPendingShowKeyboard_ = false;
767 }
768 return flag ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
769 }
770
DestroyPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)771 int32_t InputMethodAbility::DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
772 {
773 IMSA_HILOGI("IMA");
774 if (inputMethodPanel == nullptr) {
775 IMSA_HILOGE("panel is nullptr");
776 return ErrorCode::ERROR_BAD_PARAMETERS;
777 }
778 auto ret = inputMethodPanel->DestroyPanel();
779 if (ret == ErrorCode::NO_ERROR) {
780 PanelType panelType = inputMethodPanel->GetPanelType();
781 panels_.Erase(panelType);
782 }
783 return ret;
784 }
785
ShowPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)786 int32_t InputMethodAbility::ShowPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
787 {
788 if (inputMethodPanel == nullptr) {
789 return ErrorCode::ERROR_BAD_PARAMETERS;
790 }
791 return ShowPanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
792 }
793
HidePanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel)794 int32_t InputMethodAbility::HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
795 {
796 if (inputMethodPanel == nullptr) {
797 return ErrorCode::ERROR_BAD_PARAMETERS;
798 }
799 return HidePanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
800 }
801
ShowPanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,PanelFlag flag,Trigger trigger)802 int32_t InputMethodAbility::ShowPanel(
803 const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger)
804 {
805 if (inputMethodPanel == nullptr) {
806 return ErrorCode::ERROR_BAD_PARAMETERS;
807 }
808 if (trigger == Trigger::IME_APP && GetInputDataChannelProxy() == nullptr) {
809 IMSA_HILOGE("channel is nullptr");
810 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
811 }
812 if (flag == FLG_FIXED && inputMethodPanel->GetPanelType() == SOFT_KEYBOARD) {
813 auto ret = inputMethodPanel->SetTextFieldAvoidInfo(positionY_, height_);
814 if (ret != ErrorCode::NO_ERROR) {
815 IMSA_HILOGE("Set Keyboard failed, ret = %{public}d", ret);
816 }
817 }
818 auto ret = inputMethodPanel->ShowPanel();
819 if (ret == ErrorCode::NO_ERROR) {
820 NotifyPanelStatusInfo({ { inputMethodPanel->GetPanelType(), flag }, true, trigger });
821 }
822 return ret;
823 }
824
HidePanel(const std::shared_ptr<InputMethodPanel> & inputMethodPanel,PanelFlag flag,Trigger trigger)825 int32_t InputMethodAbility::HidePanel(
826 const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger)
827 {
828 if (inputMethodPanel == nullptr) {
829 return ErrorCode::ERROR_BAD_PARAMETERS;
830 }
831 auto ret = inputMethodPanel->HidePanel();
832 if (ret == ErrorCode::NO_ERROR) {
833 NotifyPanelStatusInfo({ { inputMethodPanel->GetPanelType(), flag }, false, trigger });
834 }
835 return ret;
836 }
837
HideKeyboard(Trigger trigger)838 int32_t InputMethodAbility::HideKeyboard(Trigger trigger)
839 {
840 if (imeListener_ == nullptr) {
841 IMSA_HILOGE("imeListener_ is nullptr");
842 return ErrorCode::ERROR_IME;
843 }
844 IMSA_HILOGD("IMA, trigger: %{public}d", static_cast<int32_t>(trigger));
845 if (panels_.Contains(SOFT_KEYBOARD)) {
846 auto panel = GetSoftKeyboardPanel();
847 if (panel == nullptr) {
848 IMSA_HILOGE("panel is nullptr.");
849 return ErrorCode::ERROR_IME;
850 }
851 auto flag = panel->GetPanelFlag();
852 imeListener_->OnKeyboardStatus(false);
853 if (flag == FLG_CANDIDATE_COLUMN) {
854 IMSA_HILOGI("panel flag is candidate, no need to hide.");
855 return ErrorCode::NO_ERROR;
856 }
857 return HidePanel(panel, flag, trigger);
858 }
859 IMSA_HILOGI("panel not create");
860 imeListener_->OnKeyboardStatus(false);
861 auto channel = GetInputDataChannelProxy();
862 if (channel != nullptr) {
863 channel->SendKeyboardStatus(KeyboardStatus::HIDE);
864 }
865 auto controlChannel = GetInputControlChannel();
866 if (controlChannel != nullptr && trigger == Trigger::IME_APP) {
867 controlChannel->HideKeyboardSelf();
868 }
869 return ErrorCode::NO_ERROR;
870 }
871
GetSoftKeyboardPanel()872 std::shared_ptr<InputMethodPanel> InputMethodAbility::GetSoftKeyboardPanel()
873 {
874 auto result = panels_.Find(SOFT_KEYBOARD);
875 if (!result.first) {
876 return nullptr;
877 }
878 auto panel = result.second;
879 if (!BlockRetry(FIND_PANEL_RETRY_INTERVAL, MAX_RETRY_TIMES, [panel]() -> bool {
880 return panel != nullptr && panel->windowId_ != InputMethodPanel::INVALID_WINDOW_ID;
881 })) {
882 return nullptr;
883 }
884 return panel;
885 }
886
IsCurrentIme()887 bool InputMethodAbility::IsCurrentIme()
888 {
889 IMSA_HILOGD("InputMethodAbility, in");
890 if (isCurrentIme_) {
891 return true;
892 }
893 std::lock_guard<std::mutex> lock(imeCheckMutex_);
894 if (isCurrentIme_) {
895 return true;
896 }
897 auto proxy = GetImsaProxy();
898 if (proxy == nullptr) {
899 IMSA_HILOGE("failed to get imsa proxy");
900 return false;
901 }
902 if (proxy->IsCurrentIme()) {
903 isCurrentIme_ = true;
904 return true;
905 }
906 return false;
907 }
908
IsEnable()909 bool InputMethodAbility::IsEnable()
910 {
911 if (imeListener_ == nullptr) {
912 return false;
913 }
914 return imeListener_->IsEnable();
915 }
916
ExitCurrentInputType()917 int32_t InputMethodAbility::ExitCurrentInputType()
918 {
919 IMSA_HILOGD("InputMethodAbility, in");
920 auto proxy = GetImsaProxy();
921 if (proxy == nullptr) {
922 IMSA_HILOGE("failed to get imsa proxy");
923 return false;
924 }
925 return proxy->ExitCurrentInputType();
926 }
927
IsPanelShown(const PanelInfo & panelInfo,bool & isShown)928 int32_t InputMethodAbility::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
929 {
930 isShown = false;
931 auto result = panels_.Find(panelInfo.panelType);
932 if (!result.first) {
933 IMSA_HILOGI("panel type: %{public}d not found", static_cast<int32_t>(panelInfo.panelType));
934 return ErrorCode::NO_ERROR;
935 }
936 auto panel = result.second;
937 if (panel->GetPanelType() == PanelType::SOFT_KEYBOARD && panel->GetPanelFlag() != panelInfo.panelFlag) {
938 IMSA_HILOGI("queried flag: %{public}d, current flag: %{public}d, panel not found",
939 static_cast<int32_t>(panelInfo.panelFlag), static_cast<int32_t>(panel->GetPanelFlag()));
940 return ErrorCode::NO_ERROR;
941 }
942 isShown = panel->IsShowing();
943 IMSA_HILOGI("type: %{public}d, flag: %{public}d, result: %{public}d", static_cast<int32_t>(panelInfo.panelType),
944 static_cast<int32_t>(panelInfo.panelFlag), isShown);
945 return ErrorCode::NO_ERROR;
946 }
947
OnClientInactive(const sptr<IRemoteObject> & channel)948 void InputMethodAbility::OnClientInactive(const sptr<IRemoteObject> &channel)
949 {
950 IMSA_HILOGI("client inactive");
951 ClearDataChannel(channel);
952 panels_.ForEach([](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
953 if (panelType != PanelType::SOFT_KEYBOARD || panel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
954 panel->HidePanel();
955 }
956 return false;
957 });
958 }
959
OnTextConfigChange(const InputClientInfo & clientInfo)960 int32_t InputMethodAbility::OnTextConfigChange(const InputClientInfo &clientInfo)
961 {
962 if (clientInfo.channel != nullptr) {
963 SetInputDataChannel(clientInfo.channel->AsObject());
964 }
965 InvokeTextChangeCallback(clientInfo.config);
966 return clientInfo.isShowKeyboard ? ShowKeyboard() : ErrorCode::NO_ERROR;
967 }
968
NotifyKeyboardHeight(const std::shared_ptr<InputMethodPanel> inputMethodPanel)969 void InputMethodAbility::NotifyKeyboardHeight(const std::shared_ptr<InputMethodPanel> inputMethodPanel)
970 {
971 if (inputMethodPanel == nullptr) {
972 IMSA_HILOGE("inputMethodPanel is nullptr");
973 return;
974 }
975 if (inputMethodPanel->GetPanelType() != PanelType::SOFT_KEYBOARD) {
976 IMSA_HILOGW("current panel is not soft keyboard");
977 return;
978 }
979 auto channel = GetInputDataChannelProxy();
980 if (channel == nullptr) {
981 IMSA_HILOGE("channel is nullptr");
982 return;
983 }
984 if (inputMethodPanel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
985 channel->NotifyKeyboardHeight(0);
986 return;
987 }
988 channel->NotifyKeyboardHeight(inputMethodPanel->GetHeight());
989 }
990 } // namespace MiscServices
991 } // namespace OHOS
992