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 #include <cinttypes>
20
21 #include "block_data.h"
22 #include "global.h"
23 #include "input_client_stub.h"
24 #include "input_data_channel_stub.h"
25 #include "input_method_agent_proxy.h"
26 #include "input_method_property.h"
27 #include "input_method_status.h"
28 #include "input_method_system_ability_proxy.h"
29 #include "inputmethod_sysevent.h"
30 #include "inputmethod_trace.h"
31 #include "iservice_registry.h"
32 #include "keyevent_consumer_stub.h"
33 #include "string_ex.h"
34 #include "sys/prctl.h"
35 #include "system_ability_definition.h"
36 #include "system_cmd_channel_stub.h"
37
38
39 namespace OHOS {
40 namespace MiscServices {
41 using namespace MessageID;
42 using namespace std::chrono;
43 sptr<InputMethodController> InputMethodController::instance_;
44 std::shared_ptr<AppExecFwk::EventHandler> InputMethodController::handler_{ nullptr };
45 std::mutex InputMethodController::instanceLock_;
46 std::mutex InputMethodController::logLock_;
47 int InputMethodController::keyEventCountInPeriod_ = 0;
48 std::chrono::system_clock::time_point InputMethodController::startLogTime_ = system_clock::now();
49 constexpr int32_t LOOP_COUNT = 5;
50 constexpr int32_t LOG_MAX_TIME = 20;
51 constexpr int64_t DELAY_TIME = 100;
52 constexpr int32_t ACE_DEAL_TIME_OUT = 200;
InputMethodController()53 InputMethodController::InputMethodController()
54 {
55 IMSA_HILOGD("IMC structure.");
56 }
57
~InputMethodController()58 InputMethodController::~InputMethodController()
59 {
60 }
61
GetInstance()62 sptr<InputMethodController> InputMethodController::GetInstance()
63 {
64 if (instance_ == nullptr) {
65 std::lock_guard<std::mutex> autoLock(instanceLock_);
66 if (instance_ == nullptr) {
67 IMSA_HILOGD("instance_ is nullptr.");
68 instance_ = new (std::nothrow) InputMethodController();
69 if (instance_ == nullptr) {
70 IMSA_HILOGE("failed to create InputMethodController!");
71 return instance_;
72 }
73 int32_t ret = instance_->Initialize();
74 if (ret != ErrorCode::NO_ERROR) {
75 InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, "", "IMC initialize failed!");
76 }
77 }
78 }
79 return instance_;
80 }
81
RestoreListenEventFlag()82 int32_t InputMethodController::RestoreListenEventFlag()
83 {
84 auto proxy = GetSystemAbilityProxy();
85 if (proxy == nullptr) {
86 IMSA_HILOGE("proxy is nullptr!");
87 return ErrorCode::ERROR_SERVICE_START_FAILED;
88 }
89 // 0 represent no need to check permission
90 return proxy->UpdateListenEventFlag(clientInfo_, 0);
91 }
92
UpdateListenEventFlag(uint32_t finalEventFlag,uint32_t eventFlag,bool isOn)93 int32_t InputMethodController::UpdateListenEventFlag(uint32_t finalEventFlag, uint32_t eventFlag, bool isOn)
94 {
95 auto oldEventFlag = clientInfo_.eventFlag;
96 clientInfo_.eventFlag = finalEventFlag;
97 auto proxy = GetSystemAbilityProxy();
98 if (proxy == nullptr) {
99 IMSA_HILOGE("proxy is nullptr!");
100 if (isOn) {
101 clientInfo_.eventFlag = oldEventFlag;
102 }
103 return ErrorCode::ERROR_SERVICE_START_FAILED;
104 }
105 auto ret = proxy->UpdateListenEventFlag(clientInfo_, eventFlag);
106 if (ret != ErrorCode::NO_ERROR && isOn) {
107 clientInfo_.eventFlag = oldEventFlag;
108 }
109 return ret;
110 }
111
SetControllerListener(std::shared_ptr<ControllerListener> controllerListener)112 void InputMethodController::SetControllerListener(std::shared_ptr<ControllerListener> controllerListener)
113 {
114 IMSA_HILOGD("InputMethodController run in");
115 controllerListener_ = std::move(controllerListener);
116 }
117
Initialize()118 int32_t InputMethodController::Initialize()
119 {
120 sptr<IInputClient> client = new (std::nothrow) InputClientStub();
121 if (client == nullptr) {
122 IMSA_HILOGE("failed to create client");
123 return ErrorCode::ERROR_NULL_POINTER;
124 }
125 sptr<IInputDataChannel> channel = new (std::nothrow) InputDataChannelStub();
126 if (channel == nullptr) {
127 IMSA_HILOGE("failed to new channel!");
128 return ErrorCode::ERROR_NULL_POINTER;
129 }
130 InputAttribute attribute = { .inputPattern = InputAttribute::PATTERN_TEXT };
131 clientInfo_ = { .attribute = attribute, .client = client, .channel = channel->AsObject() };
132
133 // make AppExecFwk::EventHandler handler
134 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
135 return ErrorCode::NO_ERROR;
136 }
137
GetSystemAbilityProxy()138 sptr<IInputMethodSystemAbility> InputMethodController::GetSystemAbilityProxy()
139 {
140 std::lock_guard<std::mutex> lock(abilityLock_);
141 if (abilityManager_ != nullptr) {
142 return abilityManager_;
143 }
144 IMSA_HILOGI("get input method service proxy.");
145 sptr<ISystemAbilityManager> systemAbilityManager =
146 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
147 if (systemAbilityManager == nullptr) {
148 IMSA_HILOGE("system ability manager is nullptr!");
149 return nullptr;
150 }
151 auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, "");
152 if (systemAbility == nullptr) {
153 IMSA_HILOGE("system ability is nullptr!");
154 return nullptr;
155 }
156 if (deathRecipient_ == nullptr) {
157 deathRecipient_ = new (std::nothrow) InputDeathRecipient();
158 if (deathRecipient_ == nullptr) {
159 IMSA_HILOGE("create death recipient failed!");
160 return nullptr;
161 }
162 }
163 deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) { OnRemoteSaDied(remote); });
164 if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
165 IMSA_HILOGE("failed to add death recipient!");
166 return nullptr;
167 }
168 abilityManager_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
169 return abilityManager_;
170 }
171
RemoveDeathRecipient()172 void InputMethodController::RemoveDeathRecipient()
173 {
174 std::lock_guard<std::mutex> lock(abilityLock_);
175 if (abilityManager_ != nullptr && abilityManager_->AsObject() != nullptr && deathRecipient_ != nullptr) {
176 abilityManager_->AsObject()->RemoveDeathRecipient(deathRecipient_);
177 }
178 deathRecipient_ = nullptr;
179 abilityManager_ = nullptr;
180 }
181
DeactivateClient()182 void InputMethodController::DeactivateClient()
183 {
184 {
185 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
186 clientInfo_.state = ClientState::INACTIVE;
187 }
188 SendKeyboardStatus(KeyboardStatus::NONE);
189 }
190
SaveTextConfig(const TextConfig & textConfig)191 void InputMethodController::SaveTextConfig(const TextConfig &textConfig)
192 {
193 IMSA_HILOGD("textConfig: %{public}s.", textConfig.ToString().c_str());
194 {
195 std::lock_guard<std::mutex> lock(textConfigLock_);
196 textConfig_ = textConfig;
197 }
198 if (textConfig.range.start != INVALID_VALUE) {
199 std::lock_guard<std::mutex> lock(editorContentLock_);
200 selectOldBegin_ = selectNewBegin_;
201 selectOldEnd_ = selectNewEnd_;
202 selectNewBegin_ = textConfig.range.start;
203 selectNewEnd_ = textConfig.range.end;
204 }
205 }
206
Attach(sptr<OnTextChangedListener> listener)207 int32_t InputMethodController::Attach(sptr<OnTextChangedListener> listener)
208 {
209 return Attach(listener, true);
210 }
211
Attach(sptr<OnTextChangedListener> listener,bool isShowKeyboard)212 int32_t InputMethodController::Attach(sptr<OnTextChangedListener> listener, bool isShowKeyboard)
213 {
214 InputAttribute attribute;
215 attribute.inputPattern = InputAttribute::PATTERN_TEXT;
216 return Attach(listener, isShowKeyboard, attribute);
217 }
218
Attach(sptr<OnTextChangedListener> listener,bool isShowKeyboard,const InputAttribute & attribute)219 int32_t InputMethodController::Attach(sptr<OnTextChangedListener> listener, bool isShowKeyboard,
220 const InputAttribute &attribute)
221 {
222 InputMethodSyncTrace tracer("InputMethodController Attach trace.");
223 TextConfig textConfig;
224 textConfig.inputAttribute = attribute;
225 return Attach(listener, isShowKeyboard, textConfig);
226 }
227
Attach(sptr<OnTextChangedListener> listener,bool isShowKeyboard,const TextConfig & textConfig)228 int32_t InputMethodController::Attach(sptr<OnTextChangedListener> listener, bool isShowKeyboard,
229 const TextConfig &textConfig)
230 {
231 IMSA_HILOGI("isShowKeyboard %{public}d.", isShowKeyboard);
232 InputMethodSyncTrace tracer("InputMethodController Attach with textConfig trace.");
233 auto lastListener = GetTextListener();
234 clientInfo_.isNotifyInputStart = lastListener != listener;
235 if (clientInfo_.isNotifyInputStart && lastListener != nullptr) {
236 lastListener->OnDetach();
237 }
238 ClearEditorCache(clientInfo_.isNotifyInputStart, lastListener);
239 SetTextListener(listener);
240 {
241 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
242 clientInfo_.isShowKeyboard = isShowKeyboard;
243 }
244 SaveTextConfig(textConfig);
245 GetTextConfig(clientInfo_.config);
246
247 sptr<IRemoteObject> agent = nullptr;
248 int32_t ret = StartInput(clientInfo_, agent);
249 if (ret != ErrorCode::NO_ERROR) {
250 IMSA_HILOGE("failed to start input, ret: %{public}d", ret);
251 return ret;
252 }
253 clientInfo_.state = ClientState::ACTIVE;
254 OnInputReady(agent);
255 if (isShowKeyboard) {
256 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_ATTACH);
257 }
258 IMSA_HILOGI("bind imf successfully.");
259 return ErrorCode::NO_ERROR;
260 }
261
ShowTextInput()262 int32_t InputMethodController::ShowTextInput()
263 {
264 InputMethodSyncTrace tracer("IMC_ShowTextInput");
265 if (!IsBound()) {
266 IMSA_HILOGE("not bound.");
267 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
268 }
269 IMSA_HILOGI("start.");
270 {
271 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
272 clientInfo_.isShowKeyboard = true;
273 }
274 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_ENEDITABLE);
275 int32_t ret = ShowInput(clientInfo_.client);
276 if (ret != ErrorCode::NO_ERROR) {
277 IMSA_HILOGE("failed to start input: %{public}d", ret);
278 return ret;
279 }
280 isEditable_.store(true);
281 IMSA_HILOGI("enter editable state.");
282 return ret;
283 }
284
HideTextInput()285 int32_t InputMethodController::HideTextInput()
286 {
287 InputMethodSyncTrace tracer("IMC_HideTextInput");
288 if (!IsBound()) {
289 IMSA_HILOGE("not bound!");
290 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
291 }
292 IMSA_HILOGI("start.");
293 isEditable_.store(false);
294 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNEDITABLE);
295 return HideInput(clientInfo_.client);
296 }
297
HideCurrentInput()298 int32_t InputMethodController::HideCurrentInput()
299 {
300 InputMethodSyncTrace tracer("IMC_HideCurrentInput");
301 IMSA_HILOGD("InputMethodController::HideCurrentInput");
302 if (!IsEditable()) {
303 IMSA_HILOGD("not editable.");
304 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
305 }
306 auto proxy = GetSystemAbilityProxy();
307 if (proxy == nullptr) {
308 IMSA_HILOGE("proxy is nullptr!");
309 return ErrorCode::ERROR_EX_NULL_POINTER;
310 }
311 {
312 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
313 clientInfo_.isShowKeyboard = false;
314 }
315 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL);
316 return proxy->HideCurrentInputDeprecated();
317 }
318
ShowCurrentInput()319 int32_t InputMethodController::ShowCurrentInput()
320 {
321 InputMethodSyncTrace tracer("IMC_ShowCurrentInput");
322 if (!IsEditable()) {
323 IMSA_HILOGD("not editable.");
324 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
325 }
326 auto proxy = GetSystemAbilityProxy();
327 if (proxy == nullptr) {
328 IMSA_HILOGE("proxy is nullptr!");
329 return ErrorCode::ERROR_EX_NULL_POINTER;
330 }
331 IMSA_HILOGI("start.");
332 {
333 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
334 clientInfo_.isShowKeyboard = true;
335 }
336 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL);
337 return proxy->ShowCurrentInputDeprecated();
338 }
339
Close()340 int32_t InputMethodController::Close()
341 {
342 if (IsBound()) {
343 IMSA_HILOGI("start.");
344 }
345
346 auto listener = GetTextListener();
347 if (listener != nullptr) {
348 listener->OnDetach();
349 }
350 OperateIMEInfoCode infoCode = OperateIMEInfoCode::IME_UNBIND;
351 {
352 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
353 infoCode = clientInfo_.isShowKeyboard ? OperateIMEInfoCode::IME_HIDE_UNBIND : OperateIMEInfoCode::IME_UNBIND;
354 }
355 InputMethodSyncTrace tracer("InputMethodController Close trace.");
356 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(infoCode);
357 return ReleaseInput(clientInfo_.client);
358 }
359
Reset()360 void InputMethodController::Reset()
361 {
362 Close();
363 RemoveDeathRecipient();
364 }
365
RequestShowInput()366 int32_t InputMethodController::RequestShowInput()
367 {
368 auto proxy = GetSystemAbilityProxy();
369 if (proxy == nullptr) {
370 IMSA_HILOGE("proxy is nullptr!");
371 return ErrorCode::ERROR_EX_NULL_POINTER;
372 }
373 IMSA_HILOGI("InputMethodController start.");
374 return proxy->RequestShowInput();
375 }
376
RequestHideInput()377 int32_t InputMethodController::RequestHideInput()
378 {
379 auto proxy = GetSystemAbilityProxy();
380 if (proxy == nullptr) {
381 IMSA_HILOGE("proxy is nullptr!");
382 return ErrorCode::ERROR_EX_NULL_POINTER;
383 }
384 IMSA_HILOGD("InputMethodController start.");
385 return proxy->RequestHideInput();
386 }
387
DisplayOptionalInputMethod()388 int32_t InputMethodController::DisplayOptionalInputMethod()
389 {
390 IMSA_HILOGD("InputMethodController::DisplayOptionalInputMethod start.");
391 auto proxy = GetSystemAbilityProxy();
392 if (proxy == nullptr) {
393 IMSA_HILOGE("proxy is nullptr!");
394 return ErrorCode::ERROR_EX_NULL_POINTER;
395 }
396 return proxy->DisplayOptionalInputMethod();
397 }
398
WasAttached()399 bool InputMethodController::WasAttached()
400 {
401 return isBound_.load();
402 }
403
ListInputMethodCommon(InputMethodStatus status,std::vector<Property> & props)404 int32_t InputMethodController::ListInputMethodCommon(InputMethodStatus status, std::vector<Property> &props)
405 {
406 IMSA_HILOGD("InputMethodController::ListInputMethodCommon start.");
407 auto proxy = GetSystemAbilityProxy();
408 if (proxy == nullptr) {
409 IMSA_HILOGE("proxy is nullptr!");
410 return ErrorCode::ERROR_EX_NULL_POINTER;
411 }
412 return proxy->ListInputMethod(status, props);
413 }
414
ListInputMethod(std::vector<Property> & props)415 int32_t InputMethodController::ListInputMethod(std::vector<Property> &props)
416 {
417 IMSA_HILOGD("InputMethodController::listInputMethod start.");
418 return ListInputMethodCommon(ALL, props);
419 }
420
ListInputMethod(bool enable,std::vector<Property> & props)421 int32_t InputMethodController::ListInputMethod(bool enable, std::vector<Property> &props)
422 {
423 IMSA_HILOGI("enable: %{public}s.", enable ? "ENABLE" : "DISABLE");
424 return ListInputMethodCommon(enable ? ENABLE : DISABLE, props);
425 }
426
GetDefaultInputMethod(std::shared_ptr<Property> & property)427 int32_t InputMethodController::GetDefaultInputMethod(std::shared_ptr<Property> &property)
428 {
429 InputMethodSyncTrace tracer("IMC_GetDefaultInputMethod");
430 IMSA_HILOGD("InputMethodController::GetDefaultInputMethod start.");
431 auto proxy = GetSystemAbilityProxy();
432 if (proxy == nullptr) {
433 IMSA_HILOGE("proxy is nullptr!");
434 return ErrorCode::ERROR_SERVICE_START_FAILED;
435 }
436 return proxy->GetDefaultInputMethod(property, false);
437 }
438
GetInputMethodConfig(OHOS::AppExecFwk::ElementName & inputMethodConfig)439 int32_t InputMethodController::GetInputMethodConfig(OHOS::AppExecFwk::ElementName &inputMethodConfig)
440 {
441 InputMethodSyncTrace tracer("IMC_GetInputMethodConfig");
442 IMSA_HILOGD("InputMethodController::inputMethodConfig start.");
443 auto proxy = GetSystemAbilityProxy();
444 if (proxy == nullptr) {
445 IMSA_HILOGE("proxy is nullptr!");
446 return ErrorCode::ERROR_SERVICE_START_FAILED;
447 }
448 return proxy->GetInputMethodConfig(inputMethodConfig);
449 }
450
GetCurrentInputMethod()451 std::shared_ptr<Property> InputMethodController::GetCurrentInputMethod()
452 {
453 InputMethodSyncTrace tracer("IMC_GetCurrentInputMethod");
454 IMSA_HILOGD("InputMethodController::GetCurrentInputMethod start.");
455 auto proxy = GetSystemAbilityProxy();
456 if (proxy == nullptr) {
457 IMSA_HILOGE("proxy is nullptr!");
458 return nullptr;
459 }
460 auto property = proxy->GetCurrentInputMethod();
461 if (property == nullptr) {
462 IMSA_HILOGE("property is nullptr!");
463 return nullptr;
464 }
465 return property;
466 }
467
GetCurrentInputMethodSubtype()468 std::shared_ptr<SubProperty> InputMethodController::GetCurrentInputMethodSubtype()
469 {
470 InputMethodSyncTrace tracer("IMC_GetCurrentInputMethodSubtype");
471 IMSA_HILOGD("InputMethodController::GetCurrentInputMethodSubtype start.");
472 auto proxy = GetSystemAbilityProxy();
473 if (proxy == nullptr) {
474 IMSA_HILOGE("proxy is nullptr!");
475 return nullptr;
476 }
477 auto property = proxy->GetCurrentInputMethodSubtype();
478 if (property == nullptr) {
479 IMSA_HILOGE("property is nullptr!");
480 return nullptr;
481 }
482 return property;
483 }
484
IsDefaultImeSet()485 bool InputMethodController::IsDefaultImeSet()
486 {
487 IMSA_HILOGI("enter.");
488 auto proxy = GetSystemAbilityProxy();
489 if (proxy == nullptr) {
490 IMSA_HILOGE("proxy is nullptr!");
491 return false;
492 }
493 return proxy->IsDefaultImeSet();
494 }
495
EnableIme(const std::string & bundleName)496 bool InputMethodController::EnableIme(const std::string &bundleName)
497 {
498 IMSA_HILOGI("enter.");
499 auto proxy = GetSystemAbilityProxy();
500 if (proxy == nullptr) {
501 IMSA_HILOGE("proxy is nullptr!");
502 return false;
503 }
504 return proxy->EnableIme(bundleName);
505 }
506
StartInput(InputClientInfo & inputClientInfo,sptr<IRemoteObject> & agent)507 int32_t InputMethodController::StartInput(InputClientInfo &inputClientInfo, sptr<IRemoteObject> &agent)
508 {
509 IMSA_HILOGD("InputMethodController::StartInput start.");
510 auto proxy = GetSystemAbilityProxy();
511 if (proxy == nullptr) {
512 IMSA_HILOGE("proxy is nullptr!");
513 return ErrorCode::ERROR_SERVICE_START_FAILED;
514 }
515 return proxy->StartInput(inputClientInfo, agent);
516 }
517
ReleaseInput(sptr<IInputClient> & client)518 int32_t InputMethodController::ReleaseInput(sptr<IInputClient> &client)
519 {
520 IMSA_HILOGD("InputMethodController::ReleaseInput start.");
521 auto proxy = GetSystemAbilityProxy();
522 if (proxy == nullptr) {
523 IMSA_HILOGE("proxy is nullptr!");
524 return ErrorCode::ERROR_SERVICE_START_FAILED;
525 }
526 int32_t ret = proxy->ReleaseInput(client);
527 if (ret == ErrorCode::NO_ERROR) {
528 OnInputStop();
529 }
530 SetTextListener(nullptr);
531 return ret;
532 }
533
ShowInput(sptr<IInputClient> & client)534 int32_t InputMethodController::ShowInput(sptr<IInputClient> &client)
535 {
536 IMSA_HILOGD("InputMethodController::ShowInput start.");
537 auto proxy = GetSystemAbilityProxy();
538 if (proxy == nullptr) {
539 IMSA_HILOGE("proxy is nullptr!");
540 return ErrorCode::ERROR_SERVICE_START_FAILED;
541 }
542 return proxy->ShowInput(client);
543 }
544
HideInput(sptr<IInputClient> & client)545 int32_t InputMethodController::HideInput(sptr<IInputClient> &client)
546 {
547 IMSA_HILOGD("InputMethodController::HideInput start.");
548 auto proxy = GetSystemAbilityProxy();
549 if (proxy == nullptr) {
550 IMSA_HILOGE("proxy is nullptr!");
551 return ErrorCode::ERROR_SERVICE_START_FAILED;
552 }
553 return proxy->HideInput(client);
554 }
555
OnRemoteSaDied(const wptr<IRemoteObject> & remote)556 void InputMethodController::OnRemoteSaDied(const wptr<IRemoteObject> &remote)
557 {
558 IMSA_HILOGI("input method service death.");
559 auto textListener = GetTextListener();
560 if (textListener != nullptr && textConfig_.inputAttribute.isTextPreviewSupported) {
561 IMSA_HILOGD("finish text preview.");
562 textListener->FinishTextPreview();
563 }
564 {
565 std::lock_guard<std::mutex> lock(abilityLock_);
566 abilityManager_ = nullptr;
567 }
568 if (handler_ == nullptr) {
569 IMSA_HILOGE("handler_ is nullptr!");
570 return;
571 }
572 RestoreListenInfoInSaDied();
573 RestoreAttachInfoInSaDied();
574 }
575
RestoreListenInfoInSaDied()576 void InputMethodController::RestoreListenInfoInSaDied()
577 {
578 {
579 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
580 if (clientInfo_.eventFlag == NO_EVENT_ON) {
581 return;
582 }
583 }
584 isDiedRestoreListen_.store(false);
585 auto restoreListenTask = [=]() {
586 if (isDiedRestoreListen_.load()) {
587 return;
588 }
589 auto ret = RestoreListenEventFlag();
590 if (ret == ErrorCode::NO_ERROR) {
591 isDiedRestoreListen_.store(true);
592 IMSA_HILOGI("try to RestoreListen success.");
593 }
594 };
595 for (int i = 0; i < LOOP_COUNT; i++) {
596 handler_->PostTask(restoreListenTask, "OnRemoteSaDied", DELAY_TIME * (i + 1));
597 }
598 }
599
RestoreAttachInfoInSaDied()600 void InputMethodController::RestoreAttachInfoInSaDied()
601 {
602 if (!IsEditable()) {
603 IMSA_HILOGD("not editable.");
604 return;
605 }
606 auto attach = [=]() -> bool {
607 TextConfig tempConfig{};
608 {
609 std::lock_guard<std::mutex> lock(textConfigLock_);
610 tempConfig = textConfig_;
611 tempConfig.cursorInfo = cursorInfo_;
612 tempConfig.range.start = selectNewBegin_;
613 tempConfig.range.end = selectNewEnd_;
614 }
615 auto listener = GetTextListener();
616 bool isShowKeyboard = false;
617 {
618 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
619 isShowKeyboard = clientInfo_.isShowKeyboard;
620 }
621 auto errCode = Attach(listener, isShowKeyboard, tempConfig);
622 IMSA_HILOGI("attach end, errCode: %{public}d", errCode);
623 return errCode == ErrorCode::NO_ERROR;
624 };
625 if (attach()) {
626 return;
627 }
628 isDiedAttached_.store(false);
629 auto attachTask = [this, attach]() {
630 if (isDiedAttached_.load()) {
631 return;
632 }
633 attach();
634 };
635 for (int i = 0; i < LOOP_COUNT; i++) {
636 handler_->PostTask(attachTask, "OnRemoteSaDied", DELAY_TIME * (i + 1));
637 }
638 }
639
OnCursorUpdate(CursorInfo cursorInfo)640 int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo)
641 {
642 if (!IsBound()) {
643 IMSA_HILOGD("not bound.");
644 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
645 }
646 if (!IsEditable()) {
647 IMSA_HILOGD("not editable.");
648 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
649 }
650 {
651 std::lock_guard<std::mutex> lock(textConfigLock_);
652 textConfig_.cursorInfo = cursorInfo;
653 }
654 {
655 std::lock_guard<std::mutex> lk(cursorInfoMutex_);
656 if (cursorInfo_ == cursorInfo) {
657 IMSA_HILOGD("same to last update.");
658 return ErrorCode::NO_ERROR;
659 }
660 cursorInfo_ = cursorInfo;
661 }
662 auto agent = GetAgent();
663 if (agent == nullptr) {
664 IMSA_HILOGE("agent is nullptr!");
665 return ErrorCode::ERROR_IME_NOT_STARTED;
666 }
667 IMSA_HILOGI("left: %{public}d, top: %{public}d, height: %{public}d.", static_cast<int32_t>(cursorInfo.left),
668 static_cast<int32_t>(cursorInfo.top), static_cast<int32_t>(cursorInfo.height));
669 agent->OnCursorUpdate(cursorInfo.left, cursorInfo.top, cursorInfo.height);
670 return ErrorCode::NO_ERROR;
671 }
672
OnSelectionChange(std::u16string text,int start,int end)673 int32_t InputMethodController::OnSelectionChange(std::u16string text, int start, int end)
674 {
675 if (!IsBound()) {
676 IMSA_HILOGD("not bound.");
677 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
678 }
679 if (!IsEditable()) {
680 IMSA_HILOGD("not editable.");
681 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
682 }
683 {
684 std::lock_guard<std::mutex> lock(textConfigLock_);
685 textConfig_.range = { start, end };
686 }
687 if (textString_ == text && selectNewBegin_ == start && selectNewEnd_ == end) {
688 IMSA_HILOGD("same to last update.");
689 return ErrorCode::NO_ERROR;
690 }
691 textString_ = text;
692 selectOldBegin_ = selectNewBegin_;
693 selectOldEnd_ = selectNewEnd_;
694 selectNewBegin_ = start;
695 selectNewEnd_ = end;
696 auto agent = GetAgent();
697 if (agent == nullptr) {
698 IMSA_HILOGE("agent is nullptr!");
699 return ErrorCode::ERROR_IME_NOT_STARTED;
700 }
701 IMSA_HILOGI("IMC size: %{public}zu, range: %{public}d/%{public}d/%{public}d/%{public}d.", text.size(),
702 selectOldBegin_, selectOldEnd_, start, end);
703 agent->OnSelectionChange(textString_, selectOldBegin_, selectOldEnd_, selectNewBegin_, selectNewEnd_);
704 return ErrorCode::NO_ERROR;
705 }
706
OnConfigurationChange(Configuration info)707 int32_t InputMethodController::OnConfigurationChange(Configuration info)
708 {
709 if (!IsBound()) {
710 IMSA_HILOGD("not bound.");
711 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
712 }
713 InputAttribute attribute;
714 {
715 std::lock_guard<std::mutex> lock(textConfigLock_);
716 textConfig_.inputAttribute.enterKeyType = static_cast<int32_t>(info.GetEnterKeyType());
717 textConfig_.inputAttribute.inputPattern = static_cast<int32_t>(info.GetTextInputType());
718 attribute = textConfig_.inputAttribute;
719 }
720 if (!IsEditable()) {
721 IMSA_HILOGD("not editable.");
722 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
723 }
724 IMSA_HILOGI("IMC enterKeyType: %{public}d, textInputType: %{public}d.", attribute.enterKeyType,
725 attribute.inputPattern);
726 auto agent = GetAgent();
727 if (agent == nullptr) {
728 IMSA_HILOGE("agent is nullptr!");
729 return ErrorCode::ERROR_IME_NOT_STARTED;
730 }
731 agent->OnAttributeChange(attribute);
732 return ErrorCode::NO_ERROR;
733 }
734
GetLeft(int32_t length,std::u16string & text)735 int32_t InputMethodController::GetLeft(int32_t length, std::u16string &text)
736 {
737 InputMethodSyncTrace tracer("IMC_GetForward");
738 IMSA_HILOGD("start, length: %{public}d", length);
739 auto listener = GetTextListener();
740 if (!IsEditable() || listener == nullptr) {
741 IMSA_HILOGE("not editable or listener is nullptr!");
742 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
743 }
744 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
745 {
746 InputMethodSyncTrace aceTracer("ACE_GetForward");
747 text = listener->GetLeftTextOfCursor(length);
748 }
749 PrintLogIfAceTimeout(start);
750 return ErrorCode::NO_ERROR;
751 }
752
GetRight(int32_t length,std::u16string & text)753 int32_t InputMethodController::GetRight(int32_t length, std::u16string &text)
754 {
755 IMSA_HILOGD("start, length: %{public}d", length);
756 auto listener = GetTextListener();
757 if (!IsEditable() || listener == nullptr) {
758 IMSA_HILOGE("not editable or textListener_ is nullptr!");
759 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
760 }
761 text = listener->GetRightTextOfCursor(length);
762 return ErrorCode::NO_ERROR;
763 }
764
GetTextIndexAtCursor(int32_t & index)765 int32_t InputMethodController::GetTextIndexAtCursor(int32_t &index)
766 {
767 IMSA_HILOGD("start.");
768 auto listener = GetTextListener();
769 if (!IsEditable() || listener == nullptr) {
770 IMSA_HILOGE("not editable or textListener_ is nullptr!");
771 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
772 }
773 index = listener->GetTextIndexAtCursor();
774 return ErrorCode::NO_ERROR;
775 }
776
PrintKeyEventLog()777 void InputMethodController::PrintKeyEventLog()
778 {
779 std::lock_guard<std::mutex> lock(logLock_);
780 auto now = system_clock::now();
781 if (keyEventCountInPeriod_ == 0) {
782 startLogTime_ = now;
783 }
784 keyEventCountInPeriod_++;
785 if (std::chrono::duration_cast<seconds>(now - startLogTime_).count() >= LOG_MAX_TIME) {
786 auto start = std::chrono::duration_cast<seconds>(startLogTime_.time_since_epoch()).count();
787 auto end = std::chrono::duration_cast<seconds>(now.time_since_epoch()).count();
788 IMSA_HILOGI("KeyEventCountInPeriod: %{public}d, startTime: %{public}lld, endTime: %{public}lld",
789 keyEventCountInPeriod_, start, end);
790 keyEventCountInPeriod_ = 0;
791 }
792 }
793
DispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent,KeyEventCallback callback)794 int32_t InputMethodController::DispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent, KeyEventCallback callback)
795 {
796 PrintKeyEventLog();
797 KeyEventInfo keyEventInfo = { std::chrono::system_clock::now(), keyEvent };
798 keyEventQueue_.Push(keyEventInfo);
799 InputMethodSyncTrace tracer("DispatchKeyEvent trace");
800 keyEventQueue_.Wait(keyEventInfo);
801 if (!IsEditable()) {
802 IMSA_HILOGD("not editable.");
803 keyEventQueue_.Pop();
804 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
805 }
806 if (keyEvent == nullptr) {
807 IMSA_HILOGE("keyEvent is nullptr!");
808 keyEventQueue_.Pop();
809 return ErrorCode::ERROR_EX_NULL_POINTER;
810 }
811 auto agent = GetAgent();
812 if (agent == nullptr) {
813 IMSA_HILOGE("agent is nullptr!");
814 keyEventQueue_.Pop();
815 return ErrorCode::ERROR_IME_NOT_STARTED;
816 }
817 IMSA_HILOGD("start.");
818 sptr<IKeyEventConsumer> consumer = new (std::nothrow) KeyEventConsumerStub(callback, keyEvent);
819 if (consumer == nullptr) {
820 IMSA_HILOGE("consumer is nullptr!");
821 keyEventQueue_.Pop();
822 return ErrorCode::ERROR_EX_NULL_POINTER;
823 }
824 auto ret = agent->DispatchKeyEvent(keyEvent, consumer);
825 if (ret != ErrorCode::NO_ERROR) {
826 IMSA_HILOGE("failed to DispatchKeyEvent: %{public}d", ret);
827 }
828 keyEventQueue_.Pop();
829 return ret;
830 }
831
GetEnterKeyType(int32_t & keyType)832 int32_t InputMethodController::GetEnterKeyType(int32_t &keyType)
833 {
834 IMSA_HILOGD("InputMethodController::GetEnterKeyType start.");
835 std::lock_guard<std::mutex> lock(textConfigLock_);
836 keyType = textConfig_.inputAttribute.enterKeyType;
837 return ErrorCode::NO_ERROR;
838 }
839
GetInputPattern(int32_t & inputpattern)840 int32_t InputMethodController::GetInputPattern(int32_t &inputpattern)
841 {
842 IMSA_HILOGD("InputMethodController::GetInputPattern start.");
843 std::lock_guard<std::mutex> lock(textConfigLock_);
844 inputpattern = textConfig_.inputAttribute.inputPattern;
845 return ErrorCode::NO_ERROR;
846 }
847
GetTextConfig(TextTotalConfig & config)848 int32_t InputMethodController::GetTextConfig(TextTotalConfig &config)
849 {
850 std::lock_guard<std::mutex> lock(textConfigLock_);
851 config.inputAttribute = textConfig_.inputAttribute;
852 config.cursorInfo = textConfig_.cursorInfo;
853 config.windowId = textConfig_.windowId;
854 config.positionY = textConfig_.positionY;
855 config.height = textConfig_.height;
856 config.privateCommand = textConfig_.privateCommand;
857 if (textConfig_.range.start == INVALID_VALUE) {
858 IMSA_HILOGD("SelectionRange is invalid.");
859 } else {
860 {
861 std::lock_guard<std::mutex> editorLock(editorContentLock_);
862 config.textSelection.oldBegin = selectOldBegin_;
863 config.textSelection.oldEnd = selectOldEnd_;
864 }
865 config.textSelection.newBegin = textConfig_.range.start;
866 config.textSelection.newEnd = textConfig_.range.end;
867 }
868 IMSA_HILOGD("textConfig: %{public}s.", config.ToString().c_str());
869 return ErrorCode::NO_ERROR;
870 }
871
SetCallingWindow(uint32_t windowId)872 int32_t InputMethodController::SetCallingWindow(uint32_t windowId)
873 {
874 if (!IsBound()) {
875 IMSA_HILOGD("not bound.");
876 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
877 }
878 if (!IsEditable()) {
879 IMSA_HILOGD("not editable.");
880 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
881 }
882 {
883 std::lock_guard<std::mutex> lock(textConfigLock_);
884 textConfig_.windowId = windowId;
885 }
886 auto agent = GetAgent();
887 if (agent == nullptr) {
888 IMSA_HILOGE("agent is nullptr!");
889 return ErrorCode::ERROR_IME_NOT_STARTED;
890 }
891 IMSA_HILOGI("windowId: %{public}d.", windowId);
892 agent->SetCallingWindow(windowId);
893 return ErrorCode::NO_ERROR;
894 }
895
ShowSoftKeyboard()896 int32_t InputMethodController::ShowSoftKeyboard()
897 {
898 auto proxy = GetSystemAbilityProxy();
899 if (proxy == nullptr) {
900 IMSA_HILOGE("proxy is nullptr!");
901 return ErrorCode::ERROR_EX_NULL_POINTER;
902 }
903 IMSA_HILOGI("start.");
904 {
905 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
906 clientInfo_.isShowKeyboard = true;
907 }
908 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL);
909 return proxy->ShowCurrentInput();
910 }
911
HideSoftKeyboard()912 int32_t InputMethodController::HideSoftKeyboard()
913 {
914 auto proxy = GetSystemAbilityProxy();
915 if (proxy == nullptr) {
916 IMSA_HILOGE("proxy is nullptr!");
917 return ErrorCode::ERROR_EX_NULL_POINTER;
918 }
919 IMSA_HILOGI("start.");
920 {
921 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
922 clientInfo_.isShowKeyboard = false;
923 }
924 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL);
925 return proxy->HideCurrentInput();
926 }
927
StopInputSession()928 int32_t InputMethodController::StopInputSession()
929 {
930 IMSA_HILOGI("start.");
931 isEditable_.store(false);
932 auto proxy = GetSystemAbilityProxy();
933 if (proxy == nullptr) {
934 IMSA_HILOGE("proxy is nullptr!");
935 return ErrorCode::ERROR_EX_NULL_POINTER;
936 }
937 return proxy->StopInputSession();
938 }
939
ShowOptionalInputMethod()940 int32_t InputMethodController::ShowOptionalInputMethod()
941 {
942 auto proxy = GetSystemAbilityProxy();
943 if (proxy == nullptr) {
944 IMSA_HILOGE("proxy is nullptr!");
945 return ErrorCode::ERROR_EX_NULL_POINTER;
946 }
947 IMSA_HILOGI("IMC start.");
948 return proxy->DisplayOptionalInputMethod();
949 }
950
ListInputMethodSubtype(const Property & property,std::vector<SubProperty> & subProps)951 int32_t InputMethodController::ListInputMethodSubtype(const Property &property, std::vector<SubProperty> &subProps)
952 {
953 auto proxy = GetSystemAbilityProxy();
954 if (proxy == nullptr) {
955 IMSA_HILOGE("proxy is nullptr!");
956 return ErrorCode::ERROR_EX_NULL_POINTER;
957 }
958 IMSA_HILOGD("ime bundleName: %{public}s.", property.name.c_str());
959 return proxy->ListInputMethodSubtype(property.name, subProps);
960 }
961
ListCurrentInputMethodSubtype(std::vector<SubProperty> & subProps)962 int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps)
963 {
964 auto proxy = GetSystemAbilityProxy();
965 if (proxy == nullptr) {
966 IMSA_HILOGE("proxy is nullptr!");
967 return ErrorCode::ERROR_EX_NULL_POINTER;
968 }
969 IMSA_HILOGD("start.");
970 return proxy->ListCurrentInputMethodSubtype(subProps);
971 }
972
SwitchInputMethod(SwitchTrigger trigger,const std::string & name,const std::string & subName)973 int32_t InputMethodController::SwitchInputMethod(
974 SwitchTrigger trigger, const std::string &name, const std::string &subName)
975 {
976 InputMethodSyncTrace tracer("IMC_SwitchInputMethod");
977 auto proxy = GetSystemAbilityProxy();
978 if (proxy == nullptr) {
979 IMSA_HILOGE("proxy is nullptr!");
980 return ErrorCode::ERROR_EX_NULL_POINTER;
981 }
982 IMSA_HILOGI("name: %{public}s, subName: %{public}s, trigger: %{public}d.", name.c_str(), subName.c_str(),
983 static_cast<uint32_t>(trigger));
984 return proxy->SwitchInputMethod(name, subName, trigger);
985 }
986
OnInputReady(sptr<IRemoteObject> agentObject)987 void InputMethodController::OnInputReady(sptr<IRemoteObject> agentObject)
988 {
989 IMSA_HILOGI("InputMethodController start.");
990 isBound_.store(true);
991 isEditable_.store(true);
992 if (agentObject == nullptr) {
993 IMSA_HILOGE("agentObject is nullptr!");
994 return;
995 }
996 SetAgent(agentObject);
997 }
998
OnInputStop(bool isStopInactiveClient)999 void InputMethodController::OnInputStop(bool isStopInactiveClient)
1000 {
1001 {
1002 std::lock_guard<std::mutex> autoLock(agentLock_);
1003 agent_ = nullptr;
1004 agentObject_ = nullptr;
1005 }
1006 auto listener = GetTextListener();
1007 if (listener != nullptr) {
1008 IMSA_HILOGD("listener is not nullptr!");
1009 if (textConfig_.inputAttribute.isTextPreviewSupported) {
1010 IMSA_HILOGD("finish text preview.");
1011 listener->FinishTextPreview();
1012 }
1013 if (!isStopInactiveClient || !listener->IsFromTs()) {
1014 listener->SendKeyboardStatus(KeyboardStatus::HIDE);
1015 }
1016 }
1017 isBound_.store(false);
1018 isEditable_.store(false);
1019 }
1020
ClearEditorCache(bool isNewEditor,sptr<OnTextChangedListener> lastListener)1021 void InputMethodController::ClearEditorCache(bool isNewEditor, sptr<OnTextChangedListener> lastListener)
1022 {
1023 IMSA_HILOGD("isNewEditor: %{public}d.", isNewEditor);
1024 if (isNewEditor && isBound_.load() && lastListener != nullptr
1025 && textConfig_.inputAttribute.isTextPreviewSupported) {
1026 IMSA_HILOGD("last editor FinishTextPreview");
1027 lastListener->FinishTextPreview();
1028 }
1029 {
1030 std::lock_guard<std::mutex> lock(editorContentLock_);
1031 // reset old range when editor changes or first attach
1032 if (isNewEditor || !isBound_.load()) {
1033 isTextNotified_.store(false);
1034 textString_ = Str8ToStr16("");
1035 selectOldBegin_ = INVALID_VALUE;
1036 selectOldEnd_ = INVALID_VALUE;
1037 selectNewBegin_ = INVALID_VALUE;
1038 selectNewEnd_ = INVALID_VALUE;
1039 }
1040 }
1041 {
1042 std::lock_guard<std::mutex> lock(textConfigLock_);
1043 textConfig_ = {};
1044 }
1045 {
1046 std::lock_guard<std::mutex> lock(cursorInfoMutex_);
1047 cursorInfo_ = {};
1048 }
1049 clientInfo_.config = {};
1050 }
1051
SelectByRange(int32_t start,int32_t end)1052 void InputMethodController::SelectByRange(int32_t start, int32_t end)
1053 {
1054 IMSA_HILOGD("InputMethodController start: %{public}d, end: %{public}d.", start, end);
1055 auto listener = GetTextListener();
1056 if (IsEditable() && listener != nullptr) {
1057 listener->HandleSetSelection(start, end);
1058 } else {
1059 IMSA_HILOGE("not editable or textListener_ is nullptr!");
1060 }
1061
1062 if (controllerListener_ != nullptr) {
1063 controllerListener_->OnSelectByRange(start, end);
1064 } else {
1065 IMSA_HILOGE("controllerListener_ is nullptr!");
1066 }
1067 }
1068
SelectByMovement(int32_t direction,int32_t cursorMoveSkip)1069 void InputMethodController::SelectByMovement(int32_t direction, int32_t cursorMoveSkip)
1070 {
1071 IMSA_HILOGD("InputMethodController start, direction: %{public}d, cursorMoveSkip: %{public}d", direction,
1072 cursorMoveSkip);
1073 auto listener = GetTextListener();
1074 if (IsEditable() && listener != nullptr) {
1075 listener->HandleSelect(CURSOR_DIRECTION_BASE_VALUE + direction, cursorMoveSkip);
1076 } else {
1077 IMSA_HILOGE("not editable or textListener_ is nullptr!");
1078 }
1079
1080 if (controllerListener_ != nullptr) {
1081 controllerListener_->OnSelectByMovement(direction);
1082 } else {
1083 IMSA_HILOGE("controllerListener_ is nullptr!");
1084 }
1085 }
1086
HandleExtendAction(int32_t action)1087 int32_t InputMethodController::HandleExtendAction(int32_t action)
1088 {
1089 IMSA_HILOGD("InputMethodController start, action: %{public}d.", action);
1090 auto listener = GetTextListener();
1091 if (!IsEditable() || listener == nullptr) {
1092 IMSA_HILOGE("not editable or textListener is nullptr!");
1093 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1094 }
1095 listener->HandleExtendAction(action);
1096 return ErrorCode::NO_ERROR;
1097 }
1098
GetTextListener()1099 sptr<OnTextChangedListener> InputMethodController::GetTextListener()
1100 {
1101 std::lock_guard<std::mutex> lock(textListenerLock_);
1102 return textListener_;
1103 }
1104
SetTextListener(sptr<OnTextChangedListener> listener)1105 void InputMethodController::SetTextListener(sptr<OnTextChangedListener> listener)
1106 {
1107 std::lock_guard<std::mutex> lock(textListenerLock_);
1108 textListener_ = listener;
1109 }
1110
IsEditable()1111 bool InputMethodController::IsEditable()
1112 {
1113 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
1114 if (clientInfo_.state != ClientState::ACTIVE) {
1115 IMSA_HILOGD("client is not active.");
1116 return false;
1117 }
1118 if (!isEditable_.load()) {
1119 IMSA_HILOGD("not in editable state.");
1120 return false;
1121 }
1122 return true;
1123 }
1124
IsBound()1125 bool InputMethodController::IsBound()
1126 {
1127 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
1128 if (clientInfo_.state != ClientState::ACTIVE) {
1129 IMSA_HILOGD("client is not active.");
1130 return false;
1131 }
1132 if (!isBound_.load()) {
1133 IMSA_HILOGD("not bound.");
1134 return false;
1135 }
1136 return true;
1137 }
1138
InsertText(const std::u16string & text)1139 int32_t InputMethodController::InsertText(const std::u16string &text)
1140 {
1141 InputMethodSyncTrace tracer("IMC_InsertText");
1142 IMSA_HILOGD("start.");
1143 auto listener = GetTextListener();
1144 if (!IsEditable() || listener == nullptr) {
1145 IMSA_HILOGE("not editable or textListener is nullptr!");
1146 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1147 }
1148 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
1149 {
1150 InputMethodSyncTrace aceTracer("ACE_InsertText");
1151 IMSA_HILOGD("ACE InsertText.");
1152 listener->InsertText(text);
1153 }
1154 PrintLogIfAceTimeout(start);
1155 return ErrorCode::NO_ERROR;
1156 }
1157
DeleteForward(int32_t length)1158 int32_t InputMethodController::DeleteForward(int32_t length)
1159 {
1160 InputMethodSyncTrace tracer("IMC_DeleteForward");
1161 IMSA_HILOGD("start, length: %{public}d.", length);
1162 auto listener = GetTextListener();
1163 if (!IsEditable() || listener == nullptr) {
1164 IMSA_HILOGE("not editable or textListener is nullptr!");
1165 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1166 }
1167 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
1168 {
1169 InputMethodSyncTrace aceTracer("ACE_DeleteForward");
1170 // reverse for compatibility
1171 listener->DeleteBackward(length);
1172 }
1173 PrintLogIfAceTimeout(start);
1174 return ErrorCode::NO_ERROR;
1175 }
1176
DeleteBackward(int32_t length)1177 int32_t InputMethodController::DeleteBackward(int32_t length)
1178 {
1179 IMSA_HILOGD("InputMethodController start, length: %{public}d.", length);
1180 auto listener = GetTextListener();
1181 if (!IsEditable() || listener == nullptr) {
1182 IMSA_HILOGE("not editable or textListener is nullptr!");
1183 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1184 }
1185 // reverse for compatibility
1186 listener->DeleteForward(length);
1187 return ErrorCode::NO_ERROR;
1188 }
1189
MoveCursor(Direction direction)1190 int32_t InputMethodController::MoveCursor(Direction direction)
1191 {
1192 IMSA_HILOGD("InputMethodController start, direction: %{public}d.", static_cast<int32_t>(direction));
1193 auto listener = GetTextListener();
1194 if (!IsEditable() || listener == nullptr) {
1195 IMSA_HILOGE("not editable or textListener_ is nullptr!");
1196 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1197 }
1198 listener->MoveCursor(direction);
1199 return ErrorCode::NO_ERROR;
1200 }
1201
SendKeyboardStatus(KeyboardStatus status)1202 void InputMethodController::SendKeyboardStatus(KeyboardStatus status)
1203 {
1204 IMSA_HILOGD("InputMethodController status: %{public}d.", static_cast<int32_t>(status));
1205 auto listener = GetTextListener();
1206 if (listener == nullptr) {
1207 IMSA_HILOGE("listener is nullptr!");
1208 return;
1209 }
1210 listener->SendKeyboardStatus(status);
1211 if (status == KeyboardStatus::HIDE) {
1212 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
1213 clientInfo_.isShowKeyboard = false;
1214 }
1215 }
1216
NotifyPanelStatusInfo(const PanelStatusInfo & info)1217 void InputMethodController::NotifyPanelStatusInfo(const PanelStatusInfo &info)
1218 {
1219 IMSA_HILOGD("InputMethodController start, type: %{public}d, flag: %{public}d, visible: %{public}d, trigger: "
1220 "%{public}d.",
1221 static_cast<PanelType>(info.panelInfo.panelType), static_cast<PanelFlag>(info.panelInfo.panelFlag),
1222 info.visible, static_cast<Trigger>(info.trigger));
1223 auto listener = GetTextListener();
1224 if (listener == nullptr) {
1225 IMSA_HILOGE("listener is nullptr!");
1226 return;
1227 }
1228 if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD) {
1229 info.visible ? SendKeyboardStatus(KeyboardStatus::SHOW)
1230 : SendKeyboardStatus(KeyboardStatus::HIDE);
1231 }
1232 listener->NotifyPanelStatusInfo(info);
1233 if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD
1234 && info.panelInfo.panelFlag != PanelFlag::FLG_CANDIDATE_COLUMN && !info.visible) {
1235 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
1236 clientInfo_.isShowKeyboard = false;
1237 }
1238 }
1239
NotifyKeyboardHeight(uint32_t height)1240 void InputMethodController::NotifyKeyboardHeight(uint32_t height)
1241 {
1242 IMSA_HILOGD("InputMethodController start, height: %{public}u.", height);
1243 auto listener = GetTextListener();
1244 if (listener == nullptr) {
1245 IMSA_HILOGE("listener is nullptr!");
1246 return;
1247 }
1248 listener->NotifyKeyboardHeight(height);
1249 }
1250
SendFunctionKey(int32_t functionKey)1251 int32_t InputMethodController::SendFunctionKey(int32_t functionKey)
1252 {
1253 IMSA_HILOGD("InputMethodController start, functionKey: %{public}d", static_cast<int32_t>(functionKey));
1254 auto listener = GetTextListener();
1255 if (!IsEditable() || listener == nullptr) {
1256 IMSA_HILOGE("not editable or listener is nullptr!");
1257 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1258 }
1259 FunctionKey funcKey;
1260 funcKey.SetEnterKeyType(static_cast<EnterKeyType>(functionKey));
1261 listener->SendFunctionKey(funcKey);
1262 return ErrorCode::NO_ERROR;
1263 }
1264
IsInputTypeSupported(InputType type)1265 bool InputMethodController::IsInputTypeSupported(InputType type)
1266 {
1267 auto proxy = GetSystemAbilityProxy();
1268 if (proxy == nullptr) {
1269 IMSA_HILOGE("proxy is nullptr!");
1270 return ErrorCode::ERROR_NULL_POINTER;
1271 }
1272 IMSA_HILOGI("type: %{public}d.", static_cast<int32_t>(type));
1273 return proxy->IsInputTypeSupported(type);
1274 }
1275
IsCurrentImeByPid(int32_t pid)1276 bool InputMethodController::IsCurrentImeByPid(int32_t pid)
1277 {
1278 auto proxy = GetSystemAbilityProxy();
1279 if (proxy == nullptr) {
1280 IMSA_HILOGE("proxy is nullptr!");
1281 return false;
1282 }
1283 return proxy->IsCurrentImeByPid(pid);
1284 }
1285
StartInputType(InputType type)1286 int32_t InputMethodController::StartInputType(InputType type)
1287 {
1288 auto proxy = GetSystemAbilityProxy();
1289 if (proxy == nullptr) {
1290 IMSA_HILOGE("proxy is nullptr!");
1291 return ErrorCode::ERROR_NULL_POINTER;
1292 }
1293 IMSA_HILOGI("type: %{public}d.", static_cast<int32_t>(type));
1294 return proxy->StartInputType(type);
1295 }
1296
IsPanelShown(const PanelInfo & panelInfo,bool & isShown)1297 int32_t InputMethodController::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
1298 {
1299 auto proxy = GetSystemAbilityProxy();
1300 if (proxy == nullptr) {
1301 IMSA_HILOGE("proxy is nullptr!");
1302 return ErrorCode::ERROR_NULL_POINTER;
1303 }
1304 IMSA_HILOGI("type: %{public}d, flag: %{public}d.", static_cast<int32_t>(panelInfo.panelType),
1305 static_cast<int32_t>(panelInfo.panelFlag));
1306 return proxy->IsPanelShown(panelInfo, isShown);
1307 }
1308
SetAgent(sptr<IRemoteObject> & agentObject)1309 void InputMethodController::SetAgent(sptr<IRemoteObject> &agentObject)
1310 {
1311 std::lock_guard<std::mutex> autoLock(agentLock_);
1312 if (agent_ != nullptr && agentObject_.GetRefPtr() == agentObject.GetRefPtr()) {
1313 IMSA_HILOGD("agent has already been set.");
1314 return;
1315 }
1316 agent_ = std::make_shared<InputMethodAgentProxy>(agentObject);
1317 agentObject_ = agentObject;
1318 }
1319
GetAgent()1320 std::shared_ptr<IInputMethodAgent> InputMethodController::GetAgent()
1321 {
1322 std::lock_guard<std::mutex> autoLock(agentLock_);
1323 return agent_;
1324 }
1325
PrintLogIfAceTimeout(int64_t start)1326 void InputMethodController::PrintLogIfAceTimeout(int64_t start)
1327 {
1328 int64_t end = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
1329 if (end - start > ACE_DEAL_TIME_OUT) {
1330 IMSA_HILOGW("timeout: [%{public}" PRId64 ", %{public}" PRId64 "].", start, end);
1331 }
1332 }
1333
ReceivePrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)1334 int32_t InputMethodController::ReceivePrivateCommand(
1335 const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
1336 {
1337 auto listener = GetTextListener();
1338 if (listener == nullptr) {
1339 IMSA_HILOGE("listener is nullptr.");
1340 return ErrorCode::ERROR_EX_NULL_POINTER;
1341 }
1342 IMSA_HILOGD("IMC in.");
1343 auto ret = listener->ReceivePrivateCommand(privateCommand);
1344 if (ret != ErrorCode::NO_ERROR) {
1345 IMSA_HILOGE("ReceivePrivateCommand err, ret: %{public}d!", ret);
1346 return ErrorCode::ERROR_TEXT_LISTENER_ERROR;
1347 }
1348 return ErrorCode::NO_ERROR;
1349 }
1350
SendPrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)1351 int32_t InputMethodController::SendPrivateCommand(
1352 const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
1353 {
1354 if (!IsBound()) {
1355 IMSA_HILOGD("not bound.");
1356 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
1357 }
1358 if (!IsEditable()) {
1359 IMSA_HILOGD("not editable.");
1360 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1361 }
1362 if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
1363 IMSA_HILOGE("invalid private command size!");
1364 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
1365 }
1366 auto agent = GetAgent();
1367 if (agent == nullptr) {
1368 IMSA_HILOGE("agent is nullptr!");
1369 return ErrorCode::ERROR_IME_NOT_STARTED;
1370 }
1371 IMSA_HILOGD("IMC start.");
1372 return agent->SendPrivateCommand(privateCommand);
1373 }
1374
SetPreviewText(const std::string & text,const Range & range)1375 int32_t InputMethodController::SetPreviewText(const std::string &text, const Range &range)
1376 {
1377 InputMethodSyncTrace tracer("IMC_SetPreviewText");
1378 IMSA_HILOGD("IMC start.");
1379 if (!textConfig_.inputAttribute.isTextPreviewSupported) {
1380 IMSA_HILOGE("text preview do not supported!");
1381 return ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED;
1382 }
1383 auto listener = GetTextListener();
1384 if (!IsEditable() || listener == nullptr) {
1385 IMSA_HILOGE("not editable or listener is nullptr!");
1386 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1387 }
1388 int32_t ret = 0;
1389 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
1390 {
1391 InputMethodSyncTrace aceTracer("ACE_SetPreviewText");
1392 ret = listener->SetPreviewText(Str8ToStr16(text), range);
1393 }
1394 PrintLogIfAceTimeout(start);
1395 if (ret != ErrorCode::NO_ERROR) {
1396 IMSA_HILOGE("failed to SetPreviewText: %{public}d!", ret);
1397 return ret == -1 ? ErrorCode::ERROR_INVALID_RANGE : ErrorCode::ERROR_TEXT_LISTENER_ERROR;
1398 }
1399 return ErrorCode::NO_ERROR;
1400 }
1401
FinishTextPreview()1402 int32_t InputMethodController::FinishTextPreview()
1403 {
1404 InputMethodSyncTrace tracer("IMC_FinishTextPreview");
1405 IMSA_HILOGD("IMC start.");
1406 if (!textConfig_.inputAttribute.isTextPreviewSupported) {
1407 IMSA_HILOGD("text preview do not supported!");
1408 return ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED;
1409 }
1410 auto listener = GetTextListener();
1411 if (!isBound_.load() || listener == nullptr) {
1412 IMSA_HILOGW("not bound or listener is nullptr!");
1413 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1414 }
1415 {
1416 InputMethodSyncTrace aceTracer("ACE_FinishTextPreview");
1417 listener->FinishTextPreview();
1418 }
1419 return ErrorCode::NO_ERROR;
1420 }
1421 } // namespace MiscServices
1422 } // namespace OHOS