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