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