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