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