* Copyright (C) 2021-2023 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 <unistd.h>
#include <cinttypes>
#include <utility>
#include "global.h"
#include "ima_hisysevent_reporter.h"
#include "input_method_agent_service_impl.h"
#include "input_method_core_service_impl.h"
#include "input_method_system_ability_proxy.h"
#include "input_method_tools.h"
#include "input_method_utils.h"
#include "inputmethod_sysevent.h"
#include "inputmethod_trace.h"
#include "iservice_registry.h"
#include "itypes_util.h"
#include "message_parcel.h"
#include "on_demand_start_stop_sa.h"
#include "string_ex.h"
#include "sys/prctl.h"
#include "system_ability_definition.h"
#include "task_manager.h"
#include "tasks/task.h"
#include "tasks/task_imsa.h"
#include "variant_util.h"
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
#include "histogram_plugin_macros.h"
#endif
namespace OHOS {
namespace MiscServices {
using namespace MessageID;
using namespace std::chrono;
constexpr double INVALID_CURSOR_VALUE = -1.0;
constexpr int32_t INVALID_SELECTION_VALUE = -1;
constexpr uint32_t FIND_PANEL_RETRY_INTERVAL = 10;
constexpr uint32_t MAX_RETRY_TIMES = 100;
constexpr uint32_t START_INPUT_CALLBACK_TIMEOUT_MS = 1000;
constexpr uint32_t INVALID_SECURITY_MODE = -1;
constexpr uint32_t MAX_PRIVATE_COMMAND_QUEUE_SIZE = 10;
InputMethodAbility::InputMethodAbility()
{
Initialize();
}
InputMethodAbility::~InputMethodAbility()
{
IMSA_HILOGI("InputMethodAbility::~InputMethodAbility.");
}
InputMethodAbility &InputMethodAbility::GetInstance()
{
static InputMethodAbility instance;
return instance;
}
sptr<IInputMethodSystemAbility> InputMethodAbility::GetImsaProxy()
{
std::lock_guard<std::mutex> lock(abilityLock_);
if (abilityManager_ != nullptr) {
return abilityManager_;
}
IMSA_HILOGI("InputMethodAbility get imsa proxy.");
auto systemAbility = OnDemandStartStopSa::GetInputMethodSystemAbility();
if (systemAbility == nullptr) {
IMSA_HILOGE("systemAbility is nullptr!");
return nullptr;
}
if (deathRecipient_ == nullptr) {
deathRecipient_ = new (std::nothrow) InputDeathRecipient();
if (deathRecipient_ == nullptr) {
IMSA_HILOGE("failed to new death recipient!");
return nullptr;
}
}
deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) {
OnRemoteSaDied(remote);
});
if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
IMSA_HILOGE("failed to add death recipient!");
return nullptr;
}
abilityManager_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
return abilityManager_;
}
int32_t InputMethodAbility::SetCoreAndAgent()
{
IMSA_HILOGD("InputMethodAbility, start.");
TaskManager::GetInstance().SetInited(true);
if (isBound_.load()) {
IMSA_HILOGD("already bound.");
return ErrorCode::NO_ERROR;
}
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("imsa proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
int32_t ret = proxy->SetCoreAndAgent(coreStub_, agentStub_->AsObject());
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;
}
int32_t InputMethodAbility::InitConnect()
{
IMSA_HILOGD("InputMethodAbility, init connect.");
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("imsa proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
int32_t ret = proxy->InitConnect();
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("set failed, ret: %{public}d!", ret);
return ret;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::RegisterProxyIme(uint64_t displayId)
{
IMSA_HILOGD("IMA, displayId: %{public}" PRIu64 "", displayId);
TaskManager::GetInstance().SetInited(true);
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("imsa proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
if (agentStub_ == nullptr) {
IMSA_HILOGE("agent nullptr");
return ErrorCode::ERROR_NULL_POINTER;
}
int32_t ret = proxy->RegisterProxyIme(displayId, coreStub_, agentStub_->AsObject());
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed, displayId: %{public}" PRIu64 ", ret: %{public}d!", displayId, ret);
return ret;
}
isBound_.store(true);
isProxyIme_.store(true);
IMSA_HILOGD("set successfully, displayId: %{public}" PRIu64 "", displayId);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::UnregisterProxyIme(uint64_t displayId, UnRegisteredType type)
{
isBound_.store(false);
isProxyIme_.store(false);
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("imsa proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
return proxy->UnregisterProxyIme(displayId, static_cast<int32_t>(type));
}
int32_t InputMethodAbility::BindImeMirror()
{
TaskManager::GetInstance().SetInited(true);
if (isBound_.load()) {
IMSA_HILOGD("[ImeMirrorTag]already bound.");
return ErrorCode::NO_ERROR;
}
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("[ImeMirrorTag]imsa proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
if (agentStub_ == nullptr) {
IMSA_HILOGE("[ImeMirrorTag]agent nullptr");
return ErrorCode::ERROR_NULL_POINTER;
}
auto ret = proxy->BindImeMirror(coreStub_, agentStub_->AsObject());
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("[ImeMirrorTag]failed, ret: %{public}d!", ret);
return ret;
}
IMSA_HILOGD("[ImeMirrorTag]register imsa start event");
imeMirrorMgr_.SubscribeSaStart(
[this]() {
if (!imeMirrorMgr_.IsImeMirrorEnable()) {
IMSA_HILOGI("[ImeMirrorTag]imsa started, no need resume ime mirror");
return;
}
IMSA_HILOGI("[ImeMirrorTag]imsa started, resume ime mirror");
BindImeMirror();
},
INPUT_METHOD_SYSTEM_ABILITY_ID);
isBound_.store(true);
imeMirrorMgr_.SetImeMirrorEnable(true);
IMSA_HILOGI("[ImeMirrorTag]set successfully");
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::UnbindImeMirror()
{
isBound_.store(false);
imeMirrorMgr_.SetImeMirrorEnable(false);
imeMirrorMgr_.UnSubscribeSaStart(INPUT_METHOD_SYSTEM_ABILITY_ID);
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("[ImeMirrorTag]imsa proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
return proxy->UnbindImeMirror();
}
void InputMethodAbility::Initialize()
{
IMSA_HILOGD("IMA init.");
sptr<InputMethodCoreStub> coreStub = new (std::nothrow) InputMethodCoreServiceImpl();
if (coreStub == nullptr) {
IMSA_HILOGE("failed to create core!");
return;
}
sptr<InputMethodAgentStub> agentStub = new (std::nothrow) InputMethodAgentServiceImpl();
if (agentStub == nullptr) {
IMSA_HILOGE("failed to create agent!");
return;
}
agentStub_ = agentStub;
coreStub_ = coreStub;
}
void InputMethodAbility::SetConfigurationUpdate(std::function<void(Rosen::DisplayId displayId)> configurationUpdate)
{
configurationUpdate_ = configurationUpdate;
}
void InputMethodAbility::ConfigurationUpdate(Rosen::DisplayId displayId)
{
if (configurationUpdate_ != nullptr) {
configurationUpdate_(displayId);
}
}
void InputMethodAbility::SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)
{
IMSA_HILOGD("InputMethodAbility start.");
if (imeListener_ == nullptr) {
imeListener_ = std::move(imeListener);
}
}
std::shared_ptr<InputMethodEngineListener> InputMethodAbility::GetImeListener()
{
return imeListener_;
}
void InputMethodAbility::SetKdListener(std::shared_ptr<KeyboardListener> kdListener)
{
IMSA_HILOGD("InputMethodAbility start.");
if (kdListener_ == nullptr) {
kdListener_ = std::move(kdListener);
}
}
void InputMethodAbility::SetTextInputClientListener(std::shared_ptr<TextInputClientListener> textInputClientListener)
{
IMSA_HILOGD("InputMethodAbility start.");
if (textInputClientListener_ == nullptr) {
textInputClientListener_ = std::move(textInputClientListener);
}
}
void InputMethodAbility::OnInitInputControlChannel(sptr<IRemoteObject> channelObj)
{
IMSA_HILOGD("InputMethodAbility::OnInitInputControlChannel start.");
SetInputControlChannel(channelObj);
}
int32_t InputMethodAbility::StartInputInner(const InputClientInfo &clientInfo, bool isBindFromClient)
{
SetBindClientInfo(clientInfo);
if (clientInfo.channel == nullptr) {
IMSA_HILOGE("channelObject is nullptr!");
return ErrorCode::ERROR_IMA_CHANNEL_NULLPTR;
}
IMSA_HILOGI("IMA showKeyboard:%{public}d,bindFromClient:%{public}d.", clientInfo.isShowKeyboard, isBindFromClient);
SetInputDataChannel(clientInfo.channel);
auto attribute = GetInputAttribute();
ConfigurationUpdate(attribute.callingDisplayId);
if ((clientInfo.needHide && !isProxyIme_.load()) ||
IsDisplayChanged(attribute.callingDisplayId, clientInfo.config.inputAttribute.callingDisplayId)) {
IMSA_HILOGD("pwd or normal input pattern changed, need hide panel first.");
auto panel = GetSoftKeyboardPanel();
if (panel != nullptr) {
panel->HidePanel();
}
}
int32_t ret = isBindFromClient
? InvokeStartInputCallback(clientInfo.config, clientInfo.isNotifyInputStart)
: InvokeStartInputCallbackWithInfoRestruct(clientInfo.config, clientInfo.isNotifyInputStart);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to invoke callback, ret: %{public}d!", ret);
return ret;
}
auto time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
auto showPanel = [&, needShow = clientInfo.isShowKeyboard, startTime = time] {
auto endTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
int32_t ret = ErrorCode::NO_ERROR;
if (needShow) {
ret = ShowKeyboardWithoutLock(cmdId_, InputStartScene::ATTACH);
} else {
NotifyInputStartToClients(InputStartScene::ATTACH, false);
}
ReportImeStartInput(
static_cast<int32_t>(IInputMethodCoreIpcCode::COMMAND_START_INPUT), ret, needShow, endTime - startTime);
isImeTerminating_.store(false);
};
uint64_t seqId = Task::GetNextSeqId();
if (imeListener_ == nullptr || !imeListener_->PostTaskToEventHandler(
[seqId] { TaskManager::GetInstance().Complete(seqId); }, "task_manager_complete")) {
showPanel();
return ErrorCode::NO_ERROR;
}
TaskManager::GetInstance().WaitExec(seqId, START_INPUT_CALLBACK_TIMEOUT_MS, showPanel);
return ErrorCode::NO_ERROR;
}
bool InputMethodAbility::IsDisplayChanged(uint64_t oldDisplayId, uint64_t newDisplayId)
{
if (oldDisplayId == newDisplayId) {
IMSA_HILOGD("screen not changed!");
return false;
}
IMSA_HILOGD("screen changed!");
return true;
}
void InputMethodAbility::OnSetSubtype(SubProperty subProperty)
{
if (imeListener_ != nullptr) {
imeListener_->OnSetSubtype(subProperty);
}
}
void InputMethodAbility::OnSetInputType(InputType inputType, uint64_t displayId)
{
inputType_ = inputType;
if (displayId == ImfCommonConst::DEFAULT_DISPLAY_ID) {
NotifyPanelStatus(false);
}
IMSA_HILOGD("OnSetInputType, inputType = %{public}d, displayId = %{public}" PRIu64 "",
static_cast<int32_t>(inputType), displayId);
}
InputType InputMethodAbility::GetInputType()
{
return inputType_;
}
void InputMethodAbility::ClearDataChannel(const sptr<IRemoteObject> &channel)
{
std::lock_guard<std::mutex> lock(dataChannelLock_);
if (dataChannelObject_ == nullptr || channel == nullptr) {
IMSA_HILOGD("dataChannelObject_ already nullptr.");
return;
}
if (dataChannelObject_.GetRefPtr() == channel.GetRefPtr()) {
if (dataChannelDeathRecipient_ != nullptr) {
if (!dataChannelObject_->RemoveDeathRecipient(dataChannelDeathRecipient_)) {
IMSA_HILOGE("RemoveDeathRecipient failed");
}
dataChannelDeathRecipient_ = nullptr;
}
dataChannelObject_ = nullptr;
if (dataChannelProxyWrap_ != nullptr) {
dataChannelProxyWrap_->ClearRspHandlers();
}
dataChannelProxyWrap_ = nullptr;
IMSA_HILOGD("end.");
}
}
int32_t InputMethodAbility::StopInput(
sptr<IRemoteObject> channelObject, uint32_t sessionId, int32_t clientSessionId)
{
std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
int32_t cmdCount = ++cmdId_;
IMSA_HILOGI("IMA, sessionId: %{public}u, clientSessionId: %{public}d", sessionId, clientSessionId);
HideKeyboardImplWithoutLock(cmdCount, sessionId, clientSessionId);
ClearBindInfo(channelObject);
ClearInputType();
if (imeListener_ != nullptr) {
imeListener_->OnInputFinish();
}
return ErrorCode::NO_ERROR;
}
void InputMethodAbility::ClearBindInfo(const sptr<IRemoteObject> &channel)
{
ClearDataChannel(channel);
ClearInputAttribute();
ClearAttachOptions();
ClearBindClientInfo();
}
int32_t InputMethodAbility::DispatchKeyEvent(
const std::shared_ptr<MMI::KeyEvent> &keyEvent, uint64_t cbId, const sptr<IRemoteObject> &channelObject)
{
if (keyEvent == nullptr) {
IMSA_HILOGE("keyEvent is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
if (kdListener_ == nullptr) {
IMSA_HILOGE("kdListener_ is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
IMSA_HILOGD("InputMethodAbility, start.");
if (!kdListener_->OnDealKeyEvent(keyEvent, cbId, channelObject)) {
IMSA_HILOGE("keyEvent not deal!");
return ErrorCode::ERROR_DISPATCH_KEY_EVENT;
}
return ErrorCode::NO_ERROR;
}
void InputMethodAbility::SetCallingWindow(uint32_t rawEditorWindowId, const FocusedInfo &focusedInfo)
{
IMSA_HILOGD("InputMethodAbility rawEditorWindowId/focusedInfo: %{public}u/%{public}s.", rawEditorWindowId,
focusedInfo.ToString().c_str());
{
std::lock_guard<std::mutex> lock(inputAttrLock_);
inputAttribute_.windowId = focusedInfo.keyboardWindowId;
inputAttribute_.editorWindowId = focusedInfo.windowId;
}
panels_.ForEach([keyboardWindowId = focusedInfo.keyboardWindowId](
const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
panel->SetCallingWindow(keyboardWindowId);
return false;
});
if (imeListener_ != nullptr) {
imeListener_->OnSetCallingWindow(rawEditorWindowId);
}
NotifyInputStartToClients(InputStartScene::WINDOW_CHANGED);
OnCallingDisplayIdChanged(focusedInfo.displayId, focusedInfo.keyboardDisplayId);
}
void InputMethodAbility::OnCursorUpdate(int32_t positionX, int32_t positionY, int32_t height)
{
if (kdListener_ == nullptr) {
IMSA_HILOGE("kdListener_ is nullptr!");
return;
}
IMSA_HILOGD("IMA, x: %{public}d, y: %{public}d, height: %{public}d.", positionX, positionY, height);
kdListener_->OnCursorUpdate(positionX, positionY, height);
}
void InputMethodAbility::OnSelectionChange(
std::u16string text, int32_t oldBegin, int32_t oldEnd, int32_t newBegin, int32_t newEnd)
{
if (kdListener_ == nullptr) {
IMSA_HILOGE("kdListener_ is nullptr!");
return;
}
kdListener_->OnTextChange(Str16ToStr8(text));
kdListener_->OnSelectionChange(oldBegin, oldEnd, newBegin, newEnd);
}
void InputMethodAbility::OnAttributeChange(InputAttribute attribute)
{
if (kdListener_ == nullptr) {
IMSA_HILOGE("kdListener_ is nullptr!");
return;
}
IMSA_HILOGD("enterKeyType: %{public}d, inputPattern: %{public}d, consumeKeyEvents: %{public}d.",
attribute.enterKeyType, attribute.inputPattern, attribute.consumeKeyEvents);
attribute.bundleName = GetInputAttribute().bundleName;
attribute.windowId = GetInputAttribute().windowId;
attribute.callingDisplayId = GetInputAttribute().callingDisplayId;
SetInputAttribute(attribute);
NotifyPanelStatus(false);
kdListener_->OnEditorAttributeChange(attribute);
}
void InputMethodAbility::OnFunctionKey(int32_t funcKey)
{
if (kdListener_ == nullptr) {
IMSA_HILOGE("kdListener_ is nullptr!");
return;
}
kdListener_->OnFunctionKey(funcKey);
}
int32_t InputMethodAbility::OnStopInputService(bool isTerminateIme)
{
IMSA_HILOGI("isTerminateIme: %{public}d.", isTerminateIme);
isBound_.store(false);
auto imeListener = GetImeListener();
if (imeListener == nullptr) {
return ErrorCode::ERROR_IME_NOT_STARTED;
}
if (isTerminateIme) {
isImeTerminating_.store(true);
return imeListener->OnInputStop();
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::OnDiscardTypingText()
{
auto imeListener = GetImeListener();
if (imeListener == nullptr) {
IMSA_HILOGE("imeListener is nullptr!");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
return imeListener_->OnDiscardTypingText();
}
int32_t InputMethodAbility::HideKeyboard()
{
std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
int32_t cmdCount = ++cmdId_;
return HideKeyboardImplWithoutLock(cmdCount, 0);
}
int32_t InputMethodAbility::HideKeyboardImplWithoutLock(int32_t cmdId, uint32_t sessionId, int32_t clientSessionId)
{
NotifyInputStopToClients();
if (cmdId != cmdId_) {
IMSA_HILOGE("current is not last cmd cur: %{public}d, cmdId_: %{public}d!", cmdId, cmdId_);
return ErrorCode::NO_ERROR;
}
return HideKeyboard(Trigger::IMF, sessionId, clientSessionId);
}
int32_t InputMethodAbility::ShowKeyboard(int32_t requestKeyboardReason)
{
std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
int32_t cmdCount = ++cmdId_;
HandleRequestKeyboardReasonChanged(static_cast<RequestKeyboardReason>(requestKeyboardReason));
return ShowKeyboardWithoutLock(cmdCount, InputStartScene::SHOW_KEYBOARD);
}
int32_t InputMethodAbility::ShowKeyboardWithoutLock(int32_t cmdId, InputStartScene scene)
{
auto ret = ShowKeyboardImplWithoutLock(cmdId);
NotifyInputStartToClients(scene);
return ret;
}
int32_t InputMethodAbility::ShowKeyboardImplWithoutLock(int32_t cmdId)
{
if (cmdId != cmdId_) {
IMSA_HILOGE("current is not last cmd cur: %{public}d, cmdId_: %{public}d!", cmdId, cmdId_);
return ErrorCode::NO_ERROR;
}
if (imeListener_ == nullptr) {
IMSA_HILOGE("imeListener is nullptr!");
return ErrorCode::ERROR_IME;
}
IMSA_HILOGI("IMA start.");
if (panels_.Contains(SOFT_KEYBOARD)) {
auto panel = GetSoftKeyboardPanel();
if (panel == nullptr) {
IMSA_HILOGE("panel is nullptr!");
return ErrorCode::ERROR_IME;
}
auto flag = panel->GetPanelFlag();
imeListener_->OnKeyboardStatus(true);
if (flag == FLG_CANDIDATE_COLUMN) {
IMSA_HILOGI("panel flag is candidate, no need to show.");
NotifyKeyboardHeight(0, flag);
return ErrorCode::NO_ERROR;
}
return ShowPanel(panel, flag, Trigger::IMF);
}
isShowAfterCreate_.store(true);
IMSA_HILOGI("panel not create.");
auto channel = GetInputDataChannelProxy();
if (channel != nullptr) {
channel->SendKeyboardStatus(static_cast<int32_t>(KeyboardStatus::SHOW));
}
imeListener_->OnKeyboardStatus(true);
return ErrorCode::NO_ERROR;
}
void InputMethodAbility::NotifyInputStartToClients(InputStartScene scene, bool isShowKeyboard)
{
if (isProxyIme_.load()) {
IMSA_HILOGD("proxy ime, no need to notify.");
return;
}
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("imsa proxy is nullptr!");
return;
}
InputStartInfo info;
info.scene = scene;
info.clientInfo.isShowKeyboard = isShowKeyboard;
info.clientInfo.windowId = GetInputAttribute().editorWindowId;
info.clientInfo.displayId = GetInputAttribute().editorDisplayId;
info.clientInfo.requestKeyboardReason = static_cast<int32_t>(GetAttachOptions().requestKeyboardReason);
auto panel = GetSoftKeyboardPanel();
if (panel == nullptr) {
info.imeInfo.status = InputWindowStatus::HIDE;
proxy->NotifyInputStart(info);
return;
}
info.imeInfo.panelFlag = panel->GetPanelFlag();
info.imeInfo.status = panel->IsShowing() ? InputWindowStatus::SHOW : InputWindowStatus::HIDE;
info.imeInfo.displayId = ImfCommonConst::DEFAULT_DISPLAY_ID;
if (info.imeInfo.status == InputWindowStatus::HIDE) {
proxy->NotifyInputStart(info);
return;
}
info.imeInfo.displayId = GetInputAttribute().callingDisplayId;
if (scene != InputStartScene::ATTACH && scene != InputStartScene::SHOW_KEYBOARD) {
auto ret = panel->GetDisplayId(info.imeInfo.displayId);
if (ret != ErrorCode::NO_ERROR) {
info.imeInfo.displayId = GetInputAttribute().callingDisplayId;
}
}
proxy->NotifyInputStart(info);
}
void InputMethodAbility::NotifyInputStopToClients()
{
if (isProxyIme_.load()) {
IMSA_HILOGD("proxy ime, no need to notify.");
return;
}
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("imsa proxy is nullptr!");
return;
}
InputStopInfo info;
info.scene = InputStopScene::CLIENT_TRIGGER;
info.displayId = GetInputAttribute().editorDisplayId;
proxy->NotifyInputStop(info);
}
void InputMethodAbility::NotifyPanelStatusInfo(PanelStatusInfo &info)
{
auto channel = GetInputDataChannelProxy();
NotifyPanelStatusInfo(info, channel);
}
int32_t InputMethodAbility::InvokeStartInputCallbackWithInfoRestruct(
const TextTotalConfig &textConfig, bool isNotifyInputStart)
{
TextTotalConfig newTextConfig = {};
int32_t ret = GetTextConfig(newTextConfig);
if (ret == ErrorCode::NO_ERROR) {
newTextConfig.inputAttribute.bundleName = textConfig.inputAttribute.bundleName;
newTextConfig.inputAttribute.callingDisplayId = textConfig.inputAttribute.callingDisplayId;
newTextConfig.inputAttribute.windowId = textConfig.inputAttribute.windowId;
newTextConfig.inputAttribute.editorDisplayId = textConfig.inputAttribute.editorDisplayId;
newTextConfig.inputAttribute.editorWindowId = textConfig.inputAttribute.editorWindowId;
newTextConfig.isSimpleKeyboardEnabled = textConfig.isSimpleKeyboardEnabled;
return InvokeStartInputCallback(newTextConfig, isNotifyInputStart);
}
IMSA_HILOGW("failed to get text config, ret: %{public}d.", ret);
if (imeListener_ == nullptr) {
IMSA_HILOGE("imeListener_ is nullptr!");
return ErrorCode::ERROR_IME;
}
if (isNotifyInputStart) {
imeListener_->OnInputStart();
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::InvokeStartInputCallback(const TextTotalConfig &textConfig, bool isNotifyInputStart)
{
if (imeListener_ == nullptr) {
IMSA_HILOGE("imeListener_ is nullptr!");
return ErrorCode::ERROR_IME;
}
positionY_ = textConfig.positionY;
height_ = textConfig.height;
NotifyInfoToWmsInStartInput(textConfig);
IMSA_HILOGI("attributeInfo:%{public}s, isNotifyInputStartInfo:%{public}d/%{public}d.",
textConfig.inputAttribute.InfoLog().c_str(), isNotifyInputStart, isInputStartNotified_);
SetInputAttribute(textConfig.inputAttribute);
if (kdListener_ != nullptr) {
kdListener_->OnEditorAttributeChange(textConfig.inputAttribute);
}
AttachOptions options;
options.requestKeyboardReason = textConfig.requestKeyboardReason;
options.isSimpleKeyboardEnabled = textConfig.isSimpleKeyboardEnabled;
InvokeAttachOptionsCallback(options, isNotifyInputStart || !isInputStartNotified_);
if (isNotifyInputStart || !isInputStartNotified_) {
isInputStartNotified_ = true;
IMSA_HILOGD("OnInputStart begin");
imeListener_->OnInputStart();
}
if (TextConfig::IsPrivateCommandValid(textConfig.privateCommand) && IsDefaultIme()) {
imeListener_->ReceivePrivateCommand(textConfig.privateCommand);
}
if (kdListener_ != nullptr) {
if (textConfig.cursorInfo.left != INVALID_CURSOR_VALUE) {
kdListener_->OnCursorUpdate(
textConfig.cursorInfo.left, textConfig.cursorInfo.top, textConfig.cursorInfo.height);
}
if (textConfig.textSelection.newBegin == INVALID_SELECTION_VALUE ||
(textConfig.textSelection.newBegin == textConfig.textSelection.oldBegin &&
textConfig.textSelection.newEnd == textConfig.textSelection.oldEnd)) {
IMSA_HILOGD("invalid selection or no selection change");
} else {
kdListener_->OnSelectionChange(textConfig.textSelection.oldBegin, textConfig.textSelection.oldEnd,
textConfig.textSelection.newBegin, textConfig.textSelection.newEnd);
}
}
if (textConfig.windowId != INVALID_WINDOW_ID) {
imeListener_->OnSetCallingWindow(textConfig.windowId);
}
return ErrorCode::NO_ERROR;
}
void InputMethodAbility::HandleRequestKeyboardReasonChanged(const RequestKeyboardReason &requestKeyboardReason)
{
AttachOptions options;
options.requestKeyboardReason = requestKeyboardReason;
options.isSimpleKeyboardEnabled = GetAttachOptions().isSimpleKeyboardEnabled;
InvokeAttachOptionsCallback(options);
}
void InputMethodAbility::InvokeAttachOptionsCallback(const AttachOptions &options, bool isFirstNotify)
{
auto oldOptions = GetAttachOptions();
if (!isFirstNotify && oldOptions.isSimpleKeyboardEnabled == options.isSimpleKeyboardEnabled
&& options.requestKeyboardReason == oldOptions.requestKeyboardReason) {
return;
}
SetAttachOptions(options);
if (textInputClientListener_ != nullptr) {
textInputClientListener_->OnAttachOptionsChanged(options);
}
}
void InputMethodAbility::SetAttachOptions(const AttachOptions &options)
{
std::lock_guard<std::mutex> lock(attachOptionsLock_);
attachOptions_ = options;
}
void InputMethodAbility::ClearAttachOptions()
{
std::lock_guard<std::mutex> lock(attachOptionsLock_);
attachOptions_ = {};
}
AttachOptions InputMethodAbility::GetAttachOptions()
{
std::lock_guard<std::mutex> lock(attachOptionsLock_);
return attachOptions_;
}
int32_t InputMethodAbility::InsertText(const std::string &text, const AsyncIpcCallBack &callback)
{
InputMethodSyncTrace tracer("IMA_InsertText");
IMSA_HILOGD("InputMethodAbility start.");
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_IMA_CHANNEL_NULLPTR;
}
return channel->InsertText(text, callback);
}
int32_t InputMethodAbility::DeleteForward(int32_t length, const AsyncIpcCallBack &callback)
{
InputMethodSyncTrace tracer("IMA_DeleteForward");
IMSA_HILOGD("InputMethodAbility start, length: %{public}d.", length);
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_IMA_CHANNEL_NULLPTR;
}
return channel->DeleteForward(length, callback);
}
int32_t InputMethodAbility::DeleteBackward(int32_t length, const AsyncIpcCallBack &callback)
{
IMSA_HILOGD("InputMethodAbility start, length: %{public}d.", length);
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_IMA_CHANNEL_NULLPTR;
}
return channel->DeleteBackward(length, callback);
}
int32_t InputMethodAbility::SendFunctionKey(int32_t funcKey, const AsyncIpcCallBack &callback)
{
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return channel->SendFunctionKey(funcKey, callback);
}
int32_t InputMethodAbility::HideKeyboardSelf()
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethodEngine.KeyboardController.hide", 1);
#endif
if (isImeTerminating_.load()) {
IMSA_HILOGI("Current Ime is terminating, no need to hide keyboard.");
return ErrorCode::NO_ERROR;
}
InputMethodSyncTrace tracer("IMA_HideKeyboardSelf start.");
auto ret = HideKeyboard(Trigger::IME_APP, 0);
if (ret == ErrorCode::NO_ERROR) {
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_SELF);
}
return ret == ErrorCode::ERROR_CLIENT_NULL_POINTER ? ret : ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::SendExtendAction(int32_t action, const AsyncIpcCallBack &callback)
{
IMSA_HILOGD("InputMethodAbility, action: %{public}d.", action);
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return channel->HandleExtendAction(action, callback);
}
int32_t InputMethodAbility::GetTextBeforeCursor(int32_t number, std::u16string &text, const AsyncIpcCallBack &callback)
{
InputMethodSyncTrace tracer("IMA_GetForward");
IMSA_HILOGD("InputMethodAbility, number: %{public}d.", number);
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
std::string textu8 = "";
auto ret = channel->GetTextBeforeCursor(number, textu8, callback);
text = Str8ToStr16(textu8);
return ret;
}
int32_t InputMethodAbility::GetTextAfterCursor(
int32_t number, std::u16string &text, const AsyncIpcCallBack &callback)
{
InputMethodSyncTrace tracer("IMA_GetTextAfterCursor");
IMSA_HILOGD("InputMethodAbility, number: %{public}d.", number);
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
std::string textu8 = "";
auto ret = channel->GetTextAfterCursor(number, textu8, callback);
text = Str8ToStr16(textu8);
return ret;
}
int32_t InputMethodAbility::MoveCursor(int32_t keyCode, const AsyncIpcCallBack &callback)
{
IMSA_HILOGD("InputMethodAbility, keyCode: %{public}d.", keyCode);
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return channel->MoveCursor(keyCode, callback);
}
int32_t InputMethodAbility::SelectByRange(int32_t start, int32_t end, const AsyncIpcCallBack &callback)
{
IMSA_HILOGD("InputMethodAbility, start: %{public}d, end: %{public}d", start, end);
if (start < 0 || end < 0) {
IMSA_HILOGE("check parameter failed, start: %{public}d, end: %{public}d!", start, end);
return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
}
auto dataChannel = GetInputDataChannelProxyWrap();
if (dataChannel == nullptr) {
IMSA_HILOGE("datachannel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return dataChannel->SelectByRange(start, end, callback);
}
int32_t InputMethodAbility::SelectByMovement(int32_t direction, const AsyncIpcCallBack &callback)
{
IMSA_HILOGD("InputMethodAbility, direction: %{public}d.", direction);
auto dataChannel = GetInputDataChannelProxyWrap();
if (dataChannel == nullptr) {
IMSA_HILOGE("datachannel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return dataChannel->SelectByMovement(direction, 0, callback);
}
int32_t InputMethodAbility::GetEnterKeyType(int32_t &keyType)
{
IMSA_HILOGD("InputMethodAbility start.");
auto channel = GetInputDataChannelProxy();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return channel->GetEnterKeyType(keyType);
}
int32_t InputMethodAbility::GetInputPattern(int32_t &inputPattern)
{
IMSA_HILOGD("InputMethodAbility start.");
auto channel = GetInputDataChannelProxy();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return channel->GetInputPattern(inputPattern);
}
int32_t InputMethodAbility::GetTextIndexAtCursor(int32_t &index, const AsyncIpcCallBack &callback)
{
IMSA_HILOGD("InputMethodAbility start.");
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return channel->GetTextIndexAtCursor(index, callback);
}
int32_t InputMethodAbility::GetTextConfig(TextTotalConfig &textConfig)
{
IMSA_HILOGI("InputMethodAbility start.");
auto channel = GetInputDataChannelProxy();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
TextTotalConfigInner textConfigInner = InputMethodTools::GetInstance().TextTotalConfigToInner(textConfig);
auto ret = channel->GetTextConfig(textConfigInner);
if (ret == ErrorCode::NO_ERROR) {
textConfig = InputMethodTools::GetInstance().InnerToTextTotalConfig(textConfigInner);
textConfig.inputAttribute.bundleName = GetInputAttribute().bundleName;
textConfig.inputAttribute.callingDisplayId = GetInputAttribute().callingDisplayId;
textConfig.inputAttribute.windowId = GetInputAttribute().windowId;
textConfig.inputAttribute.editorDisplayId = GetInputAttribute().editorDisplayId;
textConfig.inputAttribute.editorWindowId = GetInputAttribute().editorWindowId;
}
return ret;
}
void InputMethodAbility::SetInputDataChannel(const sptr<IRemoteObject> &object)
{
IMSA_HILOGD("SetInputDataChannel start.");
if (object == nullptr) {
IMSA_HILOGE("object is nullptr.");
return;
}
std::lock_guard<std::mutex> lock(dataChannelLock_);
if (dataChannelObject_ != nullptr && object != nullptr && object.GetRefPtr() == dataChannelObject_.GetRefPtr()) {
IMSA_HILOGD("datachannel has already been set.");
return;
}
auto channelProxy = std::make_shared<InputDataChannelProxy>(object);
if (channelProxy == nullptr) {
IMSA_HILOGE("failed to create channel proxy!");
return;
}
sptr<IRemoteObject> agentObject = nullptr;
if (agentStub_ != nullptr) {
agentObject = agentStub_->AsObject();
}
auto channelWrap = std::make_shared<InputDataChannelProxyWrap>(channelProxy, agentObject);
if (channelWrap == nullptr) {
IMSA_HILOGE("failed to create channel wrap!");
return;
}
if (dataChannelProxyWrap_ != nullptr) {
dataChannelProxyWrap_->ClearRspHandlers();
}
if (dataChannelObject_ != nullptr && dataChannelDeathRecipient_ != nullptr) {
if (!dataChannelObject_->RemoveDeathRecipient(dataChannelDeathRecipient_)) {
IMSA_HILOGE("RemoveDeathRecipient failed");
}
dataChannelDeathRecipient_ = nullptr;
}
dataChannelProxyWrap_ = channelWrap;
dataChannelObject_ = object;
dataChannelDeathRecipient_ = new (std::nothrow) InputDeathRecipient();
if (dataChannelDeathRecipient_ != nullptr) {
dataChannelDeathRecipient_->SetDeathRecipient(
[this, object](const wptr<IRemoteObject> &remote) { OnInputDataChannelDied(object); });
if (object->IsProxyObject() && !object->AddDeathRecipient(dataChannelDeathRecipient_)) {
IMSA_HILOGE("failed to add death recipient!");
}
}
}
void InputMethodAbility::OnInputDataChannelDied(const sptr<IRemoteObject> &dataChannelObject)
{
IMSA_HILOGW("data channel died!");
ClearDataChannel(dataChannelObject);
}
bool InputMethodAbility::NotifyInfoToWmsInStartInput(const TextTotalConfig &textConfig)
{
auto imeListener = GetImeListener();
if (imeListener == nullptr) {
IMSA_HILOGE("imeListener is nullptr!");
return false;
}
auto task = [this, textConfig]() {
panels_.ForEach([&textConfig](const PanelType &type, const std::shared_ptr<InputMethodPanel> &panel) {
if (panel == nullptr) {
return false;
}
if (type == SOFT_KEYBOARD && panel->GetPanelFlag() == FLG_FIXED && panel->IsShowing()) {
panel->SetTextFieldAvoidInfo(textConfig.positionY, textConfig.height);
}
return false;
});
};
return imeListener->PostTaskToEventHandler(task, "NotifyInfoToWms");
}
std::shared_ptr<InputDataChannelProxyWrap> InputMethodAbility::GetInputDataChannelProxyWrap()
{
if (imeMirrorMgr_.IsImeMirrorEnable()) {
IMSA_HILOGW("[ImeMirrorTag] not allow send to data channel");
return nullptr;
}
std::lock_guard<std::mutex> lock(dataChannelLock_);
return dataChannelProxyWrap_;
}
std::shared_ptr<InputDataChannelProxy> InputMethodAbility::GetInputDataChannelProxy()
{
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
return nullptr;
}
return channel->GetDataChannel();
}
void InputMethodAbility::SetInputControlChannel(sptr<IRemoteObject> &object)
{
IMSA_HILOGD("SetInputControlChannel start.");
std::lock_guard<std::mutex> lock(controlChannelLock_);
std::shared_ptr<InputControlChannelProxy> channelProxy = std::make_shared<InputControlChannelProxy>(object);
if (channelProxy == nullptr) {
IMSA_HILOGD("channelProxy is nullptr!");
return;
}
controlChannel_ = channelProxy;
}
void InputMethodAbility::ClearInputControlChannel()
{
std::lock_guard<std::mutex> lock(controlChannelLock_);
controlChannel_ = nullptr;
}
std::shared_ptr<InputControlChannelProxy> InputMethodAbility::GetInputControlChannel()
{
std::lock_guard<std::mutex> lock(controlChannelLock_);
return controlChannel_;
}
void InputMethodAbility::OnRemoteSaDied(const wptr<IRemoteObject> &object)
{
IMSA_HILOGI("input method service died.");
isBound_.store(false);
ClearDataChannel(dataChannelObject_);
ClearInputControlChannel();
ClearSystemCmdChannel();
{
std::lock_guard<std::mutex> lock(abilityLock_);
abilityManager_ = nullptr;
}
if (imeListener_ != nullptr) {
imeListener_->OnInputStop();
}
}
int32_t InputMethodAbility::GetSecurityMode(int32_t &security)
{
IMSA_HILOGI("InputMethodAbility start.");
int32_t securityMode = securityMode_.load();
if (securityMode != static_cast<int32_t>(INVALID_SECURITY_MODE)) {
IMSA_HILOGD("Get cache security mode: %{public}d.", securityMode);
security = securityMode;
return ErrorCode::NO_ERROR;
}
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("Imsa proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
auto ret = proxy->GetSecurityMode(security);
if (ret == ErrorCode::NO_ERROR) {
securityMode_.store(security);
}
return ret;
}
void InputMethodAbility::ClearSystemCmdChannel()
{
std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
if (systemCmdChannelProxy_ == nullptr) {
IMSA_HILOGD("systemCmdChannelProxy_ already nullptr.");
return;
}
systemCmdChannelProxy_ = nullptr;
IMSA_HILOGD("end.");
}
sptr<SystemCmdChannelProxy> InputMethodAbility::GetSystemCmdChannelProxy()
{
std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
return systemCmdChannelProxy_;
}
int32_t InputMethodAbility::OnConnectSystemCmd(const sptr<IRemoteObject> &channel)
{
IMSA_HILOGD("InputMethodAbility start.");
sptr<SystemCmdChannelProxy> cmdChannel = new (std::nothrow) SystemCmdChannelProxy(channel);
if (cmdChannel == nullptr) {
IMSA_HILOGE("failed to create channel proxy!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
{
std::lock_guard<std::mutex> lock(systemCmdChannelLock_);
systemCmdChannelProxy_ = cmdChannel;
}
PushPrivateCommand();
auto panel = GetSoftKeyboardPanel();
if (panel != nullptr) {
NotifyPanelStatus(false);
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::OnSecurityChange(int32_t security)
{
IMSA_HILOGI("InputMethodAbility start.");
securityMode_.store(security);
if (imeListener_ == nullptr) {
IMSA_HILOGE("imeListener_ is nullptr!");
return ErrorCode::ERROR_BAD_PARAMETERS;
}
imeListener_->OnSecurityChange(security);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::AdjustKeyboard()
{
if (panels_.Contains(SOFT_KEYBOARD)) {
auto panel = GetSoftKeyboardPanel();
if (panel == nullptr) {
IMSA_HILOGE("panel is nullptr!");
return ErrorCode::ERROR_IME;
}
auto flag = panel->GetPanelFlag();
if (flag != FLG_FIXED) {
IMSA_HILOGI("panel flag is not fix, no need to adjust.");
return ErrorCode::NO_ERROR;
}
return panel->AdjustKeyboard();
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context,
const PanelInfo &panelInfo, std::shared_ptr<InputMethodPanel> &inputMethodPanel)
{
IMSA_HILOGI("InputMethodAbility start.");
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethodEngine.createPanel", 1);
#endif
auto panelHeightCallback = [this](uint32_t panelHeight, PanelFlag panelFlag) {
NotifyKeyboardHeight(panelHeight, panelFlag);
};
auto flag = panels_.ComputeIfAbsent(panelInfo.panelType,
[panelHeightCallback, &panelInfo, &context, &inputMethodPanel](
const PanelType &panelType, std::shared_ptr<InputMethodPanel> &panel) {
inputMethodPanel = std::make_shared<InputMethodPanel>();
inputMethodPanel->SetPanelHeightCallback(panelHeightCallback);
auto ret = inputMethodPanel->CreatePanel(context, panelInfo);
if (ret == ErrorCode::NO_ERROR) {
panel = inputMethodPanel;
return true;
}
inputMethodPanel = nullptr;
return false;
});
if (flag && isShowAfterCreate_.load() && panelInfo.panelType == SOFT_KEYBOARD &&
panelInfo.panelFlag != FLG_CANDIDATE_COLUMN) {
isShowAfterCreate_.store(false);
auto task = std::make_shared<TaskImsaShowKeyboard>();
TaskManager::GetInstance().PostTask(task);
}
return flag ? ErrorCode::NO_ERROR : ErrorCode::ERROR_OPERATE_PANEL;
}
int32_t InputMethodAbility::DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
{
IMSA_HILOGI("InputMethodAbility start.");
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethodEngine.destroyPanel", 1);
#endif
if (inputMethodPanel == nullptr) {
IMSA_HILOGE("panel is nullptr!");
return ErrorCode::ERROR_BAD_PARAMETERS;
}
auto ret = inputMethodPanel->DestroyPanel();
if (ret == ErrorCode::NO_ERROR) {
PanelType panelType = inputMethodPanel->GetPanelType();
panels_.Erase(panelType);
}
return ret;
}
int32_t InputMethodAbility::ShowPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethodEngine.panel.show", 1);
#endif
std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
if (inputMethodPanel == nullptr) {
return ErrorCode::ERROR_BAD_PARAMETERS;
}
return ShowPanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP);
}
int32_t InputMethodAbility::HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethodEngine.panel.hide", 1);
#endif
if (inputMethodPanel == nullptr) {
return ErrorCode::ERROR_BAD_PARAMETERS;
}
if (isImeTerminating_.load() && inputMethodPanel->GetPanelType() == PanelType::SOFT_KEYBOARD) {
IMSA_HILOGI("Current Ime is terminating, no need to hide keyboard.");
return ErrorCode::NO_ERROR;
}
if (isShowAfterCreate_.load() && inputMethodPanel->GetPanelType() == PanelType::SOFT_KEYBOARD &&
inputMethodPanel->GetPanelFlag() != PanelFlag::FLG_CANDIDATE_COLUMN) {
isShowAfterCreate_.store(false);
}
std::lock_guard<std::recursive_mutex> lock(keyboardCmdLock_);
return HidePanel(inputMethodPanel, inputMethodPanel->GetPanelFlag(), Trigger::IME_APP, 0);
}
int32_t InputMethodAbility::ShowPanel(
const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger)
{
if (inputMethodPanel == nullptr) {
return ErrorCode::ERROR_IMA_NULLPTR;
}
if (trigger == Trigger::IME_APP && GetInputDataChannelProxyWrap() == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_IMA_CHANNEL_NULLPTR;
}
if (flag == FLG_FIXED && inputMethodPanel->GetPanelType() == SOFT_KEYBOARD) {
auto ret = inputMethodPanel->SetTextFieldAvoidInfo(positionY_, height_);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to set keyBoard, ret: %{public}d!", ret);
}
}
auto ret = inputMethodPanel->ShowPanel(trigger, GetInputAttribute().windowId);
if (ret == ErrorCode::NO_ERROR) {
NotifyPanelStatus(false, FLG_FIXED, true);
PanelStatusInfo info;
info.panelInfo.panelType = inputMethodPanel->GetPanelType();
info.panelInfo.panelFlag = flag;
info.visible = true;
info.trigger = trigger;
NotifyPanelStatusInfo(info);
}
return ret;
}
int32_t InputMethodAbility::HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag,
Trigger trigger, uint32_t sessionId, int32_t clientSessionId)
{
if (inputMethodPanel == nullptr) {
return ErrorCode::ERROR_BAD_PARAMETERS;
}
auto ret = inputMethodPanel->HidePanel();
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGD("failed, ret: %{public}d", ret);
return ret;
}
PanelStatusInfo info;
info.panelInfo.panelType = inputMethodPanel->GetPanelType();
info.panelInfo.panelFlag = flag;
info.visible = false;
info.trigger = trigger;
info.sessionId = sessionId;
info.clientSessionId = clientSessionId;
NotifyPanelStatusInfo(info);
if (trigger == Trigger::IMF && inputMethodPanel->GetPanelType() == PanelType::SOFT_KEYBOARD) {
AsyncIpcCallBack callback = [](int32_t code, const ResponseData &data) {};
FinishTextPreview(callback);
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::NotifyPanelStatus(bool isUseParameterFlag, PanelFlag panelFlag, bool isCheckFuncButton)
{
auto panel = GetSoftKeyboardPanel();
if (panel == nullptr) {
IMSA_HILOGE("panel is null");
return ErrorCode::ERROR_NULL_POINTER;
}
auto keyboardSize = panel->GetKeyboardSize();
PanelFlag curPanelFlag = isUseParameterFlag ? panelFlag : panel->GetPanelFlag();
SysPanelStatus sysPanelStatus = { inputType_, curPanelFlag, keyboardSize.width, keyboardSize.height };
sysPanelStatus.isPanelRaised = panel->IsKeyboardBottomElevated(curPanelFlag);
sysPanelStatus.needFuncButton = panel->IsFunctionButtonVisible(sysPanelStatus.isPanelRaised);
auto systemChannel = GetSystemCmdChannelProxy();
if (systemChannel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
SetSysPanelStatus(sysPanelStatus);
return systemChannel->NotifyPanelStatus(sysPanelStatus);
}
void InputMethodAbility::SetInputAttribute(const InputAttribute &inputAttribute)
{
std::lock_guard<std::mutex> lock(inputAttrLock_);
auto callingScreenId = inputAttribute_.callingScreenId;
if (inputAttribute.callingDisplayId != inputAttribute_.callingDisplayId) {
const auto display = Rosen::DisplayManager::GetInstance().GetDisplayById(inputAttribute.callingDisplayId);
if (display != nullptr) {
callingScreenId = display->GetScreenId();
} else {
IMSA_HILOGE("failed to get display by id %{public}" PRIu64 ".", inputAttribute.callingDisplayId);
callingScreenId = 0;
}
}
inputAttribute_ = inputAttribute;
inputAttribute_.callingScreenId = callingScreenId;
}
void InputMethodAbility::ClearInputAttribute()
{
std::lock_guard<std::mutex> lock(inputAttrLock_);
auto callingDisplayId = inputAttribute_.callingDisplayId;
auto callingScreenId = inputAttribute_.callingScreenId;
inputAttribute_ = {};
inputAttribute_.callingDisplayId = callingDisplayId;
inputAttribute_.callingScreenId = callingScreenId;
}
InputAttribute InputMethodAbility::GetInputAttribute()
{
std::lock_guard<std::mutex> lock(inputAttrLock_);
return inputAttribute_;
}
int32_t InputMethodAbility::HideKeyboard(Trigger trigger, uint32_t sessionId, int32_t clientSessionId)
{
isShowAfterCreate_.store(false);
InputMethodSyncTrace tracer("IMA_HideKeyboard");
if (imeListener_ == nullptr) {
IMSA_HILOGE("imeListener_ is nullptr!");
return ErrorCode::ERROR_IME;
}
IMSA_HILOGD("IMA, trigger: %{public}d.", static_cast<int32_t>(trigger));
if (panels_.Contains(SOFT_KEYBOARD)) {
auto panel = GetSoftKeyboardPanel();
if (panel == nullptr) {
IMSA_HILOGE("panel is nullptr!");
return ErrorCode::ERROR_IME;
}
auto flag = panel->GetPanelFlag();
imeListener_->OnKeyboardStatus(false);
if (flag == FLG_CANDIDATE_COLUMN && inputType_ != InputType::VOICEKB_INPUT) {
IMSA_HILOGI("panel flag is candidate, no need to hide.");
return ErrorCode::NO_ERROR;
}
return HidePanel(panel, flag, trigger, sessionId, clientSessionId);
}
IMSA_HILOGI("panel is not created.");
imeListener_->OnKeyboardStatus(false);
auto channel = GetInputDataChannelProxy();
if (channel != nullptr) {
channel->SendKeyboardStatus(static_cast<int32_t>(KeyboardStatus::HIDE));
}
auto controlChannel = GetInputControlChannel();
if (controlChannel != nullptr && trigger == Trigger::IME_APP) {
controlChannel->HideKeyboardSelf();
}
return ErrorCode::NO_ERROR;
}
std::shared_ptr<InputMethodPanel> InputMethodAbility::GetSoftKeyboardPanel()
{
auto result = panels_.Find(SOFT_KEYBOARD);
if (!result.first) {
return nullptr;
}
auto panel = result.second;
if (!BlockRetry(FIND_PANEL_RETRY_INTERVAL, MAX_RETRY_TIMES, [panel]() -> bool {
return panel != nullptr && panel->windowId_ != InputMethodPanel::INVALID_WINDOW_ID;
})) {
return nullptr;
}
return panel;
}
bool InputMethodAbility::IsCurrentIme()
{
IMSA_HILOGD("InputMethodAbility start.");
if (isCurrentIme_) {
return true;
}
std::lock_guard<std::mutex> lock(imeCheckMutex_);
if (isCurrentIme_) {
return true;
}
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("failed to get imsa proxy!");
return false;
}
bool ret = false;
proxy->IsCurrentIme(ret);
if (ret) {
isCurrentIme_ = true;
}
return ret;
}
bool InputMethodAbility::IsDefaultIme()
{
IMSA_HILOGD("InputMethodAbility start");
if (isDefaultIme_) {
return true;
}
std::lock_guard<std::mutex> lock(defaultImeCheckMutex_);
if (isDefaultIme_) {
return true;
}
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("failed to get imsa proxy!");
return false;
}
auto ret = proxy->IsDefaultIme();
if (ret == ErrorCode::NO_ERROR) {
isDefaultIme_ = true;
return true;
}
IMSA_HILOGE("call IsDefaultIme failed, ret: %{public}d!", ret);
return false;
}
bool InputMethodAbility::IsEnable(uint64_t displayId)
{
if (imeListener_ == nullptr) {
return false;
}
return imeListener_->IsEnable(displayId);
}
bool InputMethodAbility::IsCallbackRegistered(const std::string &type)
{
if (imeListener_ == nullptr) {
return false;
}
return imeListener_->IsCallbackRegistered(type);
}
bool InputMethodAbility::IsSystemApp()
{
IMSA_HILOGD("InputMethodAbility start");
if (isSystemApp_) {
return true;
}
std::lock_guard<std::mutex> lock(systemAppCheckMutex_);
if (isSystemApp_) {
return true;
}
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("failed to get imsa proxy!");
return false;
}
bool ret = false;
proxy->IsSystemApp(ret);
if (ret) {
isSystemApp_ = true;
}
return ret;
}
int32_t InputMethodAbility::ExitCurrentInputType()
{
IMSA_HILOGD("InputMethodAbility start.");
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethodEngine.exitCurrentInputType", 1);
#endif
ClearInputType();
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("failed to get imsa proxy!");
return false;
}
auto ret = proxy->ExitCurrentInputType();
if (ret == ErrorCode::NO_ERROR) {
NotifyPanelStatus(false);
}
return ret;
}
void InputMethodAbility::ClearInputType()
{
std::lock_guard<std::mutex> lock(inputTypeLock_);
if (inputType_ != InputType::SECURITY_INPUT) {
inputType_ = InputType::NONE;
}
}
int32_t InputMethodAbility::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
{
isShown = false;
auto result = panels_.Find(panelInfo.panelType);
if (!result.first) {
IMSA_HILOGI("panel type: %{public}d not found.", static_cast<int32_t>(panelInfo.panelType));
return ErrorCode::NO_ERROR;
}
auto panel = result.second;
if (panel->GetPanelType() == PanelType::SOFT_KEYBOARD && panel->GetPanelFlag() != panelInfo.panelFlag) {
IMSA_HILOGI("queried flag: %{public}d, current flag: %{public}d, panel not found.",
static_cast<int32_t>(panelInfo.panelFlag), static_cast<int32_t>(panel->GetPanelFlag()));
return ErrorCode::NO_ERROR;
}
isShown = panel->IsShowing();
IMSA_HILOGI("type: %{public}d, flag: %{public}d, result: %{public}d.", static_cast<int32_t>(panelInfo.panelType),
static_cast<int32_t>(panelInfo.panelFlag), isShown);
return ErrorCode::NO_ERROR;
}
void InputMethodAbility::OnClientInactive(const sptr<IRemoteObject> &channel)
{
IMSA_HILOGI("client inactive.");
if (imeListener_ != nullptr) {
imeListener_->OnInputFinish();
}
auto channelProxy = std::make_shared<InputDataChannelProxy>(channel);
if (channelProxy == nullptr) {
IMSA_HILOGE("failed to create channel proxy!");
return;
}
auto panel = GetSoftKeyboardPanel();
if (imeListener_ != nullptr && panel != nullptr && panel->GetPanelFlag() != PanelFlag::FLG_FIXED) {
imeListener_->OnKeyboardStatus(false);
}
panels_.ForEach([this, &channelProxy](const PanelType &panelType, const std::shared_ptr<InputMethodPanel> &panel) {
if (panel == nullptr) {
return false;
}
if (panelType == PanelType::SOFT_KEYBOARD && panel->GetPanelFlag() == PanelFlag::FLG_FIXED) {
return false;
}
auto ret = panel->HidePanel();
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed, ret: %{public}d", ret);
return false;
}
PanelStatusInfo info;
info.panelInfo.panelType = panel->GetPanelType();
info.panelInfo.panelFlag = panel->GetPanelFlag();
info.visible = false;
info.trigger = Trigger::IME_APP;
NotifyPanelStatusInfo(info, channelProxy);
if (panel->GetPanelType() == PanelType::SOFT_KEYBOARD) {
AsyncIpcCallBack callback = [](int32_t code, const ResponseData &data) {};
FinishTextPreview(callback);
}
return false;
});
ClearDataChannel(channel);
ClearAttachOptions();
ClearBindClientInfo();
}
void InputMethodAbility::NotifyKeyboardHeight(uint32_t panelHeight, PanelFlag panelFlag)
{
auto channel = GetInputDataChannelProxy();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return;
}
IMSA_HILOGD("notify panel height: %{public}u, flag: %{public}d.", panelHeight, static_cast<int32_t>(panelFlag));
if (panelFlag != PanelFlag::FLG_FIXED) {
channel->NotifyKeyboardHeight(0);
return;
}
channel->NotifyKeyboardHeight(panelHeight);
}
int32_t InputMethodAbility::SendPrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand,
bool validateDefaultIme)
{
if (validateDefaultIme && !IsDefaultIme()) {
IMSA_HILOGE("current is not default ime!");
return ErrorCode::ERROR_NOT_DEFAULT_IME;
}
if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
IMSA_HILOGE("privateCommand is limit 32KB, count limit 5!");
return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
}
if (TextConfig::IsSystemPrivateCommand(privateCommand)) {
auto systemChannel = GetSystemCmdChannelProxy();
if (systemChannel == nullptr) {
if (!IsSystemPanelSupported()) {
IMSA_HILOGW("not input method panel!");
return ErrorCode::NO_ERROR;
}
UpdatePrivateCommand(privateCommand);
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_SYSTEM_CMD_CHANNEL_ERROR;
}
Value commandValueMap(privateCommand);
return systemChannel->SendPrivateCommand(commandValueMap);
} else {
auto channel = GetInputDataChannelProxy();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
Value commandValueMap(privateCommand);
return channel->SendPrivateCommand(commandValueMap);
}
}
void InputMethodAbility::PushPrivateCommand()
{
if (privateCommandData_.size() == 0) {
return;
}
auto systemChannel = GetSystemCmdChannelProxy();
if (systemChannel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return;
}
std::lock_guard<std::mutex> lock(privateCommandLock_);
for (const auto &privateCommand : privateCommandData_) {
Value commandValueMap(privateCommand);
auto ret = systemChannel->SendPrivateCommand(commandValueMap);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("send privateCommand failed!");
}
}
privateCommandData_.clear();
}
void InputMethodAbility::UpdatePrivateCommand(
const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
std::lock_guard<std::mutex> lock(privateCommandLock_);
if (privateCommandData_.size() >= MAX_PRIVATE_COMMAND_QUEUE_SIZE) {
privateCommandData_.erase(privateCommandData_.begin());
}
privateCommandData_.push_back(privateCommand);
}
int32_t InputMethodAbility::ReceivePrivateCommand(
const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
if (imeListener_ == nullptr) {
IMSA_HILOGE("imeListener is nullptr!");
return ErrorCode::ERROR_IME;
}
imeListener_->ReceivePrivateCommand(privateCommand);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::SetPreviewText(
const std::string &text, const Range &range, const AsyncIpcCallBack &callback)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethodEngine.setPreviewText", 1);
#endif
InputMethodSyncTrace tracer("IMA_SetPreviewText");
auto dataChannel = GetInputDataChannelProxyWrap();
if (dataChannel == nullptr) {
IMSA_HILOGE("dataChannel is nullptr!");
return ErrorCode::ERROR_IMA_CHANNEL_NULLPTR;
}
RangeInner rangeInner = InputMethodTools::GetInstance().RangeToInner(range);
return dataChannel->SetPreviewText(text, rangeInner, callback);
}
int32_t InputMethodAbility::FinishTextPreview(const AsyncIpcCallBack &callback)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethodEngine.finishTextPreview", 1);
#endif
InputMethodSyncTrace tracer("IMA_FinishTextPreview");
auto dataChannel = GetInputDataChannelProxyWrap();
if (dataChannel == nullptr) {
IMSA_HILOGE("dataChannel is nullptr!");
return ErrorCode::ERROR_IMA_CHANNEL_NULLPTR;
}
return dataChannel->FinishTextPreview(callback);
}
int32_t InputMethodAbility::GetCallingWindowInfo(CallingWindowInfo &windowInfo)
{
IMSA_HILOGD("IMA start.");
auto channel = GetInputDataChannelProxy();
if (channel == nullptr) {
IMSA_HILOGE("channel is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
auto panel = GetSoftKeyboardPanel();
if (panel == nullptr) {
IMSA_HILOGE("panel not found!");
return ErrorCode::ERROR_PANEL_NOT_FOUND;
}
auto ret = panel->SetCallingWindow(GetInputAttribute().windowId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to set calling window, ret: %{public}d!", ret);
return ret;
}
ret = panel->GetCallingWindowInfo(windowInfo);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to get calling window, ret: %{public}d", ret);
}
return ret;
}
void InputMethodAbility::NotifyPanelStatusInfo(
PanelStatusInfo &info, std::shared_ptr<InputDataChannelProxy> &channelProxy)
{
info.inputType = GetInputType();
if (info.panelInfo.panelFlag == PanelFlag::FLG_CANDIDATE_COLUMN && info.inputType != InputType::VOICEKB_INPUT) {
return;
}
if (channelProxy != nullptr) {
PanelStatusInfoInner inner = InputMethodTools::GetInstance().PanelStatusInfoToInner(info);
channelProxy->NotifyPanelStatusInfo(inner);
}
auto controlChannel = GetInputControlChannel();
if (controlChannel != nullptr && info.panelInfo.panelType == PanelType::SOFT_KEYBOARD &&
info.trigger == Trigger::IME_APP && !info.visible && !isImeTerminating_.load()) {
controlChannel->HideKeyboardSelf();
}
}
int32_t InputMethodAbility::SendMessage(const ArrayBuffer &arrayBuffer)
{
int32_t securityMode = INVALID_SECURITY_MODE;
auto ret = GetSecurityMode(securityMode);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("Get security mode failed!");
return ret;
}
if (!ArrayBuffer::IsSizeValid(arrayBuffer)) {
IMSA_HILOGE("arrayBuffer size is invalid!");
return ErrorCode::ERROR_INVALID_ARRAY_BUFFER_SIZE;
}
if (securityMode != static_cast<int32_t>(SecurityMode::FULL)) {
IMSA_HILOGE("Security mode must be FULL!.");
return ErrorCode::ERROR_SECURITY_MODE_OFF;
}
auto dataChannel = GetInputDataChannelProxy();
if (dataChannel == nullptr) {
IMSA_HILOGE("datachannel is nullptr.");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return dataChannel->SendMessage(arrayBuffer);
}
int32_t InputMethodAbility::RecvMessage(const ArrayBuffer &arrayBuffer)
{
int32_t securityMode = -1;
auto ret = GetSecurityMode(securityMode);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("Get security mode failed!");
return ret;
}
if (securityMode != static_cast<int32_t>(SecurityMode::FULL)) {
IMSA_HILOGE("Security mode must be FULL!.");
return ErrorCode::ERROR_SECURITY_MODE_OFF;
}
auto msgHandlerCallback = GetMsgHandlerCallback();
if (msgHandlerCallback == nullptr) {
IMSA_HILOGW("Message handler was not regist!");
return ErrorCode::ERROR_MSG_HANDLER_NOT_REGIST;
}
return msgHandlerCallback->OnMessage(arrayBuffer);
}
int32_t InputMethodAbility::RegisterMsgHandler(const std::shared_ptr<MsgHandlerCallbackInterface> &msgHandler)
{
IMSA_HILOGI("isRegist: %{public}d", msgHandler != nullptr);
std::shared_ptr<MsgHandlerCallbackInterface> exMsgHandler = nullptr;
{
std::lock_guard<decltype(msgHandlerMutex_)> lock(msgHandlerMutex_);
exMsgHandler = msgHandler_;
msgHandler_ = msgHandler;
}
if (exMsgHandler != nullptr) {
IMSA_HILOGI("Trigger exMessageHandler OnTerminated.");
exMsgHandler->OnTerminated();
}
return ErrorCode::NO_ERROR;
}
std::shared_ptr<MsgHandlerCallbackInterface> InputMethodAbility::GetMsgHandlerCallback()
{
std::lock_guard<decltype(msgHandlerMutex_)> lock(msgHandlerMutex_);
return msgHandler_;
}
int32_t InputMethodAbility::StartInput(const InputClientInfo &clientInfo, bool isBindFromClient)
{
auto ret = StartInputInner(clientInfo, isBindFromClient);
if (ret == ErrorCode::NO_ERROR) {
return ret;
}
ReportImeStartInput(
static_cast<int32_t>(IInputMethodCoreIpcCode::COMMAND_START_INPUT), ret, clientInfo.isShowKeyboard);
return ret;
}
void InputMethodAbility::SetBindClientInfo(const InputClientInfo &clientInfo)
{
std::lock_guard<std::mutex> lock(bindClientInfoLock_);
bindClientInfo_ = { clientInfo.pid, clientInfo.type, clientInfo.name };
}
HiSysEventClientInfo InputMethodAbility::GetBindClientInfo()
{
std::lock_guard<std::mutex> lock(bindClientInfoLock_);
return bindClientInfo_;
}
void InputMethodAbility::ClearBindClientInfo()
{
std::lock_guard<std::mutex> lock(bindClientInfoLock_);
bindClientInfo_ = { };
}
void InputMethodAbility::ReportImeStartInput(
int32_t eventCode, int32_t errCode, bool isShowKeyboard, int64_t consumeTime)
{
IMSA_HILOGD("HiSysEvent report start:[%{public}d, %{public}d]!", eventCode, errCode);
auto clientInfo = GetBindClientInfo();
auto evenInfo = HiSysOriginalInfo::Builder()
.SetPeerName(clientInfo.name)
.SetPeerPid(clientInfo.pid)
.SetIsShowKeyboard(isShowKeyboard)
.SetEventCode(eventCode)
.SetErrCode(errCode)
.SetImeCbTime(consumeTime)
.Build();
ImaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::IME_START_INPUT, *evenInfo);
IMSA_HILOGD("HiSysEvent report end:[%{public}d, %{public}d]!", eventCode, errCode);
}
int32_t InputMethodAbility::OnCallingDisplayIdChanged(uint64_t editorDisplayId, uint64_t keyboardDisplayId)
{
auto oldKeyboardDisplayId = GetInputAttribute().callingDisplayId;
auto oldEditorDisplayId = GetInputAttribute().editorDisplayId;
IMSA_HILOGI("IMA oldEditorDisplayId/oldKeyboardDisplayId/editorDisplayId/keyboardDisplayId: %{public}" PRIu64
"/%{public}" PRIu64 "/%{public}" PRIu64 "/%{public}" PRIu64 ".",
oldEditorDisplayId, oldKeyboardDisplayId, editorDisplayId, keyboardDisplayId);
if (oldKeyboardDisplayId == keyboardDisplayId && editorDisplayId == oldEditorDisplayId) {
return ErrorCode::NO_ERROR;
}
{
std::lock_guard<std::mutex> lock(inputAttrLock_);
inputAttribute_.callingDisplayId = keyboardDisplayId;
inputAttribute_.editorDisplayId = editorDisplayId;
const auto display = Rosen::DisplayManager::GetInstance().GetDisplayById(keyboardDisplayId);
if (display != nullptr) {
inputAttribute_.callingScreenId = display->GetScreenId();
} else {
IMSA_HILOGE("failed to get display by id %{public}" PRIu64 ".", keyboardDisplayId);
inputAttribute_.callingScreenId = 0;
}
}
NotifyInputStartToClients(InputStartScene::DISPLAY_CHANGED);
if (oldKeyboardDisplayId == keyboardDisplayId) {
return ErrorCode::NO_ERROR;
}
auto panel = GetSoftKeyboardPanel();
if (panel != nullptr && panel->GetPanelFlag() == PanelFlag::FLG_FIXED) {
HidePanel(panel, PanelFlag::FLG_FIXED, Trigger::IMF, 0);
}
ConfigurationUpdate(keyboardDisplayId);
if (imeListener_ == nullptr) {
IMSA_HILOGD("imeListener_ is nullptr!");
return ErrorCode::NO_ERROR;
}
imeListener_->OnCallingDisplayIdChanged(keyboardDisplayId);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::OnSendPrivateData(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
auto ret = ReceivePrivateCommand(privateCommand);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("OnSendPrivateData failed!");
}
IMSA_HILOGD("InputMethodAbility ReceivePrivateCommand success.");
return ret;
}
bool InputMethodAbility::HandleUnconsumedKey(const std::shared_ptr<MMI::KeyEvent> &keyEvent)
{
if (keyEvent == nullptr) {
IMSA_HILOGE("keyEvent nullptr");
return false;
}
auto channel = GetInputDataChannelProxyWrap();
if (channel == nullptr) {
IMSA_HILOGD("channel is nullptr!");
return false;
}
if (!GetInputAttribute().needAutoInputNumkey) {
IMSA_HILOGD("no need");
return false;
}
if (keyEvent->GetKeyAction() != MMI::KeyEvent::KEY_ACTION_DOWN) {
IMSA_HILOGD("not down key");
return false;
}
if (keyEvent->GetPressedKeys().size() > 1) {
IMSA_HILOGD("only handle single key");
return false;
}
int32_t keyCode = keyEvent->GetKeyCode();
std::string inputNumber;
AsyncIpcCallBack callback = [](int32_t code, const ResponseData &data) {};
if (MMI::KeyEvent::KEYCODE_0 <= keyCode && keyCode <= MMI::KeyEvent::KEYCODE_9) {
IMSA_HILOGI("auto input a number");
channel->InsertText(std::to_string(keyCode - MMI::KeyEvent::KEYCODE_0), callback);
return true;
}
if (!keyEvent->GetFunctionKey(MMI::KeyEvent::NUM_LOCK_FUNCTION_KEY)) {
IMSA_HILOGD("num lock off");
return false;
}
if (MMI::KeyEvent::KEYCODE_NUMPAD_0 <= keyCode && keyCode <= MMI::KeyEvent::KEYCODE_NUMPAD_9) {
IMSA_HILOGI("auto input a number");
channel->InsertText(std::to_string(keyCode - MMI::KeyEvent::KEYCODE_NUMPAD_0), callback);
return true;
}
return false;
}
int32_t InputMethodAbility::OnResponse(uint64_t msgId, int32_t code, const ResponseData &data)
{
auto channel = GetInputDataChannelProxyWrap();
if (channel != nullptr) {
ResponseInfo rspInfo = { code, data };
channel->HandleResponse(msgId, rspInfo);
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::IsCapacitySupport(int32_t capacity, bool &isSupport)
{
auto proxy = GetImsaProxy();
if (proxy == nullptr) {
IMSA_HILOGE("failed to get imsa proxy!");
return ErrorCode::ERROR_NULL_POINTER;
}
return proxy->IsCapacitySupport(capacity, isSupport);
}
bool InputMethodAbility::IsSystemPanelSupported()
{
if (isSysPanelSupport_ != 0) {
return isSysPanelSupport_ == 1;
}
std::lock_guard<std::mutex> lock(isSysPanelSupportMutex_);
bool isSupportTemp = false;
int32_t ret = IsCapacitySupport(static_cast<int32_t>(CapacityType::SYSTEM_PANEL), isSupportTemp);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("IsCapacitySupport failed, ret:%{public}d", ret);
return false;
}
isSysPanelSupport_ = isSupportTemp ? 1 : -1;
IMSA_HILOGI("isSupportTemp:%{public}d", isSupportTemp);
return isSupportTemp;
}
int32_t InputMethodAbility::OnNotifyPreemption()
{
IMSA_HILOGD("start.");
StopInput(dataChannelObject_, 0);
isBound_.store(false);
auto imeListener = GetImeListener();
if (imeListener == nullptr) {
return ErrorCode::ERROR_IME_NOT_STARTED;
}
IMSA_HILOGD("notifyPreemption begin.");
imeListener->NotifyPreemption();
return ErrorCode::NO_ERROR;
}
int32_t InputMethodAbility::HandleKeyEventResult(
uint64_t cbId, bool consumeResult, const sptr<IRemoteObject> &channelObject)
{
IMSA_HILOGD("run in:%{public}" PRIu64 "/%{public}d.", cbId, consumeResult);
if (channelObject == nullptr) {
IMSA_HILOGE("channelObject is nullptr:%{public}" PRIu64 ".", cbId);
return ErrorCode::ERROR_IMA_CHANNEL_NULLPTR;
}
auto channel = std::make_shared<InputDataChannelProxy>(channelObject);
return channel->HandleKeyEventResult(cbId, consumeResult);
}
void InputMethodAbility::RemoveDeathRecipient()
{
std::lock_guard<std::mutex> lock(abilityLock_);
if (abilityManager_ == nullptr || deathRecipient_ == nullptr) {
IMSA_HILOGE("abilityManager_ or deathRecipient_ is nullptr");
return;
}
auto remoteObject = abilityManager_->AsObject();
if (remoteObject == nullptr) {
IMSA_HILOGE("remoteObject is nullptr");
return;
}
if (!remoteObject->RemoveDeathRecipient(deathRecipient_)) {
IMSA_HILOGE("RemoveDeathRecipient failed");
}
}
void InputMethodAbility::SetSysPanelStatus(const SysPanelStatus &sysPanelStatus)
{
std::lock_guard<std::mutex> lock(sysPanelStatusLock_);
sysPanelStatus_ = sysPanelStatus;
}
SysPanelStatus InputMethodAbility::GetSysPanelStatus()
{
std::lock_guard<std::mutex> lock(sysPanelStatusLock_);
return sysPanelStatus_;
}
int32_t InputMethodAbility::GetSoftKeyboardInfo(BoundImeInfo &imeInfo)
{
auto panel = GetSoftKeyboardPanel();
if (panel == nullptr) {
imeInfo.status = InputWindowStatus::HIDE;
return ErrorCode::NO_ERROR;
}
imeInfo.panelFlag = panel->GetPanelFlag();
imeInfo.status = panel->IsShowing() ? InputWindowStatus::SHOW : InputWindowStatus::HIDE;
imeInfo.displayId = ImfCommonConst::DEFAULT_DISPLAY_ID;
if (imeInfo.status == InputWindowStatus::HIDE) {
IMSA_HILOGD("hide status: %{public}s.", imeInfo.ToString().c_str());
return ErrorCode::NO_ERROR;
}
auto ret = panel->GetDisplayId(imeInfo.displayId);
if (ret != ErrorCode::NO_ERROR) {
imeInfo.displayId = GetInputAttribute().callingDisplayId;
}
IMSA_HILOGD("show status: %{public}s.", imeInfo.ToString().c_str());
return ErrorCode::NO_ERROR;
}
}
}