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