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_controller.h"
17
18 #include <algorithm>
19
20 #include "block_data.h"
21 #include "global.h"
22 #include "input_client_stub.h"
23 #include "input_data_channel_stub.h"
24 #include "input_method_agent_proxy.h"
25 #include "input_method_property.h"
26 #include "input_method_status.h"
27 #include "input_method_system_ability_proxy.h"
28 #include "inputmethod_sysevent.h"
29 #include "inputmethod_trace.h"
30 #include "iservice_registry.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 using namespace MessageID;
38 sptr<InputMethodController> InputMethodController::instance_;
39 std::shared_ptr<AppExecFwk::EventHandler> InputMethodController::handler_{ nullptr };
40 std::mutex InputMethodController::instanceLock_;
41 constexpr int32_t LOOP_COUNT = 5;
42 constexpr int64_t DELAY_TIME = 100;
43 const std::unordered_map<std::string, EventType> EVENT_TYPE{ { "imeChange", IME_CHANGE }, { "imeShow", IME_SHOW },
44 { "imeHide", IME_HIDE } };
InputMethodController()45 InputMethodController::InputMethodController() : msgHandler_(nullptr), stop_(false)
46 {
47 IMSA_HILOGI("InputMethodController structure");
48 }
49
~InputMethodController()50 InputMethodController::~InputMethodController()
51 {
52 QuitWorkThread();
53 delete msgHandler_;
54 msgHandler_ = nullptr;
55 }
56
GetInstance()57 sptr<InputMethodController> InputMethodController::GetInstance()
58 {
59 if (instance_ == nullptr) {
60 std::lock_guard<std::mutex> autoLock(instanceLock_);
61 if (instance_ == nullptr) {
62 IMSA_HILOGI("InputMethodController::GetInstance instance_ is nullptr");
63 instance_ = new (std::nothrow) InputMethodController();
64 if (instance_ == nullptr) {
65 return instance_;
66 }
67 int32_t ret = instance_->Initialize();
68 if (ret != ErrorCode::NO_ERROR) {
69 InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, "", "IMC initialize failed!");
70 }
71 }
72 }
73 return instance_;
74 }
75
SetSettingListener(std::shared_ptr<InputMethodSettingListener> listener)76 void InputMethodController::SetSettingListener(std::shared_ptr<InputMethodSettingListener> listener)
77 {
78 settingListener_ = std::move(listener);
79 }
80
RestoreListenEventFlag()81 int32_t InputMethodController::RestoreListenEventFlag()
82 {
83 auto proxy = GetSystemAbilityProxy();
84 if (proxy == nullptr) {
85 IMSA_HILOGE("proxy is nullptr");
86 return ErrorCode::ERROR_SERVICE_START_FAILED;
87 }
88 return proxy->UpdateListenEventFlag(clientInfo_, IME_NONE);
89 }
90
UpdateListenEventFlag(const std::string & type,bool isOn)91 int32_t InputMethodController::UpdateListenEventFlag(const std::string &type, bool isOn)
92 {
93 auto it = EVENT_TYPE.find(type);
94 if (it == EVENT_TYPE.end()) {
95 return ErrorCode::ERROR_BAD_PARAMETERS;
96 }
97 auto eventType = it->second;
98 auto proxy = GetSystemAbilityProxy();
99 if (proxy == nullptr) {
100 IMSA_HILOGE("proxy is nullptr");
101 return ErrorCode::ERROR_SERVICE_START_FAILED;
102 }
103 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
104 auto oldEventFlag = clientInfo_.eventFlag;
105 UpdateNativeEventFlag(eventType, isOn);
106 auto ret = proxy->UpdateListenEventFlag(clientInfo_, eventType);
107 if (ret != ErrorCode::NO_ERROR && isOn) {
108 clientInfo_.eventFlag = oldEventFlag;
109 }
110 return ret;
111 }
112
UpdateNativeEventFlag(EventType eventType,bool isOn)113 void InputMethodController::UpdateNativeEventFlag(EventType eventType, bool isOn)
114 {
115 uint32_t currentEvent = isOn ? 1u << eventType : ~(1u << eventType);
116 clientInfo_.eventFlag = isOn ? clientInfo_.eventFlag | currentEvent : clientInfo_.eventFlag & currentEvent;
117 }
118
SetControllerListener(std::shared_ptr<ControllerListener> controllerListener)119 void InputMethodController::SetControllerListener(std::shared_ptr<ControllerListener> controllerListener)
120 {
121 IMSA_HILOGI("InputMethodController run in");
122 controllerListener_ = std::move(controllerListener);
123 }
124
Initialize()125 int32_t InputMethodController::Initialize()
126 {
127 auto handler = new (std::nothrow) MessageHandler();
128 if (handler == nullptr) {
129 IMSA_HILOGE("failed to new message handler");
130 return ErrorCode::ERROR_NULL_POINTER;
131 }
132 msgHandler_ = handler;
133 auto client = new (std::nothrow) InputClientStub();
134 if (client == nullptr) {
135 IMSA_HILOGE("failed to new client");
136 return ErrorCode::ERROR_NULL_POINTER;
137 }
138 client->SetHandler(msgHandler_);
139 auto channel = new (std::nothrow) InputDataChannelStub();
140 if (channel == nullptr) {
141 IMSA_HILOGE("failed to new channel");
142 return ErrorCode::ERROR_NULL_POINTER;
143 }
144 channel->SetHandler(msgHandler_);
145 InputAttribute attribute = { .inputPattern = InputAttribute::PATTERN_TEXT };
146 clientInfo_ = { .attribute = attribute, .client = client, .channel = channel };
147 workThreadHandler = std::thread([this] { WorkThread(); });
148
149 // make AppExecFwk::EventHandler handler
150 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
151 return ErrorCode::NO_ERROR;
152 }
153
GetSystemAbilityProxy()154 sptr<IInputMethodSystemAbility> InputMethodController::GetSystemAbilityProxy()
155 {
156 std::lock_guard<std::mutex> lock(abilityLock_);
157 if (abilityManager_ != nullptr) {
158 return abilityManager_;
159 }
160 IMSA_HILOGI("get input method service proxy");
161 sptr<ISystemAbilityManager> systemAbilityManager =
162 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
163 if (systemAbilityManager == nullptr) {
164 IMSA_HILOGI("system ability manager is nullptr");
165 return nullptr;
166 }
167 auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, "");
168 if (systemAbility == nullptr) {
169 IMSA_HILOGI("system ability is nullptr");
170 return nullptr;
171 }
172 if (deathRecipient_ == nullptr) {
173 deathRecipient_ = new (std::nothrow) InputDeathRecipient();
174 if (deathRecipient_ == nullptr) {
175 IMSA_HILOGE("new death recipient failed");
176 return nullptr;
177 }
178 }
179 deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) { OnRemoteSaDied(remote); });
180 if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
181 IMSA_HILOGE("failed to add death recipient.");
182 return nullptr;
183 }
184 abilityManager_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
185 return abilityManager_;
186 }
187
WorkThread()188 void InputMethodController::WorkThread()
189 {
190 prctl(PR_SET_NAME, "IMCWorkThread");
191 while (!stop_) {
192 Message *msg = msgHandler_->GetMessage();
193 switch (msg->msgId_) {
194 case MSG_ID_INSERT_CHAR: {
195 IMSA_HILOGD("insert text");
196 auto listener = GetTextListener();
197 if (!isEditable_.load() || listener == nullptr) {
198 IMSA_HILOGE("not editable or textListener is nullptr");
199 break;
200 }
201 MessageParcel *data = msg->msgContent_;
202 listener->InsertText(data->ReadString16());
203 break;
204 }
205 case MSG_ID_DELETE_FORWARD: {
206 IMSA_HILOGD("delete forward");
207 auto listener = GetTextListener();
208 if (!isEditable_.load() || listener == nullptr) {
209 IMSA_HILOGE("not editable or textListener is nullptr");
210 break;
211 }
212 MessageParcel *data = msg->msgContent_;
213 // reverse for compatibility
214 listener->DeleteBackward(data->ReadInt32());
215 break;
216 }
217 case MSG_ID_DELETE_BACKWARD: {
218 IMSA_HILOGD("delete backward");
219 auto listener = GetTextListener();
220 if (!isEditable_.load() || listener == nullptr) {
221 IMSA_HILOGE("not editable or textListener is nullptr");
222 break;
223 }
224 MessageParcel *data = msg->msgContent_;
225 // reverse for compatibility
226 listener->DeleteForward(data->ReadInt32());
227 break;
228 }
229 case MSG_ID_ON_INPUT_STOP: {
230 auto listener = GetTextListener();
231 if (listener != nullptr) {
232 IMSA_HILOGE("textListener_ is not nullptr");
233 listener->SendKeyboardStatus(KeyboardStatus::HIDE);
234 }
235 isBound_.store(false);
236 isEditable_.store(false);
237 SetTextListener(nullptr);
238 {
239 std::lock_guard<std::mutex> autoLock(agentLock_);
240 agent_ = nullptr;
241 agentObject_ = nullptr;
242 }
243 ClearEditorCache();
244 break;
245 }
246 case MSG_ID_SEND_KEYBOARD_STATUS: {
247 auto listener = GetTextListener();
248 if (!isEditable_.load() || listener == nullptr) {
249 IMSA_HILOGE("not editable or textListener_ is nullptr");
250 break;
251 }
252 MessageParcel *data = msg->msgContent_;
253 KeyboardStatus status = static_cast<KeyboardStatus>(data->ReadInt32());
254 listener->SendKeyboardStatus(status);
255 if (status == KeyboardStatus::HIDE) {
256 clientInfo_.isShowKeyboard = false;
257 }
258 break;
259 }
260 case MSG_ID_SEND_FUNCTION_KEY: {
261 auto listener = GetTextListener();
262 if (!isEditable_.load() || listener == nullptr) {
263 IMSA_HILOGE("not editable or textListener_ is nullptr");
264 break;
265 }
266 MessageParcel *data = msg->msgContent_;
267 FunctionKey *info = new FunctionKey();
268 info->SetEnterKeyType(static_cast<EnterKeyType>(data->ReadInt32()));
269 listener->SendFunctionKey(*info);
270 delete info;
271 break;
272 }
273 case MSG_ID_MOVE_CURSOR: {
274 IMSA_HILOGD("move cursor");
275 auto listener = GetTextListener();
276 if (!isEditable_.load() || listener == nullptr) {
277 IMSA_HILOGE("not editable or textListener_ is nullptr");
278 break;
279 }
280 MessageParcel *data = msg->msgContent_;
281 Direction direction = static_cast<Direction>(data->ReadInt32());
282 listener->MoveCursor(direction);
283 break;
284 }
285 case MSG_ID_ON_SWITCH_INPUT: {
286 auto data = msg->msgContent_;
287 Property property;
288 SubProperty subProperty;
289 if (!ITypesUtil::Unmarshal(*data, property, subProperty)) {
290 IMSA_HILOGE("read property from message parcel failed");
291 break;
292 }
293 OnSwitchInput(property, subProperty);
294 break;
295 }
296 case MSG_ID_ON_PANEL_STATUS_CHANGE: {
297 auto data = msg->msgContent_;
298 uint32_t status;
299 std::vector<InputWindowInfo> windowInfo;
300 if (!ITypesUtil::Unmarshal(*data, status, windowInfo)) {
301 IMSA_HILOGE("read property from message parcel failed");
302 break;
303 }
304 OnPanelStatusChange(static_cast<InputWindowStatus>(status), windowInfo);
305 break;
306 }
307 case MSG_ID_SELECT_BY_RANGE: {
308 IMSA_HILOGD("select by range");
309 MessageParcel *data = msg->msgContent_;
310 int32_t start = 0;
311 int32_t end = 0;
312 if (!ITypesUtil::Unmarshal(*data, start, end)) {
313 IMSA_HILOGE("failed to read message parcel");
314 break;
315 }
316 OnSelectByRange(start, end);
317 break;
318 }
319 case MSG_ID_HANDLE_EXTEND_ACTION: {
320 IMSA_HILOGD("handle extend action");
321 MessageParcel *data = msg->msgContent_;
322 int32_t action;
323 if (!ITypesUtil::Unmarshal(*data, action)) {
324 IMSA_HILOGE("failed to read message parcel");
325 break;
326 }
327 HandleExtendAction(action);
328 break;
329 }
330 case MSG_ID_SELECT_BY_MOVEMENT: {
331 IMSA_HILOGD("select by movement");
332 MessageParcel *data = msg->msgContent_;
333 int32_t direction = 0;
334 int32_t cursorMoveSkip = 0;
335 if (!ITypesUtil::Unmarshal(*data, direction, cursorMoveSkip)) {
336 IMSA_HILOGE("failed to read message parcel");
337 break;
338 }
339 OnSelectByMovement(direction, cursorMoveSkip);
340 break;
341 }
342 case MSG_ID_GET_TEXT_BEFORE_CURSOR:
343 case MSG_ID_GET_TEXT_AFTER_CURSOR: {
344 IMSA_HILOGD("get text, msgId:%{public}d", msg->msgId_);
345 GetText(msg);
346 break;
347 }
348 case MSG_ID_GET_TEXT_INDEX_AT_CURSOR: {
349 IMSA_HILOGD("get text index at cursor");
350 GetTextIndexAtCursor(msg);
351 break;
352 }
353 default: {
354 IMSA_HILOGD("the message is %{public}d.", msg->msgId_);
355 break;
356 }
357 }
358 delete msg;
359 msg = nullptr;
360 }
361 }
362
QuitWorkThread()363 void InputMethodController::QuitWorkThread()
364 {
365 stop_ = true;
366 Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
367 msgHandler_->SendMessage(msg);
368 if (workThreadHandler.joinable()) {
369 workThreadHandler.join();
370 }
371 }
372
OnSwitchInput(const Property & property,const SubProperty & subProperty)373 void InputMethodController::OnSwitchInput(const Property &property, const SubProperty &subProperty)
374 {
375 IMSA_HILOGE("InputMethodController::OnSwitchInput");
376 if (settingListener_ == nullptr) {
377 IMSA_HILOGE("imeListener_ is nullptr");
378 return;
379 }
380 settingListener_->OnImeChange(property, subProperty);
381 }
382
OnPanelStatusChange(const InputWindowStatus & status,const std::vector<InputWindowInfo> & windowInfo)383 void InputMethodController::OnPanelStatusChange(
384 const InputWindowStatus &status, const std::vector<InputWindowInfo> &windowInfo)
385 {
386 IMSA_HILOGD("InputMethodController::OnPanelStatusChange");
387 if (settingListener_ == nullptr) {
388 IMSA_HILOGE("imeListener_ is nullptr");
389 return;
390 }
391 settingListener_->OnPanelStatusChange(status, windowInfo);
392 }
393
SaveTextConfig(const TextConfig & textConfig)394 void InputMethodController::SaveTextConfig(const TextConfig &textConfig)
395 {
396 IMSA_HILOGI("InputMethodController in, save text config.");
397 std::lock_guard<std::mutex> lock(textConfigLock_);
398 textConfig_ = textConfig;
399 }
400
Attach(sptr<OnTextChangedListener> & listener)401 int32_t InputMethodController::Attach(sptr<OnTextChangedListener> &listener)
402 {
403 return Attach(listener, true);
404 }
405
Attach(sptr<OnTextChangedListener> & listener,bool isShowKeyboard)406 int32_t InputMethodController::Attach(sptr<OnTextChangedListener> &listener, bool isShowKeyboard)
407 {
408 InputAttribute attribute;
409 attribute.inputPattern = InputAttribute::PATTERN_TEXT;
410 return Attach(listener, isShowKeyboard, attribute);
411 }
412
Attach(sptr<OnTextChangedListener> & listener,bool isShowKeyboard,const InputAttribute & attribute)413 int32_t InputMethodController::Attach(
414 sptr<OnTextChangedListener> &listener, bool isShowKeyboard, const InputAttribute &attribute)
415 {
416 IMSA_HILOGI("InputMethodController::Attach isShowKeyboard %{public}s", isShowKeyboard ? "true" : "false");
417 InputMethodSyncTrace tracer("InputMethodController Attach trace.");
418 TextConfig textConfig;
419 textConfig.inputAttribute = attribute;
420 return Attach(listener, isShowKeyboard, textConfig);
421 }
422
Attach(sptr<OnTextChangedListener> & listener,bool isShowKeyboard,const TextConfig & textConfig)423 int32_t InputMethodController::Attach(
424 sptr<OnTextChangedListener> &listener, bool isShowKeyboard, const TextConfig &textConfig)
425 {
426 IMSA_HILOGI("isShowKeyboard %{public}d", isShowKeyboard);
427 InputMethodSyncTrace tracer("InputMethodController Attach with textConfig trace.");
428 SetTextListener(listener);
429 clientInfo_.isShowKeyboard = isShowKeyboard;
430 SaveTextConfig(textConfig);
431
432 int32_t ret = PrepareInput(clientInfo_);
433 if (ret != ErrorCode::NO_ERROR) {
434 IMSA_HILOGE("failed to prepare, ret: %{public}d", ret);
435 return ret;
436 }
437 ret = StartInput(clientInfo_.client, isShowKeyboard, true);
438 if (ret != ErrorCode::NO_ERROR) {
439 IMSA_HILOGE("failed to start input, ret:%{public}d", ret);
440 return ret;
441 }
442 isBound_.store(true);
443 isEditable_.store(true);
444 IMSA_HILOGI("bind imf successfully, enter editable state");
445
446 if (isShowKeyboard) {
447 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_ATTACH);
448 }
449 return ErrorCode::NO_ERROR;
450 }
451
ShowTextInput()452 int32_t InputMethodController::ShowTextInput()
453 {
454 IMSA_HILOGI("InputMethodController::ShowTextInput");
455 if (!isBound_.load()) {
456 IMSA_HILOGE("not bound yet");
457 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
458 }
459 clientInfo_.isShowKeyboard = true;
460 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_ENEDITABLE);
461 int32_t ret = StartInput(clientInfo_.client, true, false);
462 if (ret != ErrorCode::NO_ERROR) {
463 IMSA_HILOGE("failed to start input, ret: %{public}d", ret);
464 return ret;
465 }
466 isEditable_.store(true);
467 IMSA_HILOGI("enter editable state");
468 return ret;
469 }
470
HideTextInput()471 int32_t InputMethodController::HideTextInput()
472 {
473 IMSA_HILOGI("InputMethodController::HideTextInput");
474 if (!isBound_.load()) {
475 IMSA_HILOGE("not bound yet");
476 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
477 }
478 isEditable_.store(false);
479 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNEDITABLE);
480 return StopInput(clientInfo_.client);
481 }
482
HideCurrentInput()483 int32_t InputMethodController::HideCurrentInput()
484 {
485 IMSA_HILOGD("InputMethodController::HideCurrentInput");
486 if (!isEditable_.load()) {
487 IMSA_HILOGE("not in editable state");
488 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
489 }
490 auto proxy = GetSystemAbilityProxy();
491 if (proxy == nullptr) {
492 IMSA_HILOGE("proxy is nullptr");
493 return ErrorCode::ERROR_EX_NULL_POINTER;
494 }
495 clientInfo_.isShowKeyboard = false;
496 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL);
497 return proxy->HideCurrentInputDeprecated();
498 }
499
ShowCurrentInput()500 int32_t InputMethodController::ShowCurrentInput()
501 {
502 IMSA_HILOGI("InputMethodController::ShowCurrentInput");
503 if (!isEditable_.load()) {
504 IMSA_HILOGE("not in editable state");
505 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
506 }
507 auto proxy = GetSystemAbilityProxy();
508 if (proxy == nullptr) {
509 IMSA_HILOGE("proxy is nullptr");
510 return ErrorCode::ERROR_EX_NULL_POINTER;
511 }
512 clientInfo_.isShowKeyboard = true;
513 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL);
514 return proxy->ShowCurrentInputDeprecated();
515 }
516
Close()517 int32_t InputMethodController::Close()
518 {
519 IMSA_HILOGI("InputMethodController::Close");
520 isBound_.store(false);
521 isEditable_.store(false);
522 bool isReportHide = clientInfo_.isShowKeyboard;
523 InputMethodSyncTrace tracer("InputMethodController Close trace.");
524 SetTextListener(nullptr);
525 {
526 std::lock_guard<std::mutex> lock(agentLock_);
527 agent_ = nullptr;
528 agentObject_ = nullptr;
529 }
530 ClearEditorCache();
531 isReportHide ? InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNBIND)
532 : InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_UNBIND);
533 return ReleaseInput(clientInfo_.client);
534 }
535
PrepareInput(InputClientInfo & inputClientInfo)536 int32_t InputMethodController::PrepareInput(InputClientInfo &inputClientInfo)
537 {
538 IMSA_HILOGI("InputMethodController::PrepareInput");
539 auto proxy = GetSystemAbilityProxy();
540 if (proxy == nullptr) {
541 IMSA_HILOGE("proxy is nullptr");
542 return ErrorCode::ERROR_SERVICE_START_FAILED;
543 }
544 return proxy->PrepareInput(inputClientInfo);
545 }
546
DisplayOptionalInputMethod()547 int32_t InputMethodController::DisplayOptionalInputMethod()
548 {
549 IMSA_HILOGI("InputMethodController::DisplayOptionalInputMethod");
550 auto proxy = GetSystemAbilityProxy();
551 if (proxy == nullptr) {
552 IMSA_HILOGE("proxy is nullptr");
553 return ErrorCode::ERROR_EX_NULL_POINTER;
554 }
555 return proxy->DisplayOptionalInputMethodDeprecated();
556 }
557
WasAttached()558 bool InputMethodController::WasAttached()
559 {
560 return isBound_.load();
561 }
562
ListInputMethodCommon(InputMethodStatus status,std::vector<Property> & props)563 int32_t InputMethodController::ListInputMethodCommon(InputMethodStatus status, std::vector<Property> &props)
564 {
565 IMSA_HILOGI("InputMethodController::ListInputMethodCommon");
566 auto proxy = GetSystemAbilityProxy();
567 if (proxy == nullptr) {
568 IMSA_HILOGE("proxy is nullptr");
569 return ErrorCode::ERROR_EX_NULL_POINTER;
570 }
571 return proxy->ListInputMethod(status, props);
572 }
573
ListInputMethod(std::vector<Property> & props)574 int32_t InputMethodController::ListInputMethod(std::vector<Property> &props)
575 {
576 IMSA_HILOGI("InputMethodController::listInputMethod");
577 return ListInputMethodCommon(ALL, props);
578 }
579
ListInputMethod(bool enable,std::vector<Property> & props)580 int32_t InputMethodController::ListInputMethod(bool enable, std::vector<Property> &props)
581 {
582 IMSA_HILOGI("InputMethodController::listInputMethod enable = %{public}s", enable ? "ENABLE" : "DISABLE");
583 return ListInputMethodCommon(enable ? ENABLE : DISABLE, props);
584 }
585
GetCurrentInputMethod()586 std::shared_ptr<Property> InputMethodController::GetCurrentInputMethod()
587 {
588 IMSA_HILOGD("InputMethodController::GetCurrentInputMethod");
589 auto proxy = GetSystemAbilityProxy();
590 if (proxy == nullptr) {
591 IMSA_HILOGE("proxy is nullptr");
592 return nullptr;
593 }
594 auto property = proxy->GetCurrentInputMethod();
595 if (property == nullptr) {
596 IMSA_HILOGE("InputMethodController::GetCurrentInputMethod property is nullptr");
597 return nullptr;
598 }
599 return property;
600 }
601
GetCurrentInputMethodSubtype()602 std::shared_ptr<SubProperty> InputMethodController::GetCurrentInputMethodSubtype()
603 {
604 IMSA_HILOGD("InputMethodController::GetCurrentInputMethod");
605 auto proxy = GetSystemAbilityProxy();
606 if (proxy == nullptr) {
607 IMSA_HILOGE("proxy is nullptr");
608 return nullptr;
609 }
610 auto property = proxy->GetCurrentInputMethodSubtype();
611 if (property == nullptr) {
612 IMSA_HILOGE("InputMethodController::GetCurrentInputMethodSubtype property is nullptr");
613 return nullptr;
614 }
615 return property;
616 }
617
StartInput(sptr<IInputClient> & client,bool isShowKeyboard,bool attachFlag)618 int32_t InputMethodController::StartInput(sptr<IInputClient> &client, bool isShowKeyboard, bool attachFlag)
619 {
620 IMSA_HILOGI("InputMethodController::StartInput");
621 auto proxy = GetSystemAbilityProxy();
622 if (proxy == nullptr) {
623 IMSA_HILOGE("proxy is nullptr");
624 return ErrorCode::ERROR_SERVICE_START_FAILED;
625 }
626 return proxy->StartInput(client, isShowKeyboard, attachFlag);
627 }
628
ReleaseInput(sptr<IInputClient> & client)629 int32_t InputMethodController::ReleaseInput(sptr<IInputClient> &client)
630 {
631 IMSA_HILOGD("InputMethodController::ReleaseInput");
632 auto proxy = GetSystemAbilityProxy();
633 if (proxy == nullptr) {
634 IMSA_HILOGE("proxy is nullptr");
635 return ErrorCode::ERROR_SERVICE_START_FAILED;
636 }
637 return proxy->ReleaseInput(client);
638 }
639
StopInput(sptr<IInputClient> & client)640 int32_t InputMethodController::StopInput(sptr<IInputClient> &client)
641 {
642 IMSA_HILOGD("InputMethodController::StopInput");
643 auto proxy = GetSystemAbilityProxy();
644 if (proxy == nullptr) {
645 IMSA_HILOGE("proxy is nullptr");
646 return ErrorCode::ERROR_SERVICE_START_FAILED;
647 }
648 return proxy->StopInput(client);
649 }
650
OnRemoteSaDied(const wptr<IRemoteObject> & remote)651 void InputMethodController::OnRemoteSaDied(const wptr<IRemoteObject> &remote)
652 {
653 IMSA_HILOGE("input method service death");
654 {
655 std::lock_guard<std::mutex> lock(abilityLock_);
656 abilityManager_ = nullptr;
657 }
658 if (handler_ == nullptr) {
659 IMSA_HILOGE("handler_ is nullptr");
660 return;
661 }
662 RestoreListenInfoInSaDied();
663 RestoreAttachInfoInSaDied();
664 }
665
RestoreListenInfoInSaDied()666 void InputMethodController::RestoreListenInfoInSaDied()
667 {
668 {
669 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
670 if (clientInfo_.eventFlag == EventStatusManager::NO_EVENT_ON) {
671 return;
672 }
673 }
674 isDiedRestoreListen_.store(false);
675 auto restoreListenTask = [=]() {
676 if (isDiedRestoreListen_.load()) {
677 return;
678 }
679 auto ret = RestoreListenEventFlag();
680 if (ret == ErrorCode::NO_ERROR) {
681 isDiedRestoreListen_.store(true);
682 IMSA_HILOGI("Try to RestoreListen success.");
683 }
684 };
685 for (int i = 0; i < LOOP_COUNT; i++) {
686 handler_->PostTask(restoreListenTask, "OnRemoteSaDied", DELAY_TIME * (i + 1));
687 }
688 }
689
RestoreAttachInfoInSaDied()690 void InputMethodController::RestoreAttachInfoInSaDied()
691 {
692 if (!isEditable_.load()) {
693 IMSA_HILOGE("not in editable state");
694 return;
695 }
696 auto attach = [=]() -> bool {
697 TextConfig tempConfig{};
698 {
699 std::lock_guard<std::mutex> lock(textConfigLock_);
700 tempConfig = textConfig_;
701 tempConfig.cursorInfo = cursorInfo_;
702 tempConfig.range.start = selectNewBegin_;
703 tempConfig.range.end = selectNewEnd_;
704 }
705 auto listener = GetTextListener();
706 auto errCode = Attach(listener, clientInfo_.isShowKeyboard, tempConfig);
707 IMSA_HILOGI("attach end, errCode = %{public}d", errCode);
708 return errCode == ErrorCode::NO_ERROR;
709 };
710 if (attach()) {
711 return;
712 }
713 isDiedAttached_.store(false);
714 auto attachTask = [this, attach]() {
715 if (isDiedAttached_.load()) {
716 return;
717 }
718 attach();
719 };
720 for (int i = 0; i < LOOP_COUNT; i++) {
721 handler_->PostTask(attachTask, "OnRemoteSaDied", DELAY_TIME * (i + 1));
722 }
723 }
724
OnCursorUpdate(CursorInfo cursorInfo)725 int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo)
726 {
727 if (!isBound_.load()) {
728 IMSA_HILOGE("not bound yet");
729 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
730 }
731 if (!isEditable_.load()) {
732 IMSA_HILOGE("not in editable state");
733 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
734 }
735 std::lock_guard<std::mutex> lock(agentLock_);
736 if (agent_ == nullptr) {
737 IMSA_HILOGI("agent is nullptr");
738 return ErrorCode::ERROR_SERVICE_START_FAILED;
739 }
740 {
741 std::lock_guard<std::mutex> lk(cursorInfoMutex_);
742 if (cursorInfo_ == cursorInfo) {
743 IMSA_HILOGI("same to last update");
744 return ErrorCode::NO_ERROR;
745 }
746 cursorInfo_ = cursorInfo;
747 }
748 agent_->OnCursorUpdate(cursorInfo.left, cursorInfo.top, cursorInfo.height);
749 return ErrorCode::NO_ERROR;
750 }
751
OnSelectionChange(std::u16string text,int start,int end)752 int32_t InputMethodController::OnSelectionChange(std::u16string text, int start, int end)
753 {
754 IMSA_HILOGD("size: %{public}zu, start: %{public}d, end: %{public}d", text.size(), start, end);
755 if (!isBound_.load()) {
756 IMSA_HILOGE("not bound yet");
757 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
758 }
759 if (!isEditable_.load()) {
760 IMSA_HILOGE("not in editable state");
761 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
762 }
763
764 if (textString_ == text && selectNewBegin_ == start && selectNewEnd_ == end) {
765 IMSA_HILOGI("same to last update");
766 return ErrorCode::NO_ERROR;
767 }
768 textString_ = text;
769 selectOldBegin_ = selectNewBegin_;
770 selectOldEnd_ = selectNewEnd_;
771 selectNewBegin_ = start;
772 selectNewEnd_ = end;
773 std::lock_guard<std::mutex> lock(agentLock_);
774 if (agent_ == nullptr) {
775 IMSA_HILOGE("agent is nullptr");
776 return ErrorCode::ERROR_SERVICE_START_FAILED;
777 }
778 agent_->OnSelectionChange(textString_, selectOldBegin_, selectOldEnd_, selectNewBegin_, selectNewEnd_);
779 return ErrorCode::NO_ERROR;
780 }
781
OnConfigurationChange(Configuration info)782 int32_t InputMethodController::OnConfigurationChange(Configuration info)
783 {
784 IMSA_HILOGI("InputMethodController::OnConfigurationChange");
785 if (!isBound_.load()) {
786 IMSA_HILOGE("not bound yet");
787 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
788 }
789 {
790 std::lock_guard<std::mutex> lock(textConfigLock_);
791 textConfig_.inputAttribute.enterKeyType = static_cast<uint32_t>(info.GetEnterKeyType());
792 textConfig_.inputAttribute.inputPattern = static_cast<uint32_t>(info.GetTextInputType());
793 }
794 std::lock_guard<std::mutex> agentLock(agentLock_);
795 if (agent_ == nullptr) {
796 IMSA_HILOGE("agent is nullptr");
797 return ErrorCode::ERROR_SERVICE_START_FAILED;
798 }
799 agent_->OnConfigurationChange(info);
800 return ErrorCode::NO_ERROR;
801 }
802
GetText(const Message * msg)803 void InputMethodController::GetText(const Message *msg)
804 {
805 std::u16string text;
806 auto resultHandler = msg->textResultHandler_;
807 auto listener = GetTextListener();
808 if (!isEditable_.load() || listener == nullptr) {
809 IMSA_HILOGE("not editable or textListener_ is nullptr");
810 resultHandler->SetValue(text);
811 return;
812 }
813 auto number = msg->msgContent_->ReadInt32();
814 if (number < 0) {
815 resultHandler->SetValue(text);
816 return;
817 }
818 if (msg->msgId_ == MSG_ID_GET_TEXT_BEFORE_CURSOR) {
819 text = listener->GetLeftTextOfCursor(number);
820 } else {
821 text = listener->GetRightTextOfCursor(number);
822 }
823 IMSA_HILOGI("get text success, msgId:%{public}d", msg->msgId_);
824 resultHandler->SetValue(text);
825 }
826
GetTextIndexAtCursor(const Message * msg)827 void InputMethodController::GetTextIndexAtCursor(const Message *msg)
828 {
829 int32_t index = -1;
830 auto resultHandler = msg->indexResultHandler_;
831 auto listener = GetTextListener();
832 if (!isEditable_.load() || listener == nullptr) {
833 IMSA_HILOGE("not editable or textListener_ is nullptr");
834 resultHandler->SetValue(index);
835 return;
836 }
837 index = listener->GetTextIndexAtCursor();
838 IMSA_HILOGI("get text index success");
839 resultHandler->SetValue(index);
840 }
841
DispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent)842 bool InputMethodController::DispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent)
843 {
844 InputMethodSyncTrace tracer("DispatchKeyEvent trace");
845 IMSA_HILOGI("InputMethodController in");
846 if (!isEditable_.load()) {
847 IMSA_HILOGE("not in editable state");
848 return false;
849 }
850 if (keyEvent == nullptr) {
851 IMSA_HILOGE("keyEvent is nullptr");
852 return false;
853 }
854 std::lock_guard<std::mutex> lock(agentLock_);
855 if (agent_ == nullptr) {
856 IMSA_HILOGI("agent is nullptr");
857 return false;
858 }
859 return agent_->DispatchKeyEvent(keyEvent);
860 }
861
GetEnterKeyType(int32_t & keyType)862 int32_t InputMethodController::GetEnterKeyType(int32_t &keyType)
863 {
864 IMSA_HILOGI("InputMethodController::GetEnterKeyType");
865 std::lock_guard<std::mutex> lock(textConfigLock_);
866 keyType = textConfig_.inputAttribute.enterKeyType;
867 return ErrorCode::NO_ERROR;
868 }
869
GetInputPattern(int32_t & inputpattern)870 int32_t InputMethodController::GetInputPattern(int32_t &inputpattern)
871 {
872 IMSA_HILOGI("InputMethodController::GetInputPattern");
873 std::lock_guard<std::mutex> lock(textConfigLock_);
874 inputpattern = textConfig_.inputAttribute.inputPattern;
875 return ErrorCode::NO_ERROR;
876 }
877
GetTextConfig(TextTotalConfig & config)878 int32_t InputMethodController::GetTextConfig(TextTotalConfig &config)
879 {
880 IMSA_HILOGI("InputMethodController run in.");
881 std::lock_guard<std::mutex> lock(textConfigLock_);
882 config.inputAttribute = textConfig_.inputAttribute;
883 config.cursorInfo = textConfig_.cursorInfo;
884 config.windowId = textConfig_.windowId;
885
886 if (textConfig_.range.start == INVALID_VALUE) {
887 IMSA_HILOGI("no valid SelectionRange param.");
888 return ErrorCode::NO_ERROR;
889 }
890 {
891 std::lock_guard<std::mutex> editorLock(editorContentLock_);
892 config.textSelection.oldBegin = selectOldBegin_;
893 config.textSelection.oldEnd = selectOldEnd_;
894 }
895 config.textSelection.newBegin = textConfig_.range.start;
896 config.textSelection.newEnd = textConfig_.range.end;
897
898 return ErrorCode::NO_ERROR;
899 }
900
SetCallingWindow(uint32_t windowId)901 int32_t InputMethodController::SetCallingWindow(uint32_t windowId)
902 {
903 if (!isBound_.load()) {
904 IMSA_HILOGE("not bound yet");
905 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
906 }
907 if (!isEditable_.load()) {
908 IMSA_HILOGE("not in editable state");
909 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
910 }
911 IMSA_HILOGI("InputMethodController::SetCallingWindow windowId = %{public}d", windowId);
912 std::lock_guard<std::mutex> lock(agentLock_);
913 if (agent_ == nullptr) {
914 IMSA_HILOGE("InputMethodController::SetCallingWindow mAgent is nullptr");
915 return ErrorCode::ERROR_SERVICE_START_FAILED;
916 }
917 agent_->SetCallingWindow(windowId);
918 return ErrorCode::NO_ERROR;
919 }
920
ShowSoftKeyboard()921 int32_t InputMethodController::ShowSoftKeyboard()
922 {
923 IMSA_HILOGI("InputMethodController ShowSoftKeyboard");
924 if (!isEditable_.load()) {
925 IMSA_HILOGE("not in editable state");
926 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
927 }
928 auto proxy = GetSystemAbilityProxy();
929 if (proxy == nullptr) {
930 IMSA_HILOGE("proxy is nullptr");
931 return ErrorCode::ERROR_EX_NULL_POINTER;
932 }
933 clientInfo_.isShowKeyboard = true;
934 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL);
935 return proxy->ShowCurrentInput();
936 }
937
HideSoftKeyboard()938 int32_t InputMethodController::HideSoftKeyboard()
939 {
940 IMSA_HILOGI("InputMethodController HideSoftKeyboard");
941 if (!isEditable_.load()) {
942 IMSA_HILOGE("not in editable state");
943 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
944 }
945 auto proxy = GetSystemAbilityProxy();
946 if (proxy == nullptr) {
947 IMSA_HILOGE("proxy is nullptr");
948 return ErrorCode::ERROR_EX_NULL_POINTER;
949 }
950 clientInfo_.isShowKeyboard = false;
951 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL);
952 return proxy->HideCurrentInput();
953 }
954
StopInputSession()955 int32_t InputMethodController::StopInputSession()
956 {
957 IMSA_HILOGI("InputMethodController HideSoftKeyboard");
958 isEditable_.store(false);
959 auto proxy = GetSystemAbilityProxy();
960 if (proxy == nullptr) {
961 IMSA_HILOGE("proxy is nullptr");
962 return ErrorCode::ERROR_EX_NULL_POINTER;
963 }
964 return proxy->StopInputSession();
965 }
966
ShowOptionalInputMethod()967 int32_t InputMethodController::ShowOptionalInputMethod()
968 {
969 IMSA_HILOGI("InputMethodController::ShowOptionalInputMethod");
970 auto proxy = GetSystemAbilityProxy();
971 if (proxy == nullptr) {
972 IMSA_HILOGE("proxy is nullptr");
973 return ErrorCode::ERROR_EX_NULL_POINTER;
974 }
975 return proxy->DisplayOptionalInputMethod();
976 }
977
ListInputMethodSubtype(const Property & property,std::vector<SubProperty> & subProps)978 int32_t InputMethodController::ListInputMethodSubtype(const Property &property, std::vector<SubProperty> &subProps)
979 {
980 IMSA_HILOGI("InputMethodController::ListInputMethodSubtype");
981 auto proxy = GetSystemAbilityProxy();
982 if (proxy == nullptr) {
983 IMSA_HILOGE("proxy is nullptr");
984 return ErrorCode::ERROR_EX_NULL_POINTER;
985 }
986 return proxy->ListInputMethodSubtype(property.name, subProps);
987 }
988
ListCurrentInputMethodSubtype(std::vector<SubProperty> & subProps)989 int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps)
990 {
991 IMSA_HILOGI("InputMethodController::ListCurrentInputMethodSubtype");
992 auto proxy = GetSystemAbilityProxy();
993 if (proxy == nullptr) {
994 IMSA_HILOGE("proxy is nullptr");
995 return ErrorCode::ERROR_EX_NULL_POINTER;
996 }
997 return proxy->ListCurrentInputMethodSubtype(subProps);
998 }
999
SwitchInputMethod(const std::string & name,const std::string & subName)1000 int32_t InputMethodController::SwitchInputMethod(const std::string &name, const std::string &subName)
1001 {
1002 IMSA_HILOGI("InputMethodController::SwitchInputMethod");
1003 auto proxy = GetSystemAbilityProxy();
1004 if (proxy == nullptr) {
1005 IMSA_HILOGE("proxy is nullptr");
1006 return ErrorCode::ERROR_EX_NULL_POINTER;
1007 }
1008 return proxy->SwitchInputMethod(name, subName);
1009 }
1010
OnInputReady(sptr<IRemoteObject> agentObject)1011 void InputMethodController::OnInputReady(sptr<IRemoteObject> agentObject)
1012 {
1013 IMSA_HILOGI("InputMethodController run in");
1014 std::lock_guard<std::mutex> lk(agentLock_);
1015 if (agentObject == nullptr) {
1016 IMSA_HILOGE("agentObject is nullptr");
1017 return;
1018 }
1019 if (agentObject_ != nullptr && agentObject_.GetRefPtr() == agentObject.GetRefPtr()) {
1020 IMSA_HILOGI("agent has already been set");
1021 return;
1022 }
1023 std::shared_ptr<IInputMethodAgent> agent = std::make_shared<InputMethodAgentProxy>(agentObject);
1024 if (agent == nullptr) {
1025 IMSA_HILOGE("failed to new agent proxy");
1026 }
1027 agentObject_ = agentObject;
1028 agent_ = agent;
1029 }
1030
ClearEditorCache()1031 void InputMethodController::ClearEditorCache()
1032 {
1033 IMSA_HILOGD("clear editor content cache");
1034 {
1035 std::lock_guard<std::mutex> lock(editorContentLock_);
1036 textString_ = Str8ToStr16("");
1037 selectOldBegin_ = 0;
1038 selectOldEnd_ = 0;
1039 selectNewBegin_ = 0;
1040 selectNewEnd_ = 0;
1041 }
1042 {
1043 std::lock_guard<std::mutex> lock(textConfigLock_);
1044 textConfig_ = {};
1045 }
1046 std::lock_guard<std::mutex> lock(cursorInfoMutex_);
1047 cursorInfo_ = {};
1048 }
1049
OnSelectByRange(int32_t start,int32_t end)1050 void InputMethodController::OnSelectByRange(int32_t start, int32_t end)
1051 {
1052 IMSA_HILOGI("InputMethodController run in");
1053 auto listener = GetTextListener();
1054 if (isEditable_.load() && listener != nullptr) {
1055 listener->HandleSetSelection(start, end);
1056 } else {
1057 IMSA_HILOGE("not editable or textListener_ is nullptr");
1058 }
1059
1060 if (controllerListener_ != nullptr) {
1061 controllerListener_->OnSelectByRange(start, end);
1062 } else {
1063 IMSA_HILOGE("controllerListener_ is nullptr");
1064 }
1065 }
1066
OnSelectByMovement(int32_t direction,int32_t cursorMoveSkip)1067 void InputMethodController::OnSelectByMovement(int32_t direction, int32_t cursorMoveSkip)
1068 {
1069 IMSA_HILOGI("InputMethodController run in");
1070 auto listener = GetTextListener();
1071 if (isEditable_.load() && listener != nullptr) {
1072 listener->HandleSelect(CURSOR_DIRECTION_BASE_VALUE + direction, cursorMoveSkip);
1073 } else {
1074 IMSA_HILOGE("not editable or textListener_ is nullptr");
1075 }
1076
1077 if (controllerListener_ != nullptr) {
1078 controllerListener_->OnSelectByMovement(direction);
1079 } else {
1080 IMSA_HILOGE("controllerListener_ is nullptr");
1081 }
1082 }
1083
HandleExtendAction(int32_t action)1084 void InputMethodController::HandleExtendAction(int32_t action)
1085 {
1086 IMSA_HILOGI("InputMethodController run in");
1087 auto listener = GetTextListener();
1088 if (!isEditable_.load() || listener == nullptr) {
1089 IMSA_HILOGE("not editable or textListener_ is nullptr");
1090 return;
1091 }
1092 listener->HandleExtendAction(action);
1093 }
1094
GetTextListener()1095 sptr<OnTextChangedListener> InputMethodController::GetTextListener()
1096 {
1097 std::lock_guard<std::mutex> lock(textListenerLock_);
1098 return textListener_;
1099 }
1100
SetTextListener(sptr<OnTextChangedListener> listener)1101 void InputMethodController::SetTextListener(sptr<OnTextChangedListener> listener)
1102 {
1103 std::lock_guard<std::mutex> lock(textListenerLock_);
1104 textListener_ = listener;
1105 }
1106 } // namespace MiscServices
1107 } // namespace OHOS
1108