1 /* 2 * Copyright (C) 2021 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_ability.h" 17 18 #include <unistd.h> 19 20 #include "global.h" 21 #include "input_method_agent_proxy.h" 22 #include "input_method_agent_stub.h" 23 #include "input_method_core_proxy.h" 24 #include "input_method_core_stub.h" 25 #include "input_method_utils.h" 26 #include "iservice_registry.h" 27 #include "itypes_util.h" 28 #include "message_parcel.h" 29 #include "string_ex.h" 30 #include "system_ability_definition.h" 31 32 namespace OHOS { 33 namespace MiscServices { 34 class MessageHandler; 35 using namespace MessageID; 36 sptr<InputMethodAbility> InputMethodAbility::instance_; 37 std::mutex InputMethodAbility::instanceLock_; InputMethodAbility()38 InputMethodAbility::InputMethodAbility() : stop_(false) 39 { 40 writeInputChannel = nullptr; 41 Initialize(); 42 } 43 ~InputMethodAbility()44 InputMethodAbility::~InputMethodAbility() 45 { 46 IMSA_HILOGI("InputMethodAbility::~InputMethodAbility"); 47 QuitWorkThread(); 48 if (msgHandler) { 49 delete msgHandler; 50 msgHandler = nullptr; 51 } 52 } 53 GetInstance()54 sptr<InputMethodAbility> InputMethodAbility::GetInstance() 55 { 56 if (!instance_) { 57 std::lock_guard<std::mutex> autoLock(instanceLock_); 58 if (!instance_) { 59 IMSA_HILOGI("InputMethodAbility::GetInstance need new IMA"); 60 instance_ = new InputMethodAbility(); 61 } 62 } 63 return instance_; 64 } 65 GetImsaProxy()66 sptr<InputMethodSystemAbilityProxy> InputMethodAbility::GetImsaProxy() 67 { 68 IMSA_HILOGI("InputMethodAbility::GetImsaProxy"); 69 sptr<ISystemAbilityManager> systemAbilityManager = 70 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); 71 if (systemAbilityManager == nullptr) { 72 IMSA_HILOGI("InputMethodAbility::GetImsaProxy systemAbilityManager is nullptr"); 73 return nullptr; 74 } 75 76 auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, ""); 77 if (systemAbility == nullptr) { 78 IMSA_HILOGI("InputMethodAbility::GetImsaProxy systemAbility is nullptr"); 79 return nullptr; 80 } 81 if (deathRecipientPtr_ == nullptr) { 82 deathRecipientPtr_ = new (std::nothrow) ServiceDeathRecipient(); 83 if (deathRecipientPtr_ == nullptr) { 84 IMSA_HILOGE("new ServiceDeathRecipient failed"); 85 return nullptr; 86 } 87 } 88 if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipientPtr_))) { 89 IMSA_HILOGE("failed to add death recipient."); 90 } 91 92 sptr<InputMethodSystemAbilityProxy> iface = new InputMethodSystemAbilityProxy(systemAbility); 93 return iface; 94 } 95 SetCoreAndAgent()96 int32_t InputMethodAbility::SetCoreAndAgent() 97 { 98 IMSA_HILOGI("InputMethodAbility, run in"); 99 if (isBound_.load()) { 100 IMSA_HILOGD("already bound"); 101 return ErrorCode::NO_ERROR; 102 } 103 mImms = GetImsaProxy(); 104 if (mImms == nullptr) { 105 IMSA_HILOGI("mImms is nullptr"); 106 return ErrorCode::ERROR_NULL_POINTER; 107 } 108 sptr<InputMethodCoreStub> stub = new InputMethodCoreStub(0); 109 stub->SetMessageHandler(msgHandler); 110 111 sptr<InputMethodAgentStub> inputMethodAgentStub(new InputMethodAgentStub()); 112 inputMethodAgentStub->SetMessageHandler(msgHandler); 113 sptr<IInputMethodAgent> inputMethodAgent = sptr(new InputMethodAgentProxy(inputMethodAgentStub)); 114 int32_t ret = mImms->SetCoreAndAgent(stub, inputMethodAgent); 115 if (ret != ErrorCode::NO_ERROR) { 116 IMSA_HILOGE("set failed, ret: %{public}d", ret); 117 return ret; 118 } 119 isBound_.store(true); 120 IMSA_HILOGD("set successfully"); 121 return ErrorCode::NO_ERROR; 122 } 123 Initialize()124 void InputMethodAbility::Initialize() 125 { 126 IMSA_HILOGI("InputMethodAbility::Initialize"); 127 msgHandler = new MessageHandler(); 128 workThreadHandler = std::thread([this] { 129 WorkThread(); 130 }); 131 } 132 setImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)133 void InputMethodAbility::setImeListener(std::shared_ptr<InputMethodEngineListener> imeListener) 134 { 135 IMSA_HILOGI("InputMethodAbility::setImeListener"); 136 if (imeListener_ == nullptr) { 137 imeListener_ = std::move(imeListener); 138 } 139 if (deathRecipientPtr_ != nullptr && deathRecipientPtr_->listener == nullptr) { 140 deathRecipientPtr_->listener = imeListener_; 141 } 142 } 143 OnImeReady()144 void InputMethodAbility::OnImeReady() 145 { 146 isImeReady_ = true; 147 if (!notifier_.isNotify) { 148 IMSA_HILOGI("InputMethodAbility::Ime Ready, don't need to notify"); 149 return; 150 } 151 IMSA_HILOGI("InputMethodAbility::Ime Ready, notify InputStart"); 152 ShowInputWindow(notifier_.isShowKeyboard, notifier_.subProperty); 153 } 154 setKdListener(std::shared_ptr<KeyboardListener> kdListener)155 void InputMethodAbility::setKdListener(std::shared_ptr<KeyboardListener> kdListener) 156 { 157 IMSA_HILOGI("InputMethodAbility::setKdListener"); 158 if (kdListener_ == nullptr) { 159 kdListener_ = kdListener; 160 } 161 } 162 WorkThread()163 void InputMethodAbility::WorkThread() 164 { 165 while (!stop_) { 166 Message *msg = msgHandler->GetMessage(); 167 switch (msg->msgId_) { 168 case MSG_ID_INIT_INPUT_CONTROL_CHANNEL: { 169 OnInitInputControlChannel(msg); 170 break; 171 } 172 case MSG_ID_SHOW_KEYBOARD: { 173 OnShowKeyboard(msg); 174 break; 175 } 176 case MSG_ID_HIDE_KEYBOARD: { 177 OnHideKeyboard(msg); 178 break; 179 } 180 case MSG_ID_ON_CURSOR_UPDATE: { 181 OnCursorUpdate(msg); 182 break; 183 } 184 case MSG_ID_ON_SELECTION_CHANGE: { 185 OnSelectionChange(msg); 186 break; 187 } 188 case MSG_ID_STOP_INPUT_SERVICE:{ 189 MessageParcel *data = msg->msgContent_; 190 std::string imeId = Str16ToStr8(data->ReadString16()); 191 if (imeListener_) { 192 imeListener_->OnInputStop(imeId); 193 } 194 break; 195 } 196 case MSG_ID_SET_SUBTYPE: { 197 OnSetSubtype(msg); 198 break; 199 } 200 default: { 201 IMSA_HILOGD("the message is %{public}d.", msg->msgId_); 202 break; 203 } 204 } 205 delete msg; 206 msg = nullptr; 207 } 208 } 209 210 OnInitInputControlChannel(Message * msg)211 void InputMethodAbility::OnInitInputControlChannel(Message *msg) 212 { 213 IMSA_HILOGI("InputMethodAbility::OnInitInputControlChannel"); 214 MessageParcel *data = msg->msgContent_; 215 sptr<IRemoteObject> channelObject = data->ReadRemoteObject(); 216 if (channelObject == nullptr) { 217 IMSA_HILOGI("InputMethodAbility::OnInitInputControlChannel channelObject is nullptr"); 218 return; 219 } 220 if (deathRecipientPtr_ != nullptr) { 221 deathRecipientPtr_->currentIme_ = data->ReadString(); 222 } 223 SetInputControlChannel(channelObject); 224 } 225 226 OnShowKeyboard(Message * msg)227 void InputMethodAbility::OnShowKeyboard(Message *msg) 228 { 229 IMSA_HILOGI("InputMethodAbility::OnShowKeyboard"); 230 MessageParcel *data = msg->msgContent_; 231 sptr<IRemoteObject> channelObject = nullptr; 232 bool isShowKeyboard = false; 233 SubProperty subProperty; 234 if (!ITypesUtil::Unmarshal(*data, channelObject, isShowKeyboard, subProperty)) { 235 IMSA_HILOGE("InputMethodAbility::OnShowKeyboard read message parcel failed"); 236 return; 237 } 238 if (channelObject == nullptr) { 239 IMSA_HILOGI("InputMethodAbility::OnShowKeyboard channelObject is nullptr"); 240 return; 241 } 242 SetInputDataChannel(channelObject); 243 ShowInputWindow(isShowKeyboard, subProperty); 244 } 245 OnHideKeyboard(Message * msg)246 void InputMethodAbility::OnHideKeyboard(Message *msg) 247 { 248 IMSA_HILOGI("InputMethodAbility::OnHideKeyboard"); 249 DissmissInputWindow(); 250 } 251 OnSetSubtype(Message * msg)252 void InputMethodAbility::OnSetSubtype(Message *msg) 253 { 254 IMSA_HILOGI("InputMethodAbility::OnSetSubtype"); 255 auto data = msg->msgContent_; 256 SubProperty subProperty; 257 if (!ITypesUtil::Unmarshal(*data, subProperty)) { 258 IMSA_HILOGE("read message parcel failed"); 259 return; 260 } 261 if (imeListener_ == nullptr) { 262 IMSA_HILOGI("InputMethodAbility::OnSetSubtype imeListener_ is nullptr"); 263 return; 264 } 265 imeListener_->OnSetSubtype(subProperty); 266 } 267 DispatchKeyEvent(int32_t keyCode,int32_t keyStatus)268 bool InputMethodAbility::DispatchKeyEvent(int32_t keyCode, int32_t keyStatus) 269 { 270 IMSA_HILOGI("key = %{public}d, status = %{public}d", keyCode, keyStatus); 271 if (!kdListener_) { 272 IMSA_HILOGI("InputMethodAbility::DispatchKeyEvent kdListener_ is nullptr"); 273 return false; 274 } 275 return kdListener_->OnKeyEvent(keyCode, keyStatus); 276 } 277 SetCallingWindow(uint32_t windowId)278 void InputMethodAbility::SetCallingWindow(uint32_t windowId) 279 { 280 IMSA_HILOGI("InputMethodAbility::SetCallingWindow"); 281 282 if (!imeListener_) { 283 IMSA_HILOGI("InputMethodAbility::SetCallingWindow imeListener_ is nullptr"); 284 return; 285 } 286 imeListener_->OnSetCallingWindow(windowId); 287 } 288 289 OnCursorUpdate(Message * msg)290 void InputMethodAbility::OnCursorUpdate(Message *msg) 291 { 292 IMSA_HILOGI("InputMethodAbility::OnCursorUpdate"); 293 MessageParcel *data = msg->msgContent_; 294 int32_t positionX = data->ReadInt32(); 295 int32_t positionY = data->ReadInt32(); 296 int32_t height = data->ReadInt32(); 297 if (!kdListener_) { 298 IMSA_HILOGI("InputMethodAbility::OnCursorUpdate kdListener_ is nullptr"); 299 return; 300 } 301 kdListener_->OnCursorUpdate(positionX, positionY, height); 302 } 303 OnSelectionChange(Message * msg)304 void InputMethodAbility::OnSelectionChange(Message *msg) 305 { 306 IMSA_HILOGI("InputMethodAbility::OnSelectionChange"); 307 MessageParcel *data = msg->msgContent_; 308 std::string text = Str16ToStr8(data->ReadString16()); 309 int32_t oldBegin = data->ReadInt32(); 310 int32_t oldEnd = data->ReadInt32(); 311 int32_t newBegin = data->ReadInt32(); 312 int32_t newEnd = data->ReadInt32(); 313 314 if (!kdListener_) { 315 IMSA_HILOGI("InputMethodAbility::OnSelectionChange kdListener_ is nullptr"); 316 return; 317 } 318 kdListener_->OnTextChange(text); 319 320 kdListener_->OnSelectionChange(oldBegin, oldEnd, newBegin, newEnd); 321 } 322 ShowInputWindow(bool isShowKeyboard,const SubProperty & subProperty)323 void InputMethodAbility::ShowInputWindow(bool isShowKeyboard, const SubProperty &subProperty) 324 { 325 IMSA_HILOGI("InputMethodAbility::ShowInputWindow"); 326 if (!isImeReady_) { 327 IMSA_HILOGI("InputMethodAbility::ime is unready, store notifier_"); 328 notifier_.isNotify = true; 329 notifier_.isShowKeyboard = isShowKeyboard; 330 notifier_.subProperty = subProperty; 331 return; 332 } 333 if (imeListener_ == nullptr) { 334 IMSA_HILOGI("InputMethodAbility::ShowInputWindow imeListener_ is nullptr"); 335 return; 336 } 337 imeListener_->OnInputStart(); 338 imeListener_->OnSetSubtype(subProperty); 339 if (!isShowKeyboard) { 340 IMSA_HILOGI("InputMethodAbility::ShowInputWindow will not show keyboard"); 341 return; 342 } 343 imeListener_->OnKeyboardStatus(true); 344 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 345 if (channel == nullptr) { 346 IMSA_HILOGI("InputMethodAbility::ShowInputWindow channel is nullptr"); 347 return; 348 } 349 channel->SendKeyboardStatus(KEYBOARD_SHOW); 350 } 351 DissmissInputWindow()352 void InputMethodAbility::DissmissInputWindow() 353 { 354 IMSA_HILOGI("InputMethodAbility::DissmissInputWindow"); 355 if (!imeListener_) { 356 IMSA_HILOGI("InputMethodAbility::DissmissInputWindow imeListener_ is nullptr"); 357 return; 358 } 359 imeListener_->OnKeyboardStatus(false); 360 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 361 if (channel == nullptr) { 362 IMSA_HILOGI("InputMethodAbility::DissmissInputWindow channel is nullptr"); 363 return; 364 } 365 channel->SendKeyboardStatus(KEYBOARD_HIDE); 366 } 367 InsertText(const std::string text)368 int32_t InputMethodAbility::InsertText(const std::string text) 369 { 370 IMSA_HILOGI("InputMethodAbility::InsertText"); 371 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 372 if (channel == nullptr) { 373 IMSA_HILOGI("InputMethodAbility::InsertText channel is nullptr"); 374 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 375 } 376 return channel->InsertText(Utils::ToStr16(text)); 377 } 378 DeleteForward(int32_t length)379 int32_t InputMethodAbility::DeleteForward(int32_t length) 380 { 381 IMSA_HILOGI("InputMethodAbility::DeleteForward"); 382 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 383 if (channel == nullptr) { 384 IMSA_HILOGI("InputMethodAbility::DeleteForward channel is nullptr"); 385 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 386 } 387 return channel->DeleteForward(length); 388 } 389 DeleteBackward(int32_t length)390 int32_t InputMethodAbility::DeleteBackward(int32_t length) 391 { 392 IMSA_HILOGI("InputMethodAbility::DeleteBackward"); 393 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 394 if (channel == nullptr) { 395 IMSA_HILOGI("InputMethodAbility::DeleteBackward channel is nullptr"); 396 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 397 } 398 return channel->DeleteBackward(length); 399 } 400 SendFunctionKey(int32_t funcKey)401 int32_t InputMethodAbility::SendFunctionKey(int32_t funcKey) 402 { 403 IMSA_HILOGI("InputMethodAbility::SendFunctionKey"); 404 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 405 if (channel == nullptr) { 406 IMSA_HILOGI("InputMethodAbility::SendFunctionKey channel is nullptr"); 407 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 408 } 409 return channel->SendFunctionKey(funcKey); 410 } 411 HideKeyboardSelf()412 int32_t InputMethodAbility::HideKeyboardSelf() 413 { 414 IMSA_HILOGI("InputMethodAbility::HideKeyboardSelf"); 415 std::shared_ptr<InputControlChannelProxy> controlChannel = GetInputControlChannel(); 416 if (controlChannel == nullptr) { 417 IMSA_HILOGI("InputMethodAbility::HideKeyboardSelf controlChannel is nullptr"); 418 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 419 } 420 return controlChannel->HideKeyboardSelf(1); 421 } 422 GetTextBeforeCursor(int32_t number,std::u16string & text)423 int32_t InputMethodAbility::GetTextBeforeCursor(int32_t number, std::u16string &text) 424 { 425 IMSA_HILOGI("InputMethodAbility::GetTextBeforeCursor"); 426 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 427 if (channel == nullptr) { 428 IMSA_HILOGI("InputMethodAbility::GetTextBeforeCursor channel is nullptr"); 429 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 430 } 431 return channel->GetTextBeforeCursor(number, text); 432 } 433 GetTextAfterCursor(int32_t number,std::u16string & text)434 int32_t InputMethodAbility::GetTextAfterCursor(int32_t number, std::u16string &text) 435 { 436 IMSA_HILOGI("InputMethodAbility::GetTextAfterCursor"); 437 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 438 if (channel == nullptr) { 439 IMSA_HILOGI("InputMethodAbility::GetTextAfterCursor channel is nullptr"); 440 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 441 } 442 return channel->GetTextAfterCursor(number, text); 443 } 444 MoveCursor(int32_t keyCode)445 int32_t InputMethodAbility::MoveCursor(int32_t keyCode) 446 { 447 IMSA_HILOGI("InputMethodAbility::MoveCursor"); 448 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 449 if (channel == nullptr) { 450 IMSA_HILOGI("InputMethodAbility::MoveCursor channel is nullptr"); 451 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 452 } 453 454 return channel->MoveCursor(keyCode); 455 } 456 GetEnterKeyType(int32_t & keyType)457 int32_t InputMethodAbility::GetEnterKeyType(int32_t &keyType) 458 { 459 IMSA_HILOGI("InputMethodAbility::GetEnterKeyType"); 460 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 461 if (channel == nullptr) { 462 IMSA_HILOGI("InputMethodAbility::GetEnterKeyType channel is nullptr"); 463 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 464 } 465 return channel->GetEnterKeyType(keyType); 466 } 467 GetInputPattern(int32_t & inputPattern)468 int32_t InputMethodAbility::GetInputPattern(int32_t &inputPattern) 469 { 470 IMSA_HILOGI("InputMethodAbility::GetInputPattern"); 471 std::shared_ptr<InputDataChannelProxy> channel = GetInputDataChannel(); 472 if (channel == nullptr) { 473 IMSA_HILOGI("InputMethodAbility::GetInputPattern channel is nullptr"); 474 return ErrorCode::ERROR_CLIENT_NULL_POINTER; 475 } 476 return channel->GetInputPattern(inputPattern); 477 } 478 479 SetInputDataChannel(sptr<IRemoteObject> & object)480 void InputMethodAbility::SetInputDataChannel(sptr<IRemoteObject> &object) 481 { 482 IMSA_HILOGI("run in SetInputDataChannel"); 483 std::lock_guard<std::mutex> lock(dataChannelLock_); 484 std::shared_ptr<InputDataChannelProxy> channalProxy = std::make_shared<InputDataChannelProxy>(object); 485 if (channalProxy == nullptr) { 486 IMSA_HILOGI("InputMethodAbility::SetInputDataChannel inputDataChannel is nullptr"); 487 return; 488 } 489 dataChannel_ = channalProxy; 490 } 491 GetInputDataChannel()492 std::shared_ptr<InputDataChannelProxy> InputMethodAbility::GetInputDataChannel() 493 { 494 std::lock_guard<std::mutex> lock(dataChannelLock_); 495 return dataChannel_; 496 } 497 SetInputControlChannel(sptr<IRemoteObject> & object)498 void InputMethodAbility::SetInputControlChannel(sptr<IRemoteObject> &object) 499 { 500 IMSA_HILOGI("run in SetInputControlChannel"); 501 std::lock_guard<std::mutex> lock(controlChannelLock_); 502 std::shared_ptr<InputControlChannelProxy> channalProxy = std::make_shared<InputControlChannelProxy>(object); 503 if (channalProxy == nullptr) { 504 IMSA_HILOGI("InputMethodAbility::SetInputControlChannel inputDataChannel is nullptr"); 505 return; 506 } 507 controlChannel_ = channalProxy; 508 } 509 GetInputControlChannel()510 std::shared_ptr<InputControlChannelProxy> InputMethodAbility::GetInputControlChannel() 511 { 512 std::lock_guard<std::mutex> lock(controlChannelLock_); 513 return controlChannel_; 514 } 515 OnRemoteDied(const wptr<IRemoteObject> & object)516 void InputMethodAbility::ServiceDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object) 517 { 518 IMSA_HILOGI("ServiceDeathRecipient::OnRemoteDied"); 519 if (listener != nullptr) { 520 listener->OnInputStop(currentIme_); 521 } 522 } 523 QuitWorkThread()524 void InputMethodAbility::QuitWorkThread() 525 { 526 stop_ = true; 527 Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr); 528 msgHandler->SendMessage(msg); 529 if (workThreadHandler.joinable()) { 530 workThreadHandler.join(); 531 } 532 } 533 } // namespace MiscServices 534 } // namespace OHOS 535