/* * Copyright (C) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "input_method_ability.h" #include #include "global.h" #include "input_method_agent_proxy.h" #include "input_method_agent_stub.h" #include "input_method_core_proxy.h" #include "input_method_core_stub.h" #include "input_method_utils.h" #include "iservice_registry.h" #include "itypes_util.h" #include "message_parcel.h" #include "string_ex.h" #include "system_ability_definition.h" namespace OHOS { namespace MiscServices { class MessageHandler; using namespace MessageID; sptr InputMethodAbility::instance_; std::mutex InputMethodAbility::instanceLock_; InputMethodAbility::InputMethodAbility() : stop_(false) { writeInputChannel = nullptr; Initialize(); } InputMethodAbility::~InputMethodAbility() { IMSA_HILOGI("InputMethodAbility::~InputMethodAbility"); QuitWorkThread(); if (msgHandler) { delete msgHandler; msgHandler = nullptr; } } sptr InputMethodAbility::GetInstance() { if (!instance_) { std::lock_guard autoLock(instanceLock_); if (!instance_) { IMSA_HILOGI("InputMethodAbility::GetInstance need new IMA"); instance_ = new InputMethodAbility(); } } return instance_; } sptr InputMethodAbility::GetImsaProxy() { IMSA_HILOGI("InputMethodAbility::GetImsaProxy"); sptr systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); if (systemAbilityManager == nullptr) { IMSA_HILOGI("InputMethodAbility::GetImsaProxy systemAbilityManager is nullptr"); return nullptr; } auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, ""); if (systemAbility == nullptr) { IMSA_HILOGI("InputMethodAbility::GetImsaProxy systemAbility is nullptr"); return nullptr; } if (deathRecipientPtr_ == nullptr) { deathRecipientPtr_ = new (std::nothrow) ServiceDeathRecipient(); if (deathRecipientPtr_ == nullptr) { IMSA_HILOGE("new ServiceDeathRecipient failed"); return nullptr; } } if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipientPtr_))) { IMSA_HILOGE("failed to add death recipient."); } sptr iface = new InputMethodSystemAbilityProxy(systemAbility); return iface; } int32_t InputMethodAbility::SetCoreAndAgent() { IMSA_HILOGI("InputMethodAbility, run in"); if (isBound_.load()) { IMSA_HILOGD("already bound"); return ErrorCode::NO_ERROR; } mImms = GetImsaProxy(); if (mImms == nullptr) { IMSA_HILOGI("mImms is nullptr"); return ErrorCode::ERROR_NULL_POINTER; } sptr stub = new InputMethodCoreStub(0); stub->SetMessageHandler(msgHandler); sptr inputMethodAgentStub(new InputMethodAgentStub()); inputMethodAgentStub->SetMessageHandler(msgHandler); sptr inputMethodAgent = sptr(new InputMethodAgentProxy(inputMethodAgentStub)); int32_t ret = mImms->SetCoreAndAgent(stub, inputMethodAgent); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("set failed, ret: %{public}d", ret); return ret; } isBound_.store(true); IMSA_HILOGD("set successfully"); return ErrorCode::NO_ERROR; } void InputMethodAbility::Initialize() { IMSA_HILOGI("InputMethodAbility::Initialize"); msgHandler = new MessageHandler(); workThreadHandler = std::thread([this] { WorkThread(); }); } void InputMethodAbility::setImeListener(std::shared_ptr imeListener) { IMSA_HILOGI("InputMethodAbility::setImeListener"); if (imeListener_ == nullptr) { imeListener_ = std::move(imeListener); } if (deathRecipientPtr_ != nullptr && deathRecipientPtr_->listener == nullptr) { deathRecipientPtr_->listener = imeListener_; } } void InputMethodAbility::OnImeReady() { isImeReady_ = true; if (!notifier_.isNotify) { IMSA_HILOGI("InputMethodAbility::Ime Ready, don't need to notify"); return; } IMSA_HILOGI("InputMethodAbility::Ime Ready, notify InputStart"); ShowInputWindow(notifier_.isShowKeyboard, notifier_.subProperty); } void InputMethodAbility::setKdListener(std::shared_ptr kdListener) { IMSA_HILOGI("InputMethodAbility::setKdListener"); if (kdListener_ == nullptr) { kdListener_ = kdListener; } } void InputMethodAbility::WorkThread() { while (!stop_) { Message *msg = msgHandler->GetMessage(); switch (msg->msgId_) { case MSG_ID_INIT_INPUT_CONTROL_CHANNEL: { OnInitInputControlChannel(msg); break; } case MSG_ID_SHOW_KEYBOARD: { OnShowKeyboard(msg); break; } case MSG_ID_HIDE_KEYBOARD: { OnHideKeyboard(msg); break; } case MSG_ID_ON_CURSOR_UPDATE: { OnCursorUpdate(msg); break; } case MSG_ID_ON_SELECTION_CHANGE: { OnSelectionChange(msg); break; } case MSG_ID_STOP_INPUT_SERVICE:{ MessageParcel *data = msg->msgContent_; std::string imeId = Str16ToStr8(data->ReadString16()); if (imeListener_) { imeListener_->OnInputStop(imeId); } break; } case MSG_ID_SET_SUBTYPE: { OnSetSubtype(msg); break; } default: { IMSA_HILOGD("the message is %{public}d.", msg->msgId_); break; } } delete msg; msg = nullptr; } } void InputMethodAbility::OnInitInputControlChannel(Message *msg) { IMSA_HILOGI("InputMethodAbility::OnInitInputControlChannel"); MessageParcel *data = msg->msgContent_; sptr channelObject = data->ReadRemoteObject(); if (channelObject == nullptr) { IMSA_HILOGI("InputMethodAbility::OnInitInputControlChannel channelObject is nullptr"); return; } if (deathRecipientPtr_ != nullptr) { deathRecipientPtr_->currentIme_ = data->ReadString(); } SetInputControlChannel(channelObject); } void InputMethodAbility::OnShowKeyboard(Message *msg) { IMSA_HILOGI("InputMethodAbility::OnShowKeyboard"); MessageParcel *data = msg->msgContent_; sptr channelObject = nullptr; bool isShowKeyboard = false; SubProperty subProperty; if (!ITypesUtil::Unmarshal(*data, channelObject, isShowKeyboard, subProperty)) { IMSA_HILOGE("InputMethodAbility::OnShowKeyboard read message parcel failed"); return; } if (channelObject == nullptr) { IMSA_HILOGI("InputMethodAbility::OnShowKeyboard channelObject is nullptr"); return; } SetInputDataChannel(channelObject); ShowInputWindow(isShowKeyboard, subProperty); } void InputMethodAbility::OnHideKeyboard(Message *msg) { IMSA_HILOGI("InputMethodAbility::OnHideKeyboard"); DissmissInputWindow(); } void InputMethodAbility::OnSetSubtype(Message *msg) { IMSA_HILOGI("InputMethodAbility::OnSetSubtype"); auto data = msg->msgContent_; SubProperty subProperty; if (!ITypesUtil::Unmarshal(*data, subProperty)) { IMSA_HILOGE("read message parcel failed"); return; } if (imeListener_ == nullptr) { IMSA_HILOGI("InputMethodAbility::OnSetSubtype imeListener_ is nullptr"); return; } imeListener_->OnSetSubtype(subProperty); } bool InputMethodAbility::DispatchKeyEvent(int32_t keyCode, int32_t keyStatus) { IMSA_HILOGI("key = %{public}d, status = %{public}d", keyCode, keyStatus); if (!kdListener_) { IMSA_HILOGI("InputMethodAbility::DispatchKeyEvent kdListener_ is nullptr"); return false; } return kdListener_->OnKeyEvent(keyCode, keyStatus); } void InputMethodAbility::SetCallingWindow(uint32_t windowId) { IMSA_HILOGI("InputMethodAbility::SetCallingWindow"); if (!imeListener_) { IMSA_HILOGI("InputMethodAbility::SetCallingWindow imeListener_ is nullptr"); return; } imeListener_->OnSetCallingWindow(windowId); } void InputMethodAbility::OnCursorUpdate(Message *msg) { IMSA_HILOGI("InputMethodAbility::OnCursorUpdate"); MessageParcel *data = msg->msgContent_; int32_t positionX = data->ReadInt32(); int32_t positionY = data->ReadInt32(); int32_t height = data->ReadInt32(); if (!kdListener_) { IMSA_HILOGI("InputMethodAbility::OnCursorUpdate kdListener_ is nullptr"); return; } kdListener_->OnCursorUpdate(positionX, positionY, height); } void InputMethodAbility::OnSelectionChange(Message *msg) { IMSA_HILOGI("InputMethodAbility::OnSelectionChange"); MessageParcel *data = msg->msgContent_; std::string text = Str16ToStr8(data->ReadString16()); int32_t oldBegin = data->ReadInt32(); int32_t oldEnd = data->ReadInt32(); int32_t newBegin = data->ReadInt32(); int32_t newEnd = data->ReadInt32(); if (!kdListener_) { IMSA_HILOGI("InputMethodAbility::OnSelectionChange kdListener_ is nullptr"); return; } kdListener_->OnTextChange(text); kdListener_->OnSelectionChange(oldBegin, oldEnd, newBegin, newEnd); } void InputMethodAbility::ShowInputWindow(bool isShowKeyboard, const SubProperty &subProperty) { IMSA_HILOGI("InputMethodAbility::ShowInputWindow"); if (!isImeReady_) { IMSA_HILOGI("InputMethodAbility::ime is unready, store notifier_"); notifier_.isNotify = true; notifier_.isShowKeyboard = isShowKeyboard; notifier_.subProperty = subProperty; return; } if (imeListener_ == nullptr) { IMSA_HILOGI("InputMethodAbility::ShowInputWindow imeListener_ is nullptr"); return; } imeListener_->OnInputStart(); imeListener_->OnSetSubtype(subProperty); if (!isShowKeyboard) { IMSA_HILOGI("InputMethodAbility::ShowInputWindow will not show keyboard"); return; } imeListener_->OnKeyboardStatus(true); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::ShowInputWindow channel is nullptr"); return; } channel->SendKeyboardStatus(KEYBOARD_SHOW); } void InputMethodAbility::DissmissInputWindow() { IMSA_HILOGI("InputMethodAbility::DissmissInputWindow"); if (!imeListener_) { IMSA_HILOGI("InputMethodAbility::DissmissInputWindow imeListener_ is nullptr"); return; } imeListener_->OnKeyboardStatus(false); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::DissmissInputWindow channel is nullptr"); return; } channel->SendKeyboardStatus(KEYBOARD_HIDE); } int32_t InputMethodAbility::InsertText(const std::string text) { IMSA_HILOGI("InputMethodAbility::InsertText"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::InsertText channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->InsertText(Utils::ToStr16(text)); } int32_t InputMethodAbility::DeleteForward(int32_t length) { IMSA_HILOGI("InputMethodAbility::DeleteForward"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::DeleteForward channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->DeleteForward(length); } int32_t InputMethodAbility::DeleteBackward(int32_t length) { IMSA_HILOGI("InputMethodAbility::DeleteBackward"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::DeleteBackward channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->DeleteBackward(length); } int32_t InputMethodAbility::SendFunctionKey(int32_t funcKey) { IMSA_HILOGI("InputMethodAbility::SendFunctionKey"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::SendFunctionKey channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->SendFunctionKey(funcKey); } int32_t InputMethodAbility::HideKeyboardSelf() { IMSA_HILOGI("InputMethodAbility::HideKeyboardSelf"); std::shared_ptr controlChannel = GetInputControlChannel(); if (controlChannel == nullptr) { IMSA_HILOGI("InputMethodAbility::HideKeyboardSelf controlChannel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return controlChannel->HideKeyboardSelf(1); } int32_t InputMethodAbility::GetTextBeforeCursor(int32_t number, std::u16string &text) { IMSA_HILOGI("InputMethodAbility::GetTextBeforeCursor"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::GetTextBeforeCursor channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->GetTextBeforeCursor(number, text); } int32_t InputMethodAbility::GetTextAfterCursor(int32_t number, std::u16string &text) { IMSA_HILOGI("InputMethodAbility::GetTextAfterCursor"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::GetTextAfterCursor channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->GetTextAfterCursor(number, text); } int32_t InputMethodAbility::MoveCursor(int32_t keyCode) { IMSA_HILOGI("InputMethodAbility::MoveCursor"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::MoveCursor channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->MoveCursor(keyCode); } int32_t InputMethodAbility::GetEnterKeyType(int32_t &keyType) { IMSA_HILOGI("InputMethodAbility::GetEnterKeyType"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::GetEnterKeyType channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->GetEnterKeyType(keyType); } int32_t InputMethodAbility::GetInputPattern(int32_t &inputPattern) { IMSA_HILOGI("InputMethodAbility::GetInputPattern"); std::shared_ptr channel = GetInputDataChannel(); if (channel == nullptr) { IMSA_HILOGI("InputMethodAbility::GetInputPattern channel is nullptr"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } return channel->GetInputPattern(inputPattern); } void InputMethodAbility::SetInputDataChannel(sptr &object) { IMSA_HILOGI("run in SetInputDataChannel"); std::lock_guard lock(dataChannelLock_); std::shared_ptr channalProxy = std::make_shared(object); if (channalProxy == nullptr) { IMSA_HILOGI("InputMethodAbility::SetInputDataChannel inputDataChannel is nullptr"); return; } dataChannel_ = channalProxy; } std::shared_ptr InputMethodAbility::GetInputDataChannel() { std::lock_guard lock(dataChannelLock_); return dataChannel_; } void InputMethodAbility::SetInputControlChannel(sptr &object) { IMSA_HILOGI("run in SetInputControlChannel"); std::lock_guard lock(controlChannelLock_); std::shared_ptr channalProxy = std::make_shared(object); if (channalProxy == nullptr) { IMSA_HILOGI("InputMethodAbility::SetInputControlChannel inputDataChannel is nullptr"); return; } controlChannel_ = channalProxy; } std::shared_ptr InputMethodAbility::GetInputControlChannel() { std::lock_guard lock(controlChannelLock_); return controlChannel_; } void InputMethodAbility::ServiceDeathRecipient::OnRemoteDied(const wptr &object) { IMSA_HILOGI("ServiceDeathRecipient::OnRemoteDied"); if (listener != nullptr) { listener->OnInputStop(currentIme_); } } void InputMethodAbility::QuitWorkThread() { stop_ = true; Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr); msgHandler->SendMessage(msg); if (workThreadHandler.joinable()) { workThreadHandler.join(); } } } // namespace MiscServices } // namespace OHOS