• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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