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
StartInput(InputClientInfo & inputClientInfo,sptr<IRemoteObject> & agent)485 int32_t InputMethodController::StartInput(InputClientInfo &inputClientInfo, sptr<IRemoteObject> &agent)
486 {
487 IMSA_HILOGD("InputMethodController::StartInput start.");
488 auto proxy = GetSystemAbilityProxy();
489 if (proxy == nullptr) {
490 IMSA_HILOGE("proxy is nullptr!");
491 return ErrorCode::ERROR_SERVICE_START_FAILED;
492 }
493 return proxy->StartInput(inputClientInfo, agent);
494 }
495
ReleaseInput(sptr<IInputClient> & client)496 int32_t InputMethodController::ReleaseInput(sptr<IInputClient> &client)
497 {
498 IMSA_HILOGD("InputMethodController::ReleaseInput start.");
499 auto proxy = GetSystemAbilityProxy();
500 if (proxy == nullptr) {
501 IMSA_HILOGE("proxy is nullptr!");
502 return ErrorCode::ERROR_SERVICE_START_FAILED;
503 }
504 int32_t ret = proxy->ReleaseInput(client);
505 if (ret == ErrorCode::NO_ERROR) {
506 OnInputStop();
507 }
508 SetTextListener(nullptr);
509 return ret;
510 }
511
ShowInput(sptr<IInputClient> & client)512 int32_t InputMethodController::ShowInput(sptr<IInputClient> &client)
513 {
514 IMSA_HILOGD("InputMethodController::ShowInput start.");
515 auto proxy = GetSystemAbilityProxy();
516 if (proxy == nullptr) {
517 IMSA_HILOGE("proxy is nullptr!");
518 return ErrorCode::ERROR_SERVICE_START_FAILED;
519 }
520 return proxy->ShowInput(client);
521 }
522
HideInput(sptr<IInputClient> & client)523 int32_t InputMethodController::HideInput(sptr<IInputClient> &client)
524 {
525 IMSA_HILOGD("InputMethodController::HideInput start.");
526 auto proxy = GetSystemAbilityProxy();
527 if (proxy == nullptr) {
528 IMSA_HILOGE("proxy is nullptr!");
529 return ErrorCode::ERROR_SERVICE_START_FAILED;
530 }
531 return proxy->HideInput(client);
532 }
533
OnRemoteSaDied(const wptr<IRemoteObject> & remote)534 void InputMethodController::OnRemoteSaDied(const wptr<IRemoteObject> &remote)
535 {
536 IMSA_HILOGI("input method service death.");
537 auto textListener = GetTextListener();
538 if (textListener != nullptr && textConfig_.inputAttribute.isTextPreviewSupported) {
539 IMSA_HILOGD("finish text preview.");
540 textListener->FinishTextPreview();
541 }
542 {
543 std::lock_guard<std::mutex> lock(abilityLock_);
544 abilityManager_ = nullptr;
545 }
546 if (handler_ == nullptr) {
547 IMSA_HILOGE("handler_ is nullptr!");
548 return;
549 }
550 RestoreListenInfoInSaDied();
551 RestoreAttachInfoInSaDied();
552 }
553
RestoreListenInfoInSaDied()554 void InputMethodController::RestoreListenInfoInSaDied()
555 {
556 {
557 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
558 if (clientInfo_.eventFlag == NO_EVENT_ON) {
559 return;
560 }
561 }
562 isDiedRestoreListen_.store(false);
563 auto restoreListenTask = [=]() {
564 if (isDiedRestoreListen_.load()) {
565 return;
566 }
567 auto ret = RestoreListenEventFlag();
568 if (ret == ErrorCode::NO_ERROR) {
569 isDiedRestoreListen_.store(true);
570 IMSA_HILOGI("try to RestoreListen success.");
571 }
572 };
573 for (int i = 0; i < LOOP_COUNT; i++) {
574 handler_->PostTask(restoreListenTask, "OnRemoteSaDied", DELAY_TIME * (i + 1));
575 }
576 }
577
RestoreAttachInfoInSaDied()578 void InputMethodController::RestoreAttachInfoInSaDied()
579 {
580 if (!IsEditable()) {
581 IMSA_HILOGD("not editable.");
582 return;
583 }
584 auto attach = [=]() -> bool {
585 TextConfig tempConfig{};
586 {
587 std::lock_guard<std::mutex> lock(textConfigLock_);
588 tempConfig = textConfig_;
589 tempConfig.cursorInfo = cursorInfo_;
590 tempConfig.range.start = selectNewBegin_;
591 tempConfig.range.end = selectNewEnd_;
592 }
593 auto listener = GetTextListener();
594 bool isShowKeyboard = false;
595 {
596 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
597 isShowKeyboard = clientInfo_.isShowKeyboard;
598 }
599 auto errCode = Attach(listener, isShowKeyboard, tempConfig);
600 IMSA_HILOGI("attach end, errCode: %{public}d", errCode);
601 return errCode == ErrorCode::NO_ERROR;
602 };
603 if (attach()) {
604 return;
605 }
606 isDiedAttached_.store(false);
607 auto attachTask = [this, attach]() {
608 if (isDiedAttached_.load()) {
609 return;
610 }
611 attach();
612 };
613 for (int i = 0; i < LOOP_COUNT; i++) {
614 handler_->PostTask(attachTask, "OnRemoteSaDied", DELAY_TIME * (i + 1));
615 }
616 }
617
OnCursorUpdate(CursorInfo cursorInfo)618 int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo)
619 {
620 if (!IsBound()) {
621 IMSA_HILOGD("not bound.");
622 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
623 }
624 if (!IsEditable()) {
625 IMSA_HILOGD("not editable.");
626 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
627 }
628 {
629 std::lock_guard<std::mutex> lock(textConfigLock_);
630 textConfig_.cursorInfo = cursorInfo;
631 }
632 {
633 std::lock_guard<std::mutex> lk(cursorInfoMutex_);
634 if (cursorInfo_ == cursorInfo) {
635 IMSA_HILOGD("same to last update.");
636 return ErrorCode::NO_ERROR;
637 }
638 cursorInfo_ = cursorInfo;
639 }
640 auto agent = GetAgent();
641 if (agent == nullptr) {
642 IMSA_HILOGE("agent is nullptr!");
643 return ErrorCode::ERROR_IME_NOT_STARTED;
644 }
645 IMSA_HILOGI("left: %{public}d, top: %{public}d, height: %{public}d.", static_cast<int32_t>(cursorInfo.left),
646 static_cast<int32_t>(cursorInfo.top), static_cast<int32_t>(cursorInfo.height));
647 agent->OnCursorUpdate(cursorInfo.left, cursorInfo.top, cursorInfo.height);
648 return ErrorCode::NO_ERROR;
649 }
650
OnSelectionChange(std::u16string text,int start,int end)651 int32_t InputMethodController::OnSelectionChange(std::u16string text, int start, int end)
652 {
653 if (!IsBound()) {
654 IMSA_HILOGD("not bound.");
655 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
656 }
657 if (!IsEditable()) {
658 IMSA_HILOGD("not editable.");
659 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
660 }
661 {
662 std::lock_guard<std::mutex> lock(textConfigLock_);
663 textConfig_.range = { start, end };
664 }
665 if (textString_ == text && selectNewBegin_ == start && selectNewEnd_ == end) {
666 IMSA_HILOGD("same to last update.");
667 return ErrorCode::NO_ERROR;
668 }
669 textString_ = text;
670 selectOldBegin_ = selectNewBegin_;
671 selectOldEnd_ = selectNewEnd_;
672 selectNewBegin_ = start;
673 selectNewEnd_ = end;
674 auto agent = GetAgent();
675 if (agent == nullptr) {
676 IMSA_HILOGE("agent is nullptr!");
677 return ErrorCode::ERROR_IME_NOT_STARTED;
678 }
679 IMSA_HILOGI("IMC size: %{public}zu, range: %{public}d/%{public}d/%{public}d/%{public}d.", text.size(),
680 selectOldBegin_, selectOldEnd_, start, end);
681 agent->OnSelectionChange(textString_, selectOldBegin_, selectOldEnd_, selectNewBegin_, selectNewEnd_);
682 return ErrorCode::NO_ERROR;
683 }
684
OnConfigurationChange(Configuration info)685 int32_t InputMethodController::OnConfigurationChange(Configuration info)
686 {
687 if (!IsBound()) {
688 IMSA_HILOGD("not bound.");
689 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
690 }
691 InputAttribute attribute;
692 {
693 std::lock_guard<std::mutex> lock(textConfigLock_);
694 textConfig_.inputAttribute.enterKeyType = static_cast<int32_t>(info.GetEnterKeyType());
695 textConfig_.inputAttribute.inputPattern = static_cast<int32_t>(info.GetTextInputType());
696 attribute = textConfig_.inputAttribute;
697 }
698 if (!IsEditable()) {
699 IMSA_HILOGD("not editable.");
700 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
701 }
702 IMSA_HILOGI("IMC enterKeyType: %{public}d, textInputType: %{public}d.", attribute.enterKeyType,
703 attribute.inputPattern);
704 auto agent = GetAgent();
705 if (agent == nullptr) {
706 IMSA_HILOGE("agent is nullptr!");
707 return ErrorCode::ERROR_IME_NOT_STARTED;
708 }
709 agent->OnAttributeChange(attribute);
710 return ErrorCode::NO_ERROR;
711 }
712
GetLeft(int32_t length,std::u16string & text)713 int32_t InputMethodController::GetLeft(int32_t length, std::u16string &text)
714 {
715 InputMethodSyncTrace tracer("IMC_GetForward");
716 IMSA_HILOGD("start, length: %{public}d", length);
717 auto listener = GetTextListener();
718 if (!IsEditable() || listener == nullptr) {
719 IMSA_HILOGE("not editable or listener is nullptr!");
720 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
721 }
722 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
723 {
724 InputMethodSyncTrace aceTracer("ACE_GetForward");
725 text = listener->GetLeftTextOfCursor(length);
726 }
727 PrintLogIfAceTimeout(start);
728 return ErrorCode::NO_ERROR;
729 }
730
GetRight(int32_t length,std::u16string & text)731 int32_t InputMethodController::GetRight(int32_t length, std::u16string &text)
732 {
733 IMSA_HILOGD("start, length: %{public}d", length);
734 auto listener = GetTextListener();
735 if (!IsEditable() || listener == nullptr) {
736 IMSA_HILOGE("not editable or textListener_ is nullptr!");
737 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
738 }
739 text = listener->GetRightTextOfCursor(length);
740 return ErrorCode::NO_ERROR;
741 }
742
GetTextIndexAtCursor(int32_t & index)743 int32_t InputMethodController::GetTextIndexAtCursor(int32_t &index)
744 {
745 IMSA_HILOGD("start.");
746 auto listener = GetTextListener();
747 if (!IsEditable() || listener == nullptr) {
748 IMSA_HILOGE("not editable or textListener_ is nullptr!");
749 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
750 }
751 index = listener->GetTextIndexAtCursor();
752 return ErrorCode::NO_ERROR;
753 }
754
PrintKeyEventLog()755 void InputMethodController::PrintKeyEventLog()
756 {
757 std::lock_guard<std::mutex> lock(logLock_);
758 auto now = system_clock::now();
759 if (keyEventCountInPeriod_ == 0) {
760 startLogTime_ = now;
761 }
762 keyEventCountInPeriod_++;
763 if (std::chrono::duration_cast<seconds>(now - startLogTime_).count() >= LOG_MAX_TIME) {
764 auto start = std::chrono::duration_cast<seconds>(startLogTime_.time_since_epoch()).count();
765 auto end = std::chrono::duration_cast<seconds>(now.time_since_epoch()).count();
766 IMSA_HILOGI("KeyEventCountInPeriod: %{public}d, startTime: %{public}lld, endTime: %{public}lld",
767 keyEventCountInPeriod_, start, end);
768 keyEventCountInPeriod_ = 0;
769 }
770 }
771
DispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent,KeyEventCallback callback)772 int32_t InputMethodController::DispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent, KeyEventCallback callback)
773 {
774 PrintKeyEventLog();
775 KeyEventInfo keyEventInfo = { std::chrono::system_clock::now(), keyEvent };
776 keyEventQueue_.Push(keyEventInfo);
777 InputMethodSyncTrace tracer("DispatchKeyEvent trace");
778 keyEventQueue_.Wait(keyEventInfo);
779 if (!IsEditable()) {
780 IMSA_HILOGD("not editable.");
781 keyEventQueue_.Pop();
782 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
783 }
784 if (keyEvent == nullptr) {
785 IMSA_HILOGE("keyEvent is nullptr!");
786 keyEventQueue_.Pop();
787 return ErrorCode::ERROR_EX_NULL_POINTER;
788 }
789 auto agent = GetAgent();
790 if (agent == nullptr) {
791 IMSA_HILOGE("agent is nullptr!");
792 keyEventQueue_.Pop();
793 return ErrorCode::ERROR_IME_NOT_STARTED;
794 }
795 IMSA_HILOGD("start.");
796 sptr<IKeyEventConsumer> consumer = new (std::nothrow) KeyEventConsumerStub(callback, keyEvent);
797 if (consumer == nullptr) {
798 IMSA_HILOGE("consumer is nullptr!");
799 keyEventQueue_.Pop();
800 return ErrorCode::ERROR_EX_NULL_POINTER;
801 }
802 auto ret = agent->DispatchKeyEvent(keyEvent, consumer);
803 if (ret != ErrorCode::NO_ERROR) {
804 IMSA_HILOGE("failed to DispatchKeyEvent: %{public}d", ret);
805 }
806 keyEventQueue_.Pop();
807 return ret;
808 }
809
GetEnterKeyType(int32_t & keyType)810 int32_t InputMethodController::GetEnterKeyType(int32_t &keyType)
811 {
812 IMSA_HILOGD("InputMethodController::GetEnterKeyType start.");
813 std::lock_guard<std::mutex> lock(textConfigLock_);
814 keyType = textConfig_.inputAttribute.enterKeyType;
815 return ErrorCode::NO_ERROR;
816 }
817
GetInputPattern(int32_t & inputpattern)818 int32_t InputMethodController::GetInputPattern(int32_t &inputpattern)
819 {
820 IMSA_HILOGD("InputMethodController::GetInputPattern start.");
821 std::lock_guard<std::mutex> lock(textConfigLock_);
822 inputpattern = textConfig_.inputAttribute.inputPattern;
823 return ErrorCode::NO_ERROR;
824 }
825
GetTextConfig(TextTotalConfig & config)826 int32_t InputMethodController::GetTextConfig(TextTotalConfig &config)
827 {
828 std::lock_guard<std::mutex> lock(textConfigLock_);
829 config.inputAttribute = textConfig_.inputAttribute;
830 config.cursorInfo = textConfig_.cursorInfo;
831 config.windowId = textConfig_.windowId;
832 config.positionY = textConfig_.positionY;
833 config.height = textConfig_.height;
834 config.privateCommand = textConfig_.privateCommand;
835 if (textConfig_.range.start == INVALID_VALUE) {
836 IMSA_HILOGD("SelectionRange is invalid.");
837 } else {
838 {
839 std::lock_guard<std::mutex> editorLock(editorContentLock_);
840 config.textSelection.oldBegin = selectOldBegin_;
841 config.textSelection.oldEnd = selectOldEnd_;
842 }
843 config.textSelection.newBegin = textConfig_.range.start;
844 config.textSelection.newEnd = textConfig_.range.end;
845 }
846 IMSA_HILOGD("textConfig: %{public}s.", config.ToString().c_str());
847 return ErrorCode::NO_ERROR;
848 }
849
SetCallingWindow(uint32_t windowId)850 int32_t InputMethodController::SetCallingWindow(uint32_t windowId)
851 {
852 if (!IsBound()) {
853 IMSA_HILOGD("not bound.");
854 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
855 }
856 if (!IsEditable()) {
857 IMSA_HILOGD("not editable.");
858 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
859 }
860 {
861 std::lock_guard<std::mutex> lock(textConfigLock_);
862 textConfig_.windowId = windowId;
863 }
864 auto agent = GetAgent();
865 if (agent == nullptr) {
866 IMSA_HILOGE("agent is nullptr!");
867 return ErrorCode::ERROR_IME_NOT_STARTED;
868 }
869 IMSA_HILOGI("windowId: %{public}d.", windowId);
870 agent->SetCallingWindow(windowId);
871 return ErrorCode::NO_ERROR;
872 }
873
ShowSoftKeyboard()874 int32_t InputMethodController::ShowSoftKeyboard()
875 {
876 auto proxy = GetSystemAbilityProxy();
877 if (proxy == nullptr) {
878 IMSA_HILOGE("proxy is nullptr!");
879 return ErrorCode::ERROR_EX_NULL_POINTER;
880 }
881 IMSA_HILOGI("start.");
882 {
883 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
884 clientInfo_.isShowKeyboard = true;
885 }
886 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL);
887 return proxy->ShowCurrentInput();
888 }
889
HideSoftKeyboard()890 int32_t InputMethodController::HideSoftKeyboard()
891 {
892 auto proxy = GetSystemAbilityProxy();
893 if (proxy == nullptr) {
894 IMSA_HILOGE("proxy is nullptr!");
895 return ErrorCode::ERROR_EX_NULL_POINTER;
896 }
897 IMSA_HILOGI("start.");
898 {
899 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
900 clientInfo_.isShowKeyboard = false;
901 }
902 InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL);
903 return proxy->HideCurrentInput();
904 }
905
StopInputSession()906 int32_t InputMethodController::StopInputSession()
907 {
908 IMSA_HILOGI("start.");
909 isEditable_.store(false);
910 auto proxy = GetSystemAbilityProxy();
911 if (proxy == nullptr) {
912 IMSA_HILOGE("proxy is nullptr!");
913 return ErrorCode::ERROR_EX_NULL_POINTER;
914 }
915 return proxy->StopInputSession();
916 }
917
ShowOptionalInputMethod()918 int32_t InputMethodController::ShowOptionalInputMethod()
919 {
920 auto proxy = GetSystemAbilityProxy();
921 if (proxy == nullptr) {
922 IMSA_HILOGE("proxy is nullptr!");
923 return ErrorCode::ERROR_EX_NULL_POINTER;
924 }
925 IMSA_HILOGI("IMC start.");
926 return proxy->DisplayOptionalInputMethod();
927 }
928
ListInputMethodSubtype(const Property & property,std::vector<SubProperty> & subProps)929 int32_t InputMethodController::ListInputMethodSubtype(const Property &property, std::vector<SubProperty> &subProps)
930 {
931 auto proxy = GetSystemAbilityProxy();
932 if (proxy == nullptr) {
933 IMSA_HILOGE("proxy is nullptr!");
934 return ErrorCode::ERROR_EX_NULL_POINTER;
935 }
936 IMSA_HILOGD("ime bundleName: %{public}s.", property.name.c_str());
937 return proxy->ListInputMethodSubtype(property.name, subProps);
938 }
939
ListCurrentInputMethodSubtype(std::vector<SubProperty> & subProps)940 int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps)
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_HILOGD("start.");
948 return proxy->ListCurrentInputMethodSubtype(subProps);
949 }
950
SwitchInputMethod(SwitchTrigger trigger,const std::string & name,const std::string & subName)951 int32_t InputMethodController::SwitchInputMethod(
952 SwitchTrigger trigger, const std::string &name, const std::string &subName)
953 {
954 InputMethodSyncTrace tracer("IMC_SwitchInputMethod");
955 auto proxy = GetSystemAbilityProxy();
956 if (proxy == nullptr) {
957 IMSA_HILOGE("proxy is nullptr!");
958 return ErrorCode::ERROR_EX_NULL_POINTER;
959 }
960 IMSA_HILOGI("name: %{public}s, subName: %{public}s, trigger: %{public}d.", name.c_str(), subName.c_str(),
961 static_cast<uint32_t>(trigger));
962 return proxy->SwitchInputMethod(name, subName, trigger);
963 }
964
OnInputReady(sptr<IRemoteObject> agentObject)965 void InputMethodController::OnInputReady(sptr<IRemoteObject> agentObject)
966 {
967 IMSA_HILOGI("InputMethodController start.");
968 isBound_.store(true);
969 isEditable_.store(true);
970 if (agentObject == nullptr) {
971 IMSA_HILOGE("agentObject is nullptr!");
972 return;
973 }
974 SetAgent(agentObject);
975 }
976
OnInputStop(bool isStopInactiveClient)977 void InputMethodController::OnInputStop(bool isStopInactiveClient)
978 {
979 {
980 std::lock_guard<std::mutex> autoLock(agentLock_);
981 agent_ = nullptr;
982 agentObject_ = nullptr;
983 }
984 auto listener = GetTextListener();
985 if (listener != nullptr) {
986 IMSA_HILOGD("listener is not nullptr!");
987 if (textConfig_.inputAttribute.isTextPreviewSupported) {
988 IMSA_HILOGD("finish text preview.");
989 listener->FinishTextPreview();
990 }
991 if (!isStopInactiveClient || !listener->IsFromTs()) {
992 listener->SendKeyboardStatus(KeyboardStatus::HIDE);
993 }
994 }
995 isBound_.store(false);
996 isEditable_.store(false);
997 }
998
ClearEditorCache(bool isNewEditor,sptr<OnTextChangedListener> lastListener)999 void InputMethodController::ClearEditorCache(bool isNewEditor, sptr<OnTextChangedListener> lastListener)
1000 {
1001 IMSA_HILOGD("isNewEditor: %{public}d.", isNewEditor);
1002 if (isNewEditor && isBound_.load() && lastListener != nullptr
1003 && textConfig_.inputAttribute.isTextPreviewSupported) {
1004 IMSA_HILOGD("last editor FinishTextPreview");
1005 lastListener->FinishTextPreview();
1006 }
1007 {
1008 std::lock_guard<std::mutex> lock(editorContentLock_);
1009 // reset old range when editor changes or first attach
1010 if (isNewEditor || !isBound_.load()) {
1011 isTextNotified_.store(false);
1012 textString_ = Str8ToStr16("");
1013 selectOldBegin_ = INVALID_VALUE;
1014 selectOldEnd_ = INVALID_VALUE;
1015 selectNewBegin_ = INVALID_VALUE;
1016 selectNewEnd_ = INVALID_VALUE;
1017 }
1018 }
1019 {
1020 std::lock_guard<std::mutex> lock(textConfigLock_);
1021 textConfig_ = {};
1022 }
1023 {
1024 std::lock_guard<std::mutex> lock(cursorInfoMutex_);
1025 cursorInfo_ = {};
1026 }
1027 clientInfo_.config = {};
1028 }
1029
SelectByRange(int32_t start,int32_t end)1030 void InputMethodController::SelectByRange(int32_t start, int32_t end)
1031 {
1032 IMSA_HILOGD("InputMethodController start: %{public}d, end: %{public}d.", start, end);
1033 auto listener = GetTextListener();
1034 if (IsEditable() && listener != nullptr) {
1035 listener->HandleSetSelection(start, end);
1036 } else {
1037 IMSA_HILOGE("not editable or textListener_ is nullptr!");
1038 }
1039
1040 if (controllerListener_ != nullptr) {
1041 controllerListener_->OnSelectByRange(start, end);
1042 } else {
1043 IMSA_HILOGE("controllerListener_ is nullptr!");
1044 }
1045 }
1046
SelectByMovement(int32_t direction,int32_t cursorMoveSkip)1047 void InputMethodController::SelectByMovement(int32_t direction, int32_t cursorMoveSkip)
1048 {
1049 IMSA_HILOGD("InputMethodController start, direction: %{public}d, cursorMoveSkip: %{public}d", direction,
1050 cursorMoveSkip);
1051 auto listener = GetTextListener();
1052 if (IsEditable() && listener != nullptr) {
1053 listener->HandleSelect(CURSOR_DIRECTION_BASE_VALUE + direction, cursorMoveSkip);
1054 } else {
1055 IMSA_HILOGE("not editable or textListener_ is nullptr!");
1056 }
1057
1058 if (controllerListener_ != nullptr) {
1059 controllerListener_->OnSelectByMovement(direction);
1060 } else {
1061 IMSA_HILOGE("controllerListener_ is nullptr!");
1062 }
1063 }
1064
HandleExtendAction(int32_t action)1065 int32_t InputMethodController::HandleExtendAction(int32_t action)
1066 {
1067 IMSA_HILOGD("InputMethodController start, action: %{public}d.", action);
1068 auto listener = GetTextListener();
1069 if (!IsEditable() || listener == nullptr) {
1070 IMSA_HILOGE("not editable or textListener is nullptr!");
1071 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1072 }
1073 listener->HandleExtendAction(action);
1074 return ErrorCode::NO_ERROR;
1075 }
1076
GetTextListener()1077 sptr<OnTextChangedListener> InputMethodController::GetTextListener()
1078 {
1079 std::lock_guard<std::mutex> lock(textListenerLock_);
1080 return textListener_;
1081 }
1082
SetTextListener(sptr<OnTextChangedListener> listener)1083 void InputMethodController::SetTextListener(sptr<OnTextChangedListener> listener)
1084 {
1085 std::lock_guard<std::mutex> lock(textListenerLock_);
1086 textListener_ = listener;
1087 }
1088
IsEditable()1089 bool InputMethodController::IsEditable()
1090 {
1091 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
1092 if (clientInfo_.state != ClientState::ACTIVE) {
1093 IMSA_HILOGD("client is not active.");
1094 return false;
1095 }
1096 if (!isEditable_.load()) {
1097 IMSA_HILOGD("not in editable state.");
1098 return false;
1099 }
1100 return true;
1101 }
1102
IsBound()1103 bool InputMethodController::IsBound()
1104 {
1105 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
1106 if (clientInfo_.state != ClientState::ACTIVE) {
1107 IMSA_HILOGD("client is not active.");
1108 return false;
1109 }
1110 if (!isBound_.load()) {
1111 IMSA_HILOGD("not bound.");
1112 return false;
1113 }
1114 return true;
1115 }
1116
InsertText(const std::u16string & text)1117 int32_t InputMethodController::InsertText(const std::u16string &text)
1118 {
1119 InputMethodSyncTrace tracer("IMC_InsertText");
1120 IMSA_HILOGD("start.");
1121 auto listener = GetTextListener();
1122 if (!IsEditable() || listener == nullptr) {
1123 IMSA_HILOGE("not editable or textListener is nullptr!");
1124 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1125 }
1126 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
1127 {
1128 InputMethodSyncTrace aceTracer("ACE_InsertText");
1129 IMSA_HILOGD("ACE InsertText.");
1130 listener->InsertText(text);
1131 }
1132 PrintLogIfAceTimeout(start);
1133 return ErrorCode::NO_ERROR;
1134 }
1135
DeleteForward(int32_t length)1136 int32_t InputMethodController::DeleteForward(int32_t length)
1137 {
1138 InputMethodSyncTrace tracer("IMC_DeleteForward");
1139 IMSA_HILOGD("start, length: %{public}d.", length);
1140 auto listener = GetTextListener();
1141 if (!IsEditable() || listener == nullptr) {
1142 IMSA_HILOGE("not editable or textListener is nullptr!");
1143 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1144 }
1145 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
1146 {
1147 InputMethodSyncTrace aceTracer("ACE_DeleteForward");
1148 // reverse for compatibility
1149 listener->DeleteBackward(length);
1150 }
1151 PrintLogIfAceTimeout(start);
1152 return ErrorCode::NO_ERROR;
1153 }
1154
DeleteBackward(int32_t length)1155 int32_t InputMethodController::DeleteBackward(int32_t length)
1156 {
1157 IMSA_HILOGD("InputMethodController start, length: %{public}d.", length);
1158 auto listener = GetTextListener();
1159 if (!IsEditable() || listener == nullptr) {
1160 IMSA_HILOGE("not editable or textListener is nullptr!");
1161 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1162 }
1163 // reverse for compatibility
1164 listener->DeleteForward(length);
1165 return ErrorCode::NO_ERROR;
1166 }
1167
MoveCursor(Direction direction)1168 int32_t InputMethodController::MoveCursor(Direction direction)
1169 {
1170 IMSA_HILOGD("InputMethodController start, direction: %{public}d.", static_cast<int32_t>(direction));
1171 auto listener = GetTextListener();
1172 if (!IsEditable() || listener == nullptr) {
1173 IMSA_HILOGE("not editable or textListener_ is nullptr!");
1174 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1175 }
1176 listener->MoveCursor(direction);
1177 return ErrorCode::NO_ERROR;
1178 }
1179
SendKeyboardStatus(KeyboardStatus status)1180 void InputMethodController::SendKeyboardStatus(KeyboardStatus status)
1181 {
1182 IMSA_HILOGD("InputMethodController status: %{public}d.", static_cast<int32_t>(status));
1183 auto listener = GetTextListener();
1184 if (listener == nullptr) {
1185 IMSA_HILOGE("listener is nullptr!");
1186 return;
1187 }
1188 listener->SendKeyboardStatus(status);
1189 if (status == KeyboardStatus::HIDE) {
1190 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
1191 clientInfo_.isShowKeyboard = false;
1192 }
1193 }
1194
NotifyPanelStatusInfo(const PanelStatusInfo & info)1195 void InputMethodController::NotifyPanelStatusInfo(const PanelStatusInfo &info)
1196 {
1197 IMSA_HILOGD("InputMethodController start, type: %{public}d, flag: %{public}d, visible: %{public}d, trigger: "
1198 "%{public}d.",
1199 static_cast<PanelType>(info.panelInfo.panelType), static_cast<PanelFlag>(info.panelInfo.panelFlag),
1200 info.visible, static_cast<Trigger>(info.trigger));
1201 auto listener = GetTextListener();
1202 if (listener == nullptr) {
1203 IMSA_HILOGE("listener is nullptr!");
1204 return;
1205 }
1206 if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD) {
1207 info.visible ? SendKeyboardStatus(KeyboardStatus::SHOW)
1208 : SendKeyboardStatus(KeyboardStatus::HIDE);
1209 }
1210 listener->NotifyPanelStatusInfo(info);
1211 if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD
1212 && info.panelInfo.panelFlag != PanelFlag::FLG_CANDIDATE_COLUMN && !info.visible) {
1213 std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
1214 clientInfo_.isShowKeyboard = false;
1215 }
1216 }
1217
NotifyKeyboardHeight(uint32_t height)1218 void InputMethodController::NotifyKeyboardHeight(uint32_t height)
1219 {
1220 IMSA_HILOGD("InputMethodController start, height: %{public}u.", height);
1221 auto listener = GetTextListener();
1222 if (listener == nullptr) {
1223 IMSA_HILOGE("listener is nullptr!");
1224 return;
1225 }
1226 listener->NotifyKeyboardHeight(height);
1227 }
1228
SendFunctionKey(int32_t functionKey)1229 int32_t InputMethodController::SendFunctionKey(int32_t functionKey)
1230 {
1231 IMSA_HILOGD("InputMethodController start, functionKey: %{public}d", static_cast<int32_t>(functionKey));
1232 auto listener = GetTextListener();
1233 if (!IsEditable() || listener == nullptr) {
1234 IMSA_HILOGE("not editable or listener is nullptr!");
1235 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1236 }
1237 FunctionKey funcKey;
1238 funcKey.SetEnterKeyType(static_cast<EnterKeyType>(functionKey));
1239 listener->SendFunctionKey(funcKey);
1240 return ErrorCode::NO_ERROR;
1241 }
1242
IsInputTypeSupported(InputType type)1243 bool InputMethodController::IsInputTypeSupported(InputType type)
1244 {
1245 auto proxy = GetSystemAbilityProxy();
1246 if (proxy == nullptr) {
1247 IMSA_HILOGE("proxy is nullptr!");
1248 return ErrorCode::ERROR_NULL_POINTER;
1249 }
1250 IMSA_HILOGI("type: %{public}d.", static_cast<int32_t>(type));
1251 return proxy->IsInputTypeSupported(type);
1252 }
1253
IsCurrentImeByPid(int32_t pid)1254 bool InputMethodController::IsCurrentImeByPid(int32_t pid)
1255 {
1256 auto proxy = GetSystemAbilityProxy();
1257 if (proxy == nullptr) {
1258 IMSA_HILOGE("proxy is nullptr!");
1259 return false;
1260 }
1261 return proxy->IsCurrentImeByPid(pid);
1262 }
1263
StartInputType(InputType type)1264 int32_t InputMethodController::StartInputType(InputType type)
1265 {
1266 auto proxy = GetSystemAbilityProxy();
1267 if (proxy == nullptr) {
1268 IMSA_HILOGE("proxy is nullptr!");
1269 return ErrorCode::ERROR_NULL_POINTER;
1270 }
1271 IMSA_HILOGI("type: %{public}d.", static_cast<int32_t>(type));
1272 return proxy->StartInputType(type);
1273 }
1274
IsPanelShown(const PanelInfo & panelInfo,bool & isShown)1275 int32_t InputMethodController::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
1276 {
1277 auto proxy = GetSystemAbilityProxy();
1278 if (proxy == nullptr) {
1279 IMSA_HILOGE("proxy is nullptr!");
1280 return ErrorCode::ERROR_NULL_POINTER;
1281 }
1282 IMSA_HILOGI("type: %{public}d, flag: %{public}d.", static_cast<int32_t>(panelInfo.panelType),
1283 static_cast<int32_t>(panelInfo.panelFlag));
1284 return proxy->IsPanelShown(panelInfo, isShown);
1285 }
1286
SetAgent(sptr<IRemoteObject> & agentObject)1287 void InputMethodController::SetAgent(sptr<IRemoteObject> &agentObject)
1288 {
1289 std::lock_guard<std::mutex> autoLock(agentLock_);
1290 if (agent_ != nullptr && agentObject_.GetRefPtr() == agentObject.GetRefPtr()) {
1291 IMSA_HILOGD("agent has already been set.");
1292 return;
1293 }
1294 agent_ = std::make_shared<InputMethodAgentProxy>(agentObject);
1295 agentObject_ = agentObject;
1296 }
1297
GetAgent()1298 std::shared_ptr<IInputMethodAgent> InputMethodController::GetAgent()
1299 {
1300 std::lock_guard<std::mutex> autoLock(agentLock_);
1301 return agent_;
1302 }
1303
PrintLogIfAceTimeout(int64_t start)1304 void InputMethodController::PrintLogIfAceTimeout(int64_t start)
1305 {
1306 int64_t end = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
1307 if (end - start > ACE_DEAL_TIME_OUT) {
1308 IMSA_HILOGW("timeout: [%{public}" PRId64 ", %{public}" PRId64 "].", start, end);
1309 }
1310 }
1311
ReceivePrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)1312 int32_t InputMethodController::ReceivePrivateCommand(
1313 const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
1314 {
1315 auto listener = GetTextListener();
1316 if (listener == nullptr) {
1317 IMSA_HILOGE("listener is nullptr.");
1318 return ErrorCode::ERROR_EX_NULL_POINTER;
1319 }
1320 IMSA_HILOGD("IMC in.");
1321 auto ret = listener->ReceivePrivateCommand(privateCommand);
1322 if (ret != ErrorCode::NO_ERROR) {
1323 IMSA_HILOGE("ReceivePrivateCommand err, ret: %{public}d!", ret);
1324 return ErrorCode::ERROR_TEXT_LISTENER_ERROR;
1325 }
1326 return ErrorCode::NO_ERROR;
1327 }
1328
SendPrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)1329 int32_t InputMethodController::SendPrivateCommand(
1330 const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
1331 {
1332 if (!IsBound()) {
1333 IMSA_HILOGD("not bound.");
1334 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
1335 }
1336 if (!IsEditable()) {
1337 IMSA_HILOGD("not editable.");
1338 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1339 }
1340 if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
1341 IMSA_HILOGE("invalid private command size!");
1342 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
1343 }
1344 auto agent = GetAgent();
1345 if (agent == nullptr) {
1346 IMSA_HILOGE("agent is nullptr!");
1347 return ErrorCode::ERROR_IME_NOT_STARTED;
1348 }
1349 IMSA_HILOGD("IMC start.");
1350 return agent->SendPrivateCommand(privateCommand);
1351 }
1352
SetPreviewText(const std::string & text,const Range & range)1353 int32_t InputMethodController::SetPreviewText(const std::string &text, const Range &range)
1354 {
1355 InputMethodSyncTrace tracer("IMC_SetPreviewText");
1356 IMSA_HILOGD("IMC start.");
1357 if (!textConfig_.inputAttribute.isTextPreviewSupported) {
1358 IMSA_HILOGE("text preview do not supported!");
1359 return ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED;
1360 }
1361 auto listener = GetTextListener();
1362 if (!IsEditable() || listener == nullptr) {
1363 IMSA_HILOGE("not editable or listener is nullptr!");
1364 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1365 }
1366 int32_t ret = 0;
1367 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
1368 {
1369 InputMethodSyncTrace aceTracer("ACE_SetPreviewText");
1370 ret = listener->SetPreviewText(Str8ToStr16(text), range);
1371 }
1372 PrintLogIfAceTimeout(start);
1373 if (ret != ErrorCode::NO_ERROR) {
1374 IMSA_HILOGE("failed to SetPreviewText: %{public}d!", ret);
1375 return ret == -1 ? ErrorCode::ERROR_INVALID_RANGE : ErrorCode::ERROR_TEXT_LISTENER_ERROR;
1376 }
1377 return ErrorCode::NO_ERROR;
1378 }
1379
FinishTextPreview()1380 int32_t InputMethodController::FinishTextPreview()
1381 {
1382 InputMethodSyncTrace tracer("IMC_FinishTextPreview");
1383 IMSA_HILOGD("IMC start.");
1384 if (!textConfig_.inputAttribute.isTextPreviewSupported) {
1385 IMSA_HILOGD("text preview do not supported!");
1386 return ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED;
1387 }
1388 auto listener = GetTextListener();
1389 if (!isBound_.load() || listener == nullptr) {
1390 IMSA_HILOGW("not bound or listener is nullptr!");
1391 return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
1392 }
1393 {
1394 InputMethodSyncTrace aceTracer("ACE_FinishTextPreview");
1395 listener->FinishTextPreview();
1396 }
1397 return ErrorCode::NO_ERROR;
1398 }
1399 } // namespace MiscServices
1400 } // namespace OHOS