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