* 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_controller.h"
#include "securec.h"
#include <algorithm>
#include <cinttypes>
#include "block_data.h"
#include "global.h"
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
#include "histogram_plugin_macros.h"
#endif
#include "imc_hisysevent_reporter.h"
#include "ime_event_monitor_manager_impl.h"
#include "input_client_service_impl.h"
#include "input_data_channel_service_impl.h"
#include "input_method_agent_proxy.h"
#include "input_method_property.h"
#include "input_method_status.h"
#include "input_method_system_ability_proxy.h"
#include "input_method_tools.h"
#include "inputmethod_sysevent.h"
#include "inputmethod_trace.h"
#include "iservice_registry.h"
#include "keyevent_consumer_service_impl.h"
#include "notify_service_impl.h"
#include "on_demand_start_stop_sa.h"
#include "on_input_stop_notify_proxy.h"
#include "string_ex.h"
#include "string_utils.h"
#include "sys/prctl.h"
#include "system_ability_definition.h"
#include "system_cmd_channel_stub.h"
#include "system_ability_status_change_stub.h"
namespace OHOS {
namespace MiscServices {
using namespace MessageID;
using namespace std::chrono;
sptr<InputMethodController> InputMethodController::instance_;
std::shared_ptr<AppExecFwk::EventHandler> InputMethodController::handler_ { nullptr };
std::mutex InputMethodController::instanceLock_;
std::mutex InputMethodController::logLock_;
int InputMethodController::keyEventCountInPeriod_ = 0;
std::chrono::system_clock::time_point InputMethodController::startLogTime_ = system_clock::now();
std::mutex InputMethodController::printTextChangeMutex_;
int32_t InputMethodController::textChangeCountInPeriod_ = 0;
std::chrono::steady_clock::time_point InputMethodController::textChangeStartLogTime_ = steady_clock::now();
constexpr uint32_t MAX_ATTACH_TIMEOUT = 2500;
BlockQueue<InputMethodController::CtrlEventInfo> InputMethodController::ctrlEventQueue_ { MAX_ATTACH_TIMEOUT };
constexpr int32_t LOOP_COUNT = 5;
constexpr int32_t LOG_MAX_TIME = 20;
constexpr int32_t LOG_INSERT_MAX_TIME = 20;
constexpr int32_t LOG_INSERT_MIN_TIME = 5;
constexpr int32_t ATTACH_RETRY_INTERVAL = 50;
constexpr int32_t ATTACH_MAX_RETRY_TIMES = 30;
constexpr int64_t DELAY_TIME = 100;
constexpr int32_t ACE_DEAL_TIME_OUT = 200;
constexpr int32_t MAX_PLACEHOLDER_SIZE = 255;
constexpr int32_t MAX_ABILITY_NAME_SIZE = 127;
static constexpr int32_t MAX_TIMEOUT = 2500;
constexpr int64_t DISPATCH_KEYBOARD_TIME_OUT = 5;
constexpr size_t MAX_AGENT_NUMBER = 2;
const std::string IME_MIRROR_NAME = "proxyIme_IME_MIRROR";
class SaMgrListener : public SystemAbilityStatusChangeStub {
public:
explicit SaMgrListener(std::function<void()> handler) : func_(handler) {};
~SaMgrListener() override = default;
void OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId) override;
void OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId) override {}
private:
std::function<void()> func_;
};
std::mutex listenerMapMutex_;
sptr<ISystemAbilityStatusChange> saMgrListener_;
InputMethodController::InputMethodController()
{
IMSA_HILOGD("IMC structure.");
}
InputMethodController::~InputMethodController() { }
sptr<InputMethodController> InputMethodController::GetInstance()
{
static std::once_flag onceFlag;
std::call_once(onceFlag, [&]() {
if (instance_ == nullptr) {
IMSA_HILOGD("instance_ is nullptr!");
instance_ = new (std::nothrow) InputMethodController();
if (instance_ == nullptr) {
IMSA_HILOGE("failed to create InputMethodController!");
return;
}
int32_t ret = instance_->Initialize();
if (ret != ErrorCode::NO_ERROR) {
InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, "", "IMC initialize failed!");
}
}
});
return instance_;
}
int32_t InputMethodController::RestoreListenEventFlag()
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
InputClientInfoInner infoInner = InputMethodTools::GetInstance().InputClientInfoToInner(clientInfo_);
return proxy->UpdateListenEventFlag(infoInner, 0);
}
int32_t InputMethodController::UpdateListenEventFlag(uint32_t finalEventFlag, uint32_t eventFlag, bool isOn)
{
auto oldEventFlag = clientInfo_.eventFlag;
clientInfo_.eventFlag = finalEventFlag;
if (!isOn) {
auto proxy = TryGetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::NO_ERROR;
}
}
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
if (isOn) {
clientInfo_.eventFlag = oldEventFlag;
}
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
InputClientInfoInner infoInner = InputMethodTools::GetInstance().InputClientInfoToInner(clientInfo_);
auto ret = proxy->UpdateListenEventFlag(infoInner, eventFlag);
if (ret != ErrorCode::NO_ERROR && isOn) {
clientInfo_.eventFlag = oldEventFlag;
}
return ret;
}
void InputMethodController::SetControllerListener(std::shared_ptr<ControllerListener> controllerListener)
{
IMSA_HILOGD("InputMethodController run in");
controllerListener_ = std::move(controllerListener);
}
int32_t InputMethodController::Initialize()
{
sptr<IInputClient> client = new (std::nothrow) InputClientServiceImpl();
if (client == nullptr) {
IMSA_HILOGE("failed to create client!");
return ErrorCode::ERROR_NULL_POINTER;
}
sptr<IInputDataChannel> channel = new (std::nothrow) InputDataChannelServiceImpl();
if (channel == nullptr) {
IMSA_HILOGE("failed to new channel!");
return ErrorCode::ERROR_NULL_POINTER;
}
SubscribeSaStart([this]() {
this->RestoreListenInfoInSaDied();
this->immersiveCache_.ResetQueried();
}, INPUT_METHOD_SYSTEM_ABILITY_ID);
InputAttribute attribute;
attribute.inputPattern = InputAttribute::PATTERN_TEXT;
clientInfo_.attribute = attribute;
clientInfo_.client = client;
clientInfo_.channel = channel->AsObject();
handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
return ErrorCode::NO_ERROR;
}
sptr<IInputMethodSystemAbility> InputMethodController::TryGetSystemAbilityProxy()
{
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
return GetSystemAbilityProxy(false);
#else
return GetSystemAbilityProxy(true);
#endif
}
sptr<IInputMethodSystemAbility> InputMethodController::GetSystemAbilityProxy(bool ifRetry)
{
std::lock_guard<std::mutex> lock(abilityLock_);
if (abilityManager_ != nullptr) {
return abilityManager_;
}
IMSA_HILOGD("get input method service proxy.");
auto systemAbility = OnDemandStartStopSa::GetInputMethodSystemAbility(ifRetry);
if (systemAbility == nullptr) {
IMSA_HILOGE("systemAbility is nullptr!");
return nullptr;
}
if (deathRecipient_ == nullptr) {
deathRecipient_ = new (std::nothrow) InputDeathRecipient();
if (deathRecipient_ == nullptr) {
IMSA_HILOGE("create death recipient failed!");
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_;
}
void InputMethodController::RemoveDeathRecipient()
{
std::lock_guard<std::mutex> lock(abilityLock_);
if (abilityManager_ != nullptr && abilityManager_->AsObject() != nullptr && deathRecipient_ != nullptr) {
abilityManager_->AsObject()->RemoveDeathRecipient(deathRecipient_);
}
deathRecipient_ = nullptr;
abilityManager_ = nullptr;
}
void InputMethodController::DeactivateClient()
{
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.state = ClientState::INACTIVE;
}
SendKeyboardStatus(KeyboardStatus::NONE);
}
void InputMethodController::CalibrateImmersiveParam(InputAttribute &inputAttribute, bool shouldOverrideImmersiveMode)
{
if (shouldOverrideImmersiveMode) {
IMSA_HILOGI("immersiveMode overridden to 0, original: %{public}d", inputAttribute.immersiveMode);
inputAttribute.immersiveMode = 0;
}
if (inputAttribute.immersiveMode == 0) {
if (inputAttribute.gradientMode != 0 || inputAttribute.fluidLightMode != 0) {
IMSA_HILOGW("immersiveMode is NONE, but gradientMode=%{public}d, fluidLightMode=%{public}d",
inputAttribute.gradientMode, inputAttribute.fluidLightMode);
inputAttribute.gradientMode = 0;
inputAttribute.fluidLightMode = 0;
}
return;
}
if (inputAttribute.gradientMode == 0 && inputAttribute.fluidLightMode != 0) {
IMSA_HILOGW("gradientMode is NONE, but fluidLightMode=%{public}d", inputAttribute.fluidLightMode);
inputAttribute.fluidLightMode = 0;
return;
}
}
void InputMethodController::CalibrateInputPatternParam(InputAttribute &inputAttribute)
{
if (inputAttribute.inputPattern != InputAttribute::PATTERN_ONE_TIME_CODE_NUMBER) {
IMSA_HILOGD("no calibration required, inputPattern = %{public}d", inputAttribute.inputPattern);
return;
}
inputAttribute.inputPattern = static_cast<int32_t>(TextInputType::NUMBER);
inputAttribute.isOneTimeCodeNumberFlag = true;
IMSA_HILOGW("isOneTimeCodeNumberFlag = %{public}d", inputAttribute.isOneTimeCodeNumberFlag);
}
bool InputMethodController::ShouldOverrideImmersiveMode(const TextConfig &textConfig)
{
if (textConfig.inputAttribute.immersiveMode == 0) {
return false;
}
if (IsSupportPcMode()) {
return IsPcMode() ? IsDisablePcModeImmersiveMode() : IsDisableImmersiveMode();
}
return IsDisableImmersiveMode();
}
bool InputMethodController::IsDisableImmersiveMode()
{
if (immersiveCache_.isDisableImmersiveModeQueried.load()) {
return immersiveCache_.isDisableImmersiveModeCached.load();
}
auto proxy = TryGetSystemAbilityProxy();
if (proxy == nullptr) {
return false;
}
bool isDisable = false;
auto ret = proxy->IsCapacitySupport(static_cast<int32_t>(CapacityType::DISABLE_IMMERSIVE_MODE), isDisable);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGD("IsCapacitySupport failed, ret: %{public}d", ret);
return false;
}
IMSA_HILOGD("isDisableImmersiveMode: %{public}d", isDisable);
immersiveCache_.isDisableImmersiveModeCached.store(isDisable);
immersiveCache_.isDisableImmersiveModeQueried.store(true);
return isDisable;
}
bool InputMethodController::IsSupportPcMode()
{
if (immersiveCache_.isSupportPcModeQueried.load()) {
return immersiveCache_.isSupportPcModeCached.load();
}
auto proxy = TryGetSystemAbilityProxy();
if (proxy == nullptr) {
return false;
}
bool isSupport = false;
auto ret = proxy->IsCapacitySupport(static_cast<int32_t>(CapacityType::SUPPORT_PC_MODE), isSupport);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGD("IsCapacitySupport SUPPORT_PC_MODE failed, ret: %{public}d", ret);
return false;
}
IMSA_HILOGD("isSupportPcMode: %{public}d", isSupport);
immersiveCache_.isSupportPcModeCached.store(isSupport);
immersiveCache_.isSupportPcModeQueried.store(true);
return isSupport;
}
bool InputMethodController::IsDisablePcModeImmersiveMode()
{
if (immersiveCache_.isDisablePcModeImmersiveModeQueried.load()) {
return immersiveCache_.isDisablePcModeImmersiveModeCached.load();
}
auto proxy = TryGetSystemAbilityProxy();
if (proxy == nullptr) {
return false;
}
bool isDisable = false;
auto ret = proxy->IsCapacitySupport(static_cast<int32_t>(CapacityType::DISABLE_PC_MODE_IMMERSIVE_MODE), isDisable);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGD("IsCapacitySupport DISABLE_PC_MODE_IMMERSIVE_MODE failed, ret: %{public}d", ret);
return false;
}
IMSA_HILOGD("isDisablePcModeImmersiveMode: %{public}d", isDisable);
immersiveCache_.isDisablePcModeImmersiveModeCached.store(isDisable);
immersiveCache_.isDisablePcModeImmersiveModeQueried.store(true);
return isDisable;
}
bool InputMethodController::IsPcMode()
{
auto proxy = TryGetSystemAbilityProxy();
if (proxy == nullptr) {
return false;
}
bool isPcMode = false;
auto ret = proxy->IsCapacitySupport(static_cast<int32_t>(CapacityType::IS_PC_MODE), isPcMode);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGD("IsCapacitySupport IS_PC_MODE failed, ret: %{public}d", ret);
return false;
}
IMSA_HILOGD("isPcMode: %{public}d", isPcMode);
return isPcMode;
}
void InputMethodController::SaveTextConfig(const TextConfig &textConfig)
{
IMSA_HILOGD("textConfig: %{public}s.", textConfig.ToString().c_str());
CursorInfo cursorInfo = textConfig.cursorInfo;
uint32_t windowId = textConfig.windowId;
GetWindowScaleCoordinate(windowId, cursorInfo);
{
std::lock_guard<std::mutex> lock(textConfigLock_);
textConfig_ = textConfig;
bool shouldOverride = ShouldOverrideImmersiveMode(textConfig);
CalibrateImmersiveParam(textConfig_.inputAttribute, shouldOverride);
CalibrateInputPatternParam(textConfig_.inputAttribute);
textConfig_.cursorInfo = cursorInfo;
StringUtils::TruncateUtf16String(textConfig_.inputAttribute.placeholder, MAX_PLACEHOLDER_SIZE);
StringUtils::TruncateUtf16String(textConfig_.inputAttribute.abilityName, MAX_ABILITY_NAME_SIZE);
}
if (textConfig.range.start != INVALID_VALUE) {
std::lock_guard<std::mutex> lock(editorContentLock_);
selectOldBegin_ = selectNewBegin_;
selectOldEnd_ = selectNewEnd_;
selectNewBegin_ = textConfig.range.start;
selectNewEnd_ = textConfig.range.end;
}
}
int32_t InputMethodController::Attach(sptr<OnTextChangedListener> listener, ClientType type)
{
return Attach(listener, true, type);
}
int32_t InputMethodController::Attach(sptr<OnTextChangedListener> listener, bool isShowKeyboard, ClientType type)
{
InputAttribute attribute;
attribute.inputPattern = InputAttribute::PATTERN_TEXT;
return Attach(listener, isShowKeyboard, attribute, type);
}
int32_t InputMethodController::Attach(
sptr<OnTextChangedListener> listener, bool isShowKeyboard, const InputAttribute &attribute, ClientType type)
{
InputMethodSyncTrace tracer("InputMethodController Attach trace.");
TextConfig textConfig;
textConfig.inputAttribute = attribute;
return Attach(listener, isShowKeyboard, textConfig, type);
}
InputMethodController::QueueGuard::QueueGuard(const std::string &name) : needPop_(true)
{
CtrlEventInfo info = { std::chrono::steady_clock::now(), name };
if (!ctrlEventQueue_.Push(info)) {
needPop_ = false;
IMSA_HILOGE("push %{public}s failed, queue size:%{public}zu", name.c_str(), ctrlEventQueue_.Size());
return;
}
if (!ctrlEventQueue_.Wait(info)) {
IMSA_HILOGE("%{public}s wait timeout, queue size:%{public}zu", name.c_str(), ctrlEventQueue_.Size());
}
}
InputMethodController::QueueGuard::~QueueGuard()
{
if (!needPop_) {
return;
}
ctrlEventQueue_.Pop();
}
int32_t InputMethodController::GetClientType(ClientType &type)
{
if (!IsBound()) {
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
type = clientInfo_.type;
}
IMSA_HILOGD("client type: %{public}u", static_cast<uint32_t>(type));
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::Attach(
sptr<OnTextChangedListener> listener, bool isShowKeyboard, const TextConfig &textConfig, ClientType type)
{
AttachOptions attachOptions;
attachOptions.isShowKeyboard = isShowKeyboard;
attachOptions.requestKeyboardReason = RequestKeyboardReason::NONE;
return Attach(listener, attachOptions, textConfig, type);
}
int32_t InputMethodController::IsValidTextConfig(const TextConfig &textConfig)
{
if (textConfig.inputAttribute.immersiveMode < static_cast<int32_t>(ImmersiveMode::NONE_IMMERSIVE) ||
textConfig.inputAttribute.immersiveMode >= static_cast<int32_t>(ImmersiveMode::END)) {
IMSA_HILOGE("invalid immersiveMode: %{public}d", textConfig.inputAttribute.immersiveMode);
return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
}
if (textConfig.inputAttribute.gradientMode < static_cast<int32_t>(GradientMode::NONE) ||
textConfig.inputAttribute.gradientMode >= static_cast<int32_t>(GradientMode::END)) {
IMSA_HILOGW("invalid gradientMode: %{public}d", textConfig.inputAttribute.gradientMode);
}
if (textConfig.inputAttribute.fluidLightMode < static_cast<int32_t>(FluidLightMode::NONE) ||
textConfig.inputAttribute.fluidLightMode >= static_cast<int32_t>(FluidLightMode::END)) {
IMSA_HILOGW("invalid fluidLightMode: %{public}d", textConfig.inputAttribute.fluidLightMode);
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::Attach(sptr<OnTextChangedListener> listener, const AttachOptions &attachOptions,
const TextConfig &textConfig, ClientType type)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.attach", 1);
HISTOGRAM_ENUMERATION("imekit.inputMethod.attach.request_keyboard_reason",
static_cast<uint32_t>(attachOptions.requestKeyboardReason),
static_cast<uint32_t>(RequestKeyboardReason::OTHER));
#endif
auto task = [listener, attachOptions, textConfig, type, this](int32_t &ret) {
ret = AttachExec(listener, attachOptions, textConfig, type);
return ret != ErrorCode::ERROR_TRY_IME_START_FAILED;
};
int32_t ret = ErrorCode::NO_ERROR;
if (BlockRetry(ATTACH_RETRY_INTERVAL, ATTACH_MAX_RETRY_TIMES, task, ret)) {
return ret;
}
return ret;
}
int32_t InputMethodController::AttachExec(sptr<OnTextChangedListener> listener, const AttachOptions &attachOptions,
const TextConfig &textConfig, ClientType type)
{
QueueGuard guard(__func__);
IMSA_HILOGI("isShowKeyboard %{public}d.", attachOptions.isShowKeyboard);
InputMethodSyncTrace tracer("InputMethodController Attach with textConfig trace.");
if (IsValidTextConfig(textConfig) != ErrorCode::NO_ERROR) {
IMSA_HILOGE("invalid textConfig.");
return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
}
auto lastListener = GetTextListener();
clientInfo_.isNotifyInputStart = lastListener != listener;
if (clientInfo_.isNotifyInputStart) {
sessionId_++;
}
IMSA_HILOGI("sessionId_ %{public}u", sessionId_.load());
if (clientInfo_.isNotifyInputStart && lastListener != nullptr) {
lastListener->OnDetachV2();
}
ClearEditorCache(clientInfo_.isNotifyInputStart, lastListener);
SetTextListener(listener);
SaveTextConfig(textConfig);
GetTextConfig(clientInfo_.config);
std::vector<sptr<IRemoteObject>> agents;
std::vector<BindImeInfo> imeInfos;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.isShowKeyboard = attachOptions.isShowKeyboard;
clientInfo_.type = type;
clientInfo_.config.requestKeyboardReason = attachOptions.requestKeyboardReason;
}
int32_t ret = StartInput(clientInfo_, agents, imeInfos);
if (ret != ErrorCode::NO_ERROR) {
auto evenInfo = HiSysOriginalInfo::Builder()
.SetInputPattern(textConfig.inputAttribute.inputPattern)
.SetIsShowKeyboard(attachOptions.isShowKeyboard)
.SetClientType(type).SetErrCode(ret).Build();
ImcHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_ATTACH, *evenInfo);
SetTextListener(nullptr);
NotifyAttachFailure(ret);
IMSA_HILOGI("bind imf failed: %{public}d.", ret);
return ret;
}
clientInfo_.state = ClientState::ACTIVE;
SetInputReady(agents, imeInfos);
if (attachOptions.isShowKeyboard) {
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_ATTACH);
}
IMSA_HILOGI("bind imf successfully.");
return ErrorCode::NO_ERROR;
}
bool InputMethodController::IsKeyboardCallingProcess(int32_t pid, uint32_t windowId)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return false;
}
bool isKeyboardCallingProcess = false;
auto ret = proxy->IsKeyboardCallingProcess(pid, windowId, isKeyboardCallingProcess);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("IsKeyboardCallingProcess failed: %{public}d.", ret);
return false;
}
return isKeyboardCallingProcess;
}
int32_t InputMethodController::ShowTextInputInner(const AttachOptions &attachOptions, ClientType type)
{
InputMethodSyncTrace tracer("IMC_ShowTextInput");
if (!IsBound()) {
IMSA_HILOGE("not bound!");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
IMSA_HILOGI("start.");
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.isShowKeyboard = true;
}
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_ENEDITABLE);
int32_t ret = ShowInput(clientInfo_.client, type, static_cast<int32_t>(attachOptions.requestKeyboardReason));
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to start input: %{public}d", ret);
return ret;
}
isEditable_.store(true);
IMSA_HILOGI("enter editable state.");
return ret;
}
int32_t InputMethodController::HideTextInput()
{
InputMethodSyncTrace tracer("IMC_HideTextInput");
if (!IsBound()) {
IMSA_HILOGE("not bound!");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
IMSA_HILOGI("start.");
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.hideTextInput", 1);
#endif
isEditable_.store(false);
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNEDITABLE);
return HideInput(clientInfo_.client);
}
int32_t InputMethodController::HideCurrentInput()
{
InputMethodSyncTrace tracer("IMC_HideCurrentInput");
IMSA_HILOGD("InputMethodController::HideCurrentInput");
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.isShowKeyboard = false;
}
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL);
uint32_t windowId = ImfCommonConst::INVALID_WINDOW_ID;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
windowId = clientInfo_.config.windowId;
}
return proxy->HideCurrentInputDeprecated(windowId);
}
int32_t InputMethodController::ShowCurrentInput()
{
InputMethodSyncTrace tracer("IMC_ShowCurrentInput");
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGI("start.");
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.isShowKeyboard = true;
}
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL);
uint32_t windowId = ImfCommonConst::INVALID_WINDOW_ID;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
windowId = clientInfo_.config.windowId;
}
return proxy->ShowCurrentInputDeprecated(windowId);
}
int32_t InputMethodController::Close()
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.detach", 1);
#endif
int32_t defaultSessionId = -1;
return Close(defaultSessionId);
}
int32_t InputMethodController::Close(int32_t clientSessionId)
{
{
QueueGuard guard(__func__);
}
if (IsBound()) {
IMSA_HILOGI("start, clientSessionId: %{public}d.", clientSessionId);
}
auto listener = GetTextListener();
if (listener != nullptr) {
listener->OnDetachV2();
}
OperateIMEInfoCode infoCode = OperateIMEInfoCode::IME_UNBIND;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
if (clientInfo_.isShowKeyboard) {
infoCode = OperateIMEInfoCode::IME_HIDE_UNBIND;
}
}
InputMethodSyncTrace tracer("InputMethodController Close trace.");
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(infoCode);
return ReleaseInput(clientInfo_.client, clientSessionId);
}
void InputMethodController::Reset()
{
Close();
RemoveDeathRecipient();
}
int32_t InputMethodController::RequestHideInput(uint32_t callingWndId, bool isFocusTriggered, uint64_t displayId,
int32_t userId)
{
IMSA_HILOGD("callingWndId/displayId/isFocusTriggered:%{public}u/%{public}" PRIu64 "/%{public}d.", callingWndId,
displayId, isFocusTriggered);
auto proxy = TryGetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGD("InputMethodController start.");
return proxy->RequestHideInput(callingWndId, displayId, isFocusTriggered, userId);
}
int32_t InputMethodController::DisplayOptionalInputMethod()
{
IMSA_HILOGD("InputMethodController::DisplayOptionalInputMethod start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
return proxy->DisplayOptionalInputMethod();
}
bool InputMethodController::WasAttached()
{
return isBound_.load();
}
int32_t InputMethodController::GetInputStartInfo(InputStartInfo &inputStartInfo)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return false;
}
return proxy->GetInputStartInfo(inputStartInfo);
}
std::shared_ptr<AppExecFwk::EventHandler> InputMethodController::GetMainHandler()
{
return handler_;
}
int32_t InputMethodController::ListInputMethodCommon(InputMethodStatus status, std::vector<Property> &props,
int32_t userId)
{
IMSA_HILOGD("InputMethodController::ListInputMethodCommon start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
return proxy->ListInputMethod(status, props, userId);
}
int32_t InputMethodController::ListInputMethod(std::vector<Property> &props, int32_t userId)
{
IMSA_HILOGD("InputMethodController::listInputMethod start.");
return ListInputMethodCommon(ALL, props, userId);
}
int32_t InputMethodController::ListInputMethod(bool enable, std::vector<Property> &props, int32_t userId)
{
IMSA_HILOGI("enable: %{public}s.", enable ? "ENABLE" : "DISABLE");
return ListInputMethodCommon(enable ? ENABLE : DISABLE, props, userId);
}
int32_t InputMethodController::GetDefaultInputMethod(std::shared_ptr<Property> &property, int32_t userId)
{
InputMethodSyncTrace tracer("IMC_GetDefaultInputMethod");
IMSA_HILOGD("InputMethodController::GetDefaultInputMethod start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
proxy = nullptr;
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
Property prop;
auto ret = proxy->GetDefaultInputMethod(prop, false, userId);
if (ret != ErrorCode::NO_ERROR) {
proxy = nullptr;
return ret;
}
property = std::make_shared<Property>(prop);
return ret;
}
int32_t InputMethodController::GetInputMethodConfig(OHOS::AppExecFwk::ElementName &inputMethodConfig, int32_t userId)
{
InputMethodSyncTrace tracer("IMC_GetInputMethodConfig");
IMSA_HILOGD("InputMethodController::inputMethodConfig start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
return proxy->GetInputMethodConfig(inputMethodConfig, userId);
}
std::shared_ptr<Property> InputMethodController::GetCurrentInputMethod(int32_t userId)
{
InputMethodSyncTrace tracer("IMC_GetCurrentInputMethod");
IMSA_HILOGD("InputMethodController::GetCurrentInputMethod start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return nullptr;
}
Property propertyData;
proxy->GetCurrentInputMethod(userId, propertyData);
auto property = std::make_shared<Property>(propertyData);
return property;
}
int32_t InputMethodController::GetSoftKeyboardInfo(int32_t userId, BoundImeInfo &imeInfo)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("imsa proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
return proxy->GetSoftKeyboardInfo(userId, imeInfo);
}
std::shared_ptr<SubProperty> InputMethodController::GetCurrentInputMethodSubtype(int32_t userId)
{
InputMethodSyncTrace tracer("IMC_GetCurrentInputMethodSubtype");
IMSA_HILOGD("InputMethodController::GetCurrentInputMethodSubtype start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return nullptr;
}
SubProperty subPropertyData;
proxy->GetCurrentInputMethodSubtype(subPropertyData, userId);
auto subProperty = std::make_shared<SubProperty>(subPropertyData);
return subProperty;
}
bool InputMethodController::IsDefaultImeSet(int32_t userId)
{
IMSA_HILOGI("enter.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return false;
}
bool ret = false;
proxy->IsDefaultImeSet(ret, userId);
return ret;
}
int32_t InputMethodController::EnableIme(
const std::string &bundleName, const std::string &extensionName, EnabledStatus status, int32_t userId)
{
IMSA_HILOGI("enter.");
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.enableInputMethod", 1);
#endif
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return false;
}
return proxy->EnableIme(bundleName, extensionName, static_cast<int32_t>(status), userId);
}
int32_t InputMethodController::StartInput(
InputClientInfo &inputClientInfo, std::vector<sptr<IRemoteObject>> &agents, std::vector<BindImeInfo> &imeInfos)
{
IMSA_HILOGD("InputMethodController::StartInput start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
InputClientInfoInner inner = InputMethodTools::GetInstance().InputClientInfoToInner(inputClientInfo);
int32_t ret = proxy->StartInput(inner, agents, imeInfos);
return ret;
}
int32_t InputMethodController::ReleaseInput(sptr<IInputClient> &client, int32_t clientSessionId)
{
IMSA_HILOGD("InputMethodController::ReleaseInput start with clientSessionId: %{public}d.", clientSessionId);
auto proxy = TryGetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
int32_t ret = proxy->ReleaseInput(client, sessionId_.load(), clientSessionId);
if (ret == ErrorCode::NO_ERROR) {
OnInputStop();
}
SetTextListener(nullptr);
return ret;
}
int32_t InputMethodController::ShowInput(sptr<IInputClient> &client, ClientType type, int32_t requestKeyboardReason)
{
IMSA_HILOGD("InputMethodController::ShowInput start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
uint32_t windowId = ImfCommonConst::INVALID_WINDOW_ID;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
windowId = clientInfo_.config.windowId;
}
return proxy->ShowInput(client, windowId, type, requestKeyboardReason);
}
int32_t InputMethodController::HideInput(sptr<IInputClient> &client)
{
IMSA_HILOGD("InputMethodController::HideInput start.");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
uint32_t windowId = ImfCommonConst::INVALID_WINDOW_ID;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
windowId = clientInfo_.config.windowId;
}
return proxy->HideInput(client, windowId);
}
void InputMethodController::OnRemoteSaDied(const wptr<IRemoteObject> &remote)
{
IMSA_HILOGI("input method service death.");
InputStopInfo info;
info.scene = InputStopScene::IMSA_DIED;
ImeEventMonitorManagerImpl::GetInstance().OnInputStop(info);
auto textListener = GetTextListener();
if (textListener != nullptr && textConfig_.inputAttribute.isTextPreviewSupported) {
IMSA_HILOGD("finish text preview.");
textListener->FinishTextPreviewV2();
}
{
std::lock_guard<std::mutex> lock(abilityLock_);
abilityManager_ = nullptr;
}
ClearAgentInfo();
if (handler_ == nullptr) {
IMSA_HILOGE("handler_ is nullptr!");
return;
}
RestoreClientInfoInSaDied();
}
void InputMethodController::RestoreListenInfoInSaDied()
{
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
if (clientInfo_.eventFlag == NO_EVENT_ON) {
return;
}
}
isDiedRestoreListen_.store(false);
auto restoreListenTask = [=]() {
if (isDiedRestoreListen_.load()) {
return;
}
auto ret = RestoreListenEventFlag();
if (ret == ErrorCode::NO_ERROR) {
isDiedRestoreListen_.store(true);
IMSA_HILOGI("try to RestoreListen success.");
}
};
for (int i = 0; i < LOOP_COUNT; i++) {
handler_->PostTask(
restoreListenTask, "OnRemoteSaDied", DELAY_TIME * (i + 1), AppExecFwk::EventQueue::Priority::VIP);
}
}
void InputMethodController::RestoreClientInfoInSaDied()
{
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
return;
}
auto attach = [=]() -> bool {
TextConfig tempConfig {};
{
std::lock_guard<std::mutex> lock(textConfigLock_);
tempConfig = textConfig_;
tempConfig.range.start = selectNewBegin_;
tempConfig.range.end = selectNewEnd_;
}
{
std::lock_guard<std::mutex> lock(cursorInfoMutex_);
tempConfig.cursorInfo = cursorInfo_;
}
auto listener = GetTextListener();
bool isShowKeyboard = false;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
isShowKeyboard = clientInfo_.isShowKeyboard;
}
auto errCode = Attach(listener, isShowKeyboard, tempConfig);
IMSA_HILOGI("attach end, errCode: %{public}d", errCode);
return errCode == ErrorCode::NO_ERROR;
};
if (attach()) {
return;
}
isDiedAttached_.store(false);
auto attachTask = [this, attach]() {
if (isDiedAttached_.load()) {
return;
}
attach();
};
for (int i = 0; i < LOOP_COUNT; i++) {
handler_->PostTask(attachTask, "OnRemoteSaDied", DELAY_TIME * (i + 1), AppExecFwk::EventQueue::Priority::VIP);
}
}
int32_t InputMethodController::DiscardTypingText()
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.discardTypingText", 1);
#endif
if (!IsBound()) {
IMSA_HILOGE("not bound.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
return SendRequestToAllAgents([](std::shared_ptr<IInputMethodAgent> agent) -> int32_t {
return agent->DiscardTypingText();
});
}
int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo)
{
if (!IsBound()) {
IMSA_HILOGD("not bound.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
uint32_t windowId = 0;
{
std::lock_guard<std::mutex> lock(textConfigLock_);
windowId = textConfig_.windowId;
}
GetWindowScaleCoordinate(windowId, cursorInfo);
{
std::lock_guard<std::mutex> lock(textConfigLock_);
textConfig_.cursorInfo = cursorInfo;
}
{
std::lock_guard<std::mutex> lk(cursorInfoMutex_);
if (cursorInfo_ == cursorInfo) {
IMSA_HILOGD("same to last update.");
return ErrorCode::NO_ERROR;
}
cursorInfo_ = cursorInfo;
}
IMSA_HILOGI("left: %{public}d, top: %{public}d, height: %{public}d.", static_cast<int32_t>(cursorInfo.left),
static_cast<int32_t>(cursorInfo.top), static_cast<int32_t>(cursorInfo.height));
return SendRequestToAllAgents([cursorInfo](std::shared_ptr<IInputMethodAgent> agent) -> int32_t {
agent->OnCursorUpdate(cursorInfo.left, cursorInfo.top, cursorInfo.height);
return ErrorCode::NO_ERROR;
});
}
int32_t InputMethodController::OnSelectionChange(std::u16string text, int start, int end)
{
if (!IsBound()) {
IMSA_HILOGD("not bound.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
{
std::lock_guard<std::mutex> lock(textConfigLock_);
textConfig_.range.start = start;
textConfig_.range.end = end;
}
{
std::lock_guard<std::mutex> lock(editorContentLock_);
if (isTextNotified_.exchange(true) && textString_ == text && selectNewBegin_ == start && selectNewEnd_ == end) {
IMSA_HILOGD("same to last update.");
return ErrorCode::NO_ERROR;
}
textString_ = text;
selectOldBegin_ = selectNewBegin_;
selectOldEnd_ = selectNewEnd_;
selectNewBegin_ = start;
selectNewEnd_ = end;
}
IMSA_HILOGI("IMC size: %{public}zu, range: %{public}d/%{public}d/%{public}d/%{public}d.", text.size(),
selectOldBegin_, selectOldEnd_, start, end);
std::string testString = Str16ToStr8(text);
return SendRequestToAllAgents(
[testString, selectOldBegin = selectOldBegin_, selectOldEnd = selectOldEnd_, selectNewBegin = selectNewBegin_,
selectNewEnd = selectNewEnd_](std::shared_ptr<IInputMethodAgent> agent) -> int32_t {
agent->OnSelectionChange(testString, selectOldBegin, selectOldEnd, selectNewBegin, selectNewEnd);
return ErrorCode::NO_ERROR;
});
}
int32_t InputMethodController::OnConfigurationChange(Configuration info)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.updateAttribute", 1);
#endif
if (!IsBound()) {
IMSA_HILOGD("not bound.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
bool oldSecurityFlag = textConfig_.inputAttribute.GetSecurityFlag();
InputAttribute attribute;
{
std::lock_guard<std::mutex> lock(textConfigLock_);
textConfig_.inputAttribute.enterKeyType = static_cast<int32_t>(info.GetEnterKeyType());
textConfig_.inputAttribute.inputPattern = static_cast<int32_t>(info.GetTextInputType());
if (info.HasConsumeKeyEvents()) {
textConfig_.inputAttribute.consumeKeyEvents = info.GetConsumeKeyEvents();
}
attribute = textConfig_.inputAttribute;
}
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
IMSA_HILOGI(
"IMC enterKeyType: %{public}d, textInputType: %{public}d, consumeKeyEvents: %{public}d.",
attribute.enterKeyType, attribute.inputPattern, attribute.consumeKeyEvents);
if (oldSecurityFlag != attribute.GetSecurityFlag()) {
GetTextConfig(clientInfo_.config);
std::vector<sptr<IRemoteObject>> agents;
std::vector<BindImeInfo> imeInfos;
int32_t ret = StartInput(clientInfo_, agents, imeInfos);
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
SetInputReady(agents, imeInfos);
}
auto agent = GetAgent();
if (agent == nullptr) {
IMSA_HILOGE("agent is nullptr!");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
InputAttributeInner inner = InputMethodTools::GetInstance().AttributeToInner(attribute);
agent->OnAttributeChange(inner);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::GetLeft(int32_t length, std::u16string &text)
{
InputMethodSyncTrace tracer("IMC_GetForward");
IMSA_HILOGD("start, length: %{public}d", length);
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or listener is nullptr!");
ReportBaseTextOperation(static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_GET_TEXT_BEFORE_CURSOR),
ErrorCode::ERROR_CLIENT_NOT_EDITABLE);
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
{
InputMethodSyncTrace aceTracer("ACE_GetForward");
text = listener->GetLeftTextOfCursorV2(length);
}
PrintLogIfAceTimeout(start);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::GetRight(int32_t length, std::u16string &text)
{
IMSA_HILOGD("start, length: %{public}d", length);
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or textListener_ is nullptr!");
ReportBaseTextOperation(static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_GET_TEXT_AFTER_CURSOR),
ErrorCode::ERROR_CLIENT_NOT_EDITABLE);
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
text = listener->GetRightTextOfCursorV2(length);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::GetTextIndexAtCursor(int32_t &index)
{
IMSA_HILOGD("start.");
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or textListener_ is nullptr!");
ReportBaseTextOperation(static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_GET_TEXT_INDEX_AT_CURSOR),
ErrorCode::ERROR_CLIENT_NOT_EDITABLE);
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
index = listener->GetTextIndexAtCursorV2();
return ErrorCode::NO_ERROR;
}
void InputMethodController::PrintKeyEventLog()
{
std::lock_guard<std::mutex> lock(logLock_);
auto now = system_clock::now();
if (keyEventCountInPeriod_ == 0) {
startLogTime_ = now;
}
keyEventCountInPeriod_++;
if (std::chrono::duration_cast<seconds>(now - startLogTime_).count() >= LOG_MAX_TIME) {
auto start = std::chrono::duration_cast<seconds>(startLogTime_.time_since_epoch()).count();
auto end = std::chrono::duration_cast<seconds>(now.time_since_epoch()).count();
IMSA_HILOGI("KeyEventCountInPeriod: %{public}d, startTime: %{public}lld, endTime: %{public}lld",
keyEventCountInPeriod_, start, end);
keyEventCountInPeriod_ = 0;
}
}
int32_t InputMethodController::DispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent, KeyEventCallback callback)
{
int64_t startTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
PrintKeyEventLog();
KeyEventInfo keyEventInfo = { std::chrono::system_clock::now(), keyEvent };
keyEventQueue_.Push(keyEventInfo);
InputMethodSyncTrace tracer("DispatchKeyEvent trace");
keyEventQueue_.Wait(keyEventInfo);
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
keyEventQueue_.Pop();
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
if (keyEvent == nullptr) {
IMSA_HILOGE("keyEvent is nullptr!");
keyEventQueue_.Pop();
return ErrorCode::ERROR_EX_NULL_POINTER;
}
auto agent = GetAgent();
if (agent == nullptr) {
IMSA_HILOGE("agent is nullptr!");
keyEventQueue_.Pop();
return ErrorCode::ERROR_IME_NOT_STARTED;
}
IMSA_HILOGD("start.");
sptr<IRemoteObject> channelObject = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
channelObject = clientInfo_.channel;
}
if (channelObject == nullptr) {
IMSA_HILOGE("channelObject is nullptr!");
keyEventQueue_.Pop();
return ErrorCode::ERROR_EX_NULL_POINTER;
}
auto cbId = keyEventRetHandler_.AddKeyEventCbInfo({ keyEvent, callback });
KeyEventValue keyEventValue;
keyEventValue.event = keyEvent;
auto ret = agent->DispatchKeyEvent(keyEventValue, cbId, channelObject);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to DispatchKeyEvent: %{public}d", ret);
keyEventRetHandler_.RemoveKeyEventCbInfo(cbId);
}
keyEventQueue_.Pop();
int64_t endTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
if (endTime - startTime > DISPATCH_KEYBOARD_TIME_OUT) {
IMSA_HILOGW("DispatchKeyEvent timeout: [%{public}" PRId64 ", %{public}" PRId64 "].", startTime, endTime);
}
return ret;
}
void InputMethodController::HandleKeyEventResult(uint64_t cbId, bool consumeResult)
{
keyEventRetHandler_.HandleKeyEventResult(cbId, consumeResult);
}
int32_t InputMethodController::GetEnterKeyType(int32_t &keyType)
{
IMSA_HILOGD("InputMethodController::GetEnterKeyType start.");
std::lock_guard<std::mutex> lock(textConfigLock_);
keyType = textConfig_.inputAttribute.enterKeyType;
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::GetInputPattern(int32_t &inputpattern)
{
IMSA_HILOGD("InputMethodController::GetInputPattern start.");
std::lock_guard<std::mutex> lock(textConfigLock_);
inputpattern = textConfig_.inputAttribute.inputPattern;
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::GetTextConfig(TextTotalConfig &config)
{
std::lock_guard<std::mutex> lock(textConfigLock_);
config.inputAttribute = textConfig_.inputAttribute;
config.cursorInfo = textConfig_.cursorInfo;
config.windowId = textConfig_.windowId;
config.positionY = textConfig_.positionY;
config.height = textConfig_.height;
config.privateCommand = textConfig_.privateCommand;
config.abilityToken = textConfig_.abilityToken;
if (textConfig_.range.start == INVALID_VALUE) {
IMSA_HILOGD("SelectionRange is invalid.");
} else {
{
std::lock_guard<std::mutex> editorLock(editorContentLock_);
config.textSelection.oldBegin = selectOldBegin_;
config.textSelection.oldEnd = selectOldEnd_;
}
config.textSelection.newBegin = textConfig_.range.start;
config.textSelection.newEnd = textConfig_.range.end;
}
IMSA_HILOGD("textConfig: %{public}s.", config.ToString().c_str());
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::GetCurrentCursorInfo(CursorInfo &cursorInfo)
{
IMSA_HILOGD("InputMethodController::GetCurrentCursorInfo start.");
std::lock_guard<std::mutex> lock(textConfigLock_);
cursorInfo.left = textConfig_.cursorInfo.left;
cursorInfo.top = textConfig_.cursorInfo.top;
cursorInfo.width = textConfig_.cursorInfo.width;
cursorInfo.height = textConfig_.cursorInfo.height;
IMSA_HILOGD("GetCurrentCursorInfo: left=%{public}f, top=%{public}f, width=%{public}f, height=%{public}f.",
cursorInfo.left, cursorInfo.top, cursorInfo.width, cursorInfo.height);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::GetCursorInfo(CursorInfo &cursorInfo, int32_t userId)
{
IMSA_HILOGD("InputMethodController::GetCursorInfo start, userId: %{public}d.", userId);
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
CursorInfoInner cursorInfoInner;
int32_t ret = proxy->GetCursorInfo(userId, cursorInfoInner);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCursorInfo failed: %{public}d", ret);
return ret;
}
cursorInfo = InputMethodTools::GetInstance().InnerToCursorInfo(cursorInfoInner);
if (IsEditable()) {
GetCurrentCursorInfo(cursorInfo);
}
CursorInfo invalidCursor = { -1.0, -1.0, -1.0, -1.0, 0 };
if (cursorInfo == invalidCursor) {
cursorInfo = { 0, 0, 0, 0, 0 };
}
IMSA_HILOGD(
"cursorInfo:left=%{public}f,top=%{public}f,width=%{public}f,height=%{public}f,displayId=%{public}" PRIu64 "",
cursorInfo.left, cursorInfo.top, cursorInfo.width, cursorInfo.height, cursorInfo.displayId);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::SetCallingWindow(uint32_t windowId)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.setCallingWindow", 1);
#endif
if (!IsBound()) {
IMSA_HILOGD("not bound.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
{
std::lock_guard<std::mutex> lock(textConfigLock_);
textConfig_.windowId = windowId;
}
auto ret = SetCallingWindowByIMSA(windowId);
if (ret == ErrorCode::NO_ERROR) {
return ret;
}
auto agent = GetAgent();
if (agent == nullptr) {
IMSA_HILOGE("agent is nullptr!");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
IMSA_HILOGI("windowId: %{public}d.", windowId);
agent->SetCallingWindow(windowId);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::SetCallingWindowByIMSA(uint32_t windowId)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
auto ret = proxy->SetCallingWindow(windowId, clientInfo_.client);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed:%{public}d!", ret);
return ret;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::ShowSoftKeyboardInner(ClientType type)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
IMSA_HILOGI("clientType:%{public}d.", type);
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.isShowKeyboard = true;
}
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL);
return proxy->ShowCurrentInput(type);
}
int32_t InputMethodController::ShowSoftKeyboardInner(uint64_t displayId, ClientType type)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_SERVICE_START_FAILED;
}
IMSA_HILOGI("displayId/clientType:%{public}" PRIu64 "/%{public}d.", displayId, type);
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_SHOW_NORMAL);
return proxy->ShowCurrentInput(displayId, type);
}
int32_t InputMethodController::HideSoftKeyboard()
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.hideSoftKeyboard", 1);
#endif
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGI("start.");
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.isShowKeyboard = false;
}
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL);
return proxy->HideCurrentInput();
}
int32_t InputMethodController::HideSoftKeyboard(uint64_t displayId)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.hideSoftKeyboard", 1);
#endif
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGI("displayId:%{public}" PRIu64 ".", displayId);
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_NORMAL);
return proxy->HideCurrentInput(displayId);
}
int32_t InputMethodController::StopInputSession()
{
IMSA_HILOGI("start.");
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.stopInputSession", 1);
#endif
isEditable_.store(false);
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
uint32_t windowId = ImfCommonConst::INVALID_WINDOW_ID;
if (IsBound()) {
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
windowId = clientInfo_.config.windowId;
}
return proxy->StopInputSession(windowId);
}
int32_t InputMethodController::ShowOptionalInputMethod()
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGI("IMC start.");
return proxy->DisplayOptionalInputMethod();
}
int32_t InputMethodController::ListInputMethodSubtype(const Property &property, std::vector<SubProperty> &subProps,
int32_t userId)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGD("ime bundleName: %{public}s.", property.name.c_str());
return proxy->ListInputMethodSubtype(property.name, subProps, userId);
}
int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps, int32_t userId)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGD("start.");
return proxy->ListCurrentInputMethodSubtype(subProps, userId);
}
int32_t InputMethodController::SwitchInputMethod(
SwitchTrigger trigger, const std::string &name, const std::string &subName, int32_t userId)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.switchInputMethod", 1);
#endif
InputMethodSyncTrace tracer("IMC_SwitchInputMethod");
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGI("name: %{public}s, subName: %{public}s, trigger: %{public}d.", name.c_str(), subName.c_str(),
static_cast<uint32_t>(trigger));
auto ret = proxy->SwitchInputMethod(name, subName, static_cast<uint32_t>(trigger), userId);
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
if (ret != ErrorCode::NO_ERROR) {
int32_t errcode = ImfHiSysEventUtil::ConvertErrorCode(ret);
HISTOGRAM_ENUMERATION("imekit.inputMethod.switchInputMethod.error_code", errcode, ErrorCode::ERROR_IMSA_END);
}
#endif
return ret;
}
int32_t InputMethodController::SetEDCDefaultInputMethod(const std::string &edcBackupImeName)
{
if (edcBackupImeName.empty()) {
IMSA_HILOGE("Invalid parameter: edcBackupImeName is empty");
return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
}
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("Proxy is nullptr");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
return proxy->SetEDCDefaultInputMethod(edcBackupImeName);
}
int32_t InputMethodController::SetSimpleKeyboardEnabled(bool enable)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.setSimpleKeyboardEnabled", 1);
#endif
InputMethodSyncTrace tracer("IMC_SetSimpleKeyboardEnabled");
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.config.isSimpleKeyboardEnabled = enable;
return ErrorCode::NO_ERROR;
}
void InputMethodController::OnInputReady(sptr<IRemoteObject> agentObject, const BindImeInfo &imeInfo)
{
IMSA_HILOGD("InputMethodController start.");
if (imeInfo.bundleName != IME_MIRROR_NAME) {
SetBindImeInfo(std::make_pair(imeInfo.pid, imeInfo.bundleName));
isBound_.store(true);
isEditable_.store(true);
} else {
IMSA_HILOGD("[ImeMirrorTag] proxyIme_IME_MIRROR no need to set bindImeInfo");
}
if (agentObject == nullptr) {
IMSA_HILOGE("agentObject is nullptr!");
return;
}
SetAgent(agentObject, imeInfo.bundleName);
}
void InputMethodController::SetInputReady(
const std::vector<sptr<IRemoteObject>> &agentObjects, const std::vector<BindImeInfo> &imeInfos)
{
if (agentObjects.size() != imeInfos.size()) {
IMSA_HILOGE("[ImeMirrorTag]agentObjects.size() != imeInfos.size()!");
return;
}
for (size_t i = 0; i < agentObjects.size(); i++) {
OnInputReady(agentObjects[i], imeInfos[i]);
}
}
void InputMethodController::OnTmpInputStop(const sptr<IRemoteObject> &proxy)
{
ClearAgentInfo();
bool isNewEditor = false;
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
isNewEditor = clientInfo_.isNotifyInputStart;
}
auto listener = GetTextListener();
if (!isNewEditor && listener != nullptr) {
IMSA_HILOGD("listener is not nullptr!");
if (textConfig_.inputAttribute.isTextPreviewSupported) {
IMSA_HILOGD("finish text preview.");
listener->FinishTextPreviewV2();
}
}
isBound_.store(false);
isEditable_.store(false);
isTextNotified_.store(false);
keyEventRetHandler_.ClearKeyEventCbInfo();
if (proxy == nullptr) {
IMSA_HILOGD("proxy is nullptr!");
return;
}
auto channelProxy = std::make_shared<OnInputStopNotifyProxy>(proxy);
channelProxy->NotifyOnInputStopFinished();
}
void InputMethodController::OnInputStop(bool isStopInactiveClient, const sptr<IRemoteObject> &proxy,
bool isSendKeyboardStatus, bool isStopByMultiPreemptInProc)
{
if (isStopByMultiPreemptInProc) {
OnTmpInputStop(proxy);
return;
}
ClearAgentInfo();
auto listener = GetTextListener();
if (listener != nullptr) {
IMSA_HILOGD("listener is not nullptr!");
if (textConfig_.inputAttribute.isTextPreviewSupported) {
IMSA_HILOGD("finish text preview.");
listener->FinishTextPreviewV2();
}
if (isSendKeyboardStatus && (!isStopInactiveClient || !listener->IsFromTs())) {
listener->SendKeyboardStatusV2(KeyboardStatus::HIDE);
}
}
isBound_.store(false);
isEditable_.store(false);
isTextNotified_.store(false);
keyEventRetHandler_.ClearKeyEventCbInfo();
{
std::lock_guard<std::mutex> lock(editorContentLock_);
textString_ = Str8ToStr16("");
selectOldBegin_ = INVALID_VALUE;
selectOldEnd_ = INVALID_VALUE;
selectNewBegin_ = INVALID_VALUE;
selectNewEnd_ = INVALID_VALUE;
}
auto now = steady_clock::now();
if (std::chrono::duration_cast<seconds>(now - textChangeStartLogTime_).count() > LOG_INSERT_MIN_TIME &&
std::chrono::duration_cast<seconds>(now - textChangeStartLogTime_).count() < LOG_INSERT_MAX_TIME) {
IMSA_HILOGW("unbind before insertText PrintTextChangeLogCount: %{public}d !", textChangeCountInPeriod_);
}
if (proxy == nullptr) {
IMSA_HILOGD("proxy is nullptr!");
return;
}
auto channelProxy = std::make_shared<OnInputStopNotifyProxy>(proxy);
channelProxy->NotifyOnInputStopFinished();
}
void InputMethodController::OnImeMirrorStop(sptr<IRemoteObject> object)
{
std::lock_guard guard(agentLock_);
auto pos = find_if(agentInfoList_.begin(), agentInfoList_.end(), [object](const AgentInfo &agentInfo) {
return agentInfo.agentObject == object;
});
if (pos == agentInfoList_.end()) {
IMSA_HILOGE("[ImeMirrorTag] object is not in agentInfoList.");
return;
}
pos->agentObject = nullptr;
pos->agent = nullptr;
agentInfoList_.erase(pos);
IMSA_HILOGI("[ImeMirrorTag]remove agent");
}
void InputMethodController::ClearEditorCache(bool isNewEditor, sptr<OnTextChangedListener> lastListener)
{
IMSA_HILOGD("isNewEditor: %{public}d.", isNewEditor);
bool isTextPreviewSupported = false;
{
std::lock_guard<std::mutex> lock(textConfigLock_);
isTextPreviewSupported = textConfig_.inputAttribute.isTextPreviewSupported;
}
if (isNewEditor && isBound_.load() && lastListener != nullptr && isTextPreviewSupported) {
IMSA_HILOGD("last editor FinishTextPreview");
lastListener->FinishTextPreviewV2();
}
{
std::lock_guard<std::mutex> lock(editorContentLock_);
if (isNewEditor || !isBound_.load()) {
isTextNotified_.store(false);
textString_ = Str8ToStr16("");
selectOldBegin_ = INVALID_VALUE;
selectOldEnd_ = INVALID_VALUE;
selectNewBegin_ = INVALID_VALUE;
selectNewEnd_ = INVALID_VALUE;
}
}
{
std::lock_guard<std::mutex> lock(textConfigLock_);
textConfig_ = {};
}
{
std::lock_guard<std::mutex> lock(cursorInfoMutex_);
cursorInfo_ = {};
}
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
auto isSimpleKeyboardEnabled = clientInfo_.config.isSimpleKeyboardEnabled;
clientInfo_.config = {};
clientInfo_.config.isSimpleKeyboardEnabled = isSimpleKeyboardEnabled;
}
}
void InputMethodController::SelectByRange(int32_t start, int32_t end)
{
IMSA_HILOGD("InputMethodController start: %{public}d, end: %{public}d.", start, end);
auto listener = GetTextListener();
if (IsEditable() && listener != nullptr) {
listener->HandleSetSelectionV2(start, end);
} else {
IMSA_HILOGE("not editable or textListener_ is nullptr!");
}
if (controllerListener_ != nullptr) {
controllerListener_->OnSelectByRange(start, end);
} else {
IMSA_HILOGE("controllerListener_ is nullptr!");
}
}
void InputMethodController::SelectByMovement(int32_t direction, int32_t cursorMoveSkip)
{
IMSA_HILOGD(
"InputMethodController start, direction: %{public}d, cursorMoveSkip: %{public}d", direction, cursorMoveSkip);
auto listener = GetTextListener();
if (IsEditable() && listener != nullptr) {
listener->HandleSelectV2(CURSOR_DIRECTION_BASE_VALUE + direction, cursorMoveSkip);
} else {
IMSA_HILOGE("not editable or textListener_ is nullptr!");
}
if (controllerListener_ != nullptr) {
controllerListener_->OnSelectByMovement(direction);
} else {
IMSA_HILOGE("controllerListener_ is nullptr!");
}
}
int32_t InputMethodController::HandleExtendAction(int32_t action)
{
IMSA_HILOGD("InputMethodController start, action: %{public}d.", action);
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or textListener is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
listener->HandleExtendActionV2(action);
return ErrorCode::NO_ERROR;
}
sptr<OnTextChangedListener> InputMethodController::GetTextListener()
{
std::lock_guard<std::mutex> lock(textListenerLock_);
return textListener_;
}
void InputMethodController::SetTextListener(sptr<OnTextChangedListener> listener)
{
std::lock_guard<std::mutex> lock(textListenerLock_);
textListener_ = listener;
}
bool InputMethodController::IsEditable()
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
if (clientInfo_.state != ClientState::ACTIVE) {
IMSA_HILOGD("client is not active.");
return false;
}
if (!isEditable_.load()) {
IMSA_HILOGD("not in editable state.");
return false;
}
return true;
}
bool InputMethodController::IsBound()
{
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
if (clientInfo_.state != ClientState::ACTIVE) {
IMSA_HILOGD("client is not active.");
return false;
}
if (!isBound_.load()) {
IMSA_HILOGD("not bound.");
return false;
}
return true;
}
int32_t InputMethodController::InsertText(const std::u16string &text)
{
InputMethodSyncTrace tracer("IMC_InsertText");
IMSA_HILOGD("start.");
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or textListener is nullptr!");
ReportBaseTextOperation(
static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_INSERT_TEXT), ErrorCode::ERROR_CLIENT_NOT_EDITABLE);
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
{
InputMethodSyncTrace aceTracer("ACE_InsertText");
IMSA_HILOGD("ACE InsertText.");
listener->InsertTextV2(text);
}
PrintTextChangeLog();
PrintLogIfAceTimeout(start);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::DeleteForward(int32_t length)
{
InputMethodSyncTrace tracer("IMC_DeleteForward");
IMSA_HILOGD("start, length: %{public}d.", length);
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or textListener is nullptr!");
ReportBaseTextOperation(static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_DELETE_FORWARD),
ErrorCode::ERROR_CLIENT_NOT_EDITABLE);
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
{
InputMethodSyncTrace aceTracer("ACE_DeleteForward");
listener->DeleteBackwardV2(length);
}
PrintLogIfAceTimeout(start);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::DeleteBackward(int32_t length)
{
IMSA_HILOGD("InputMethodController start, length: %{public}d.", length);
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or textListener is nullptr!");
ReportBaseTextOperation(static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_DELETE_BACKWARD),
ErrorCode::ERROR_CLIENT_NOT_EDITABLE);
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
listener->DeleteForwardV2(length);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::MoveCursor(Direction direction)
{
IMSA_HILOGD("InputMethodController start, direction: %{public}d.", static_cast<int32_t>(direction));
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or textListener_ is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
listener->MoveCursorV2(direction);
return ErrorCode::NO_ERROR;
}
void InputMethodController::SendKeyboardStatus(KeyboardStatus status)
{
IMSA_HILOGD("InputMethodController status: %{public}d.", static_cast<int32_t>(status));
auto listener = GetTextListener();
if (listener == nullptr) {
IMSA_HILOGE("listener is nullptr!");
return;
}
listener->SendKeyboardStatusV2(status);
if (status == KeyboardStatus::HIDE) {
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.isShowKeyboard = false;
}
}
void InputMethodController::NotifyPanelStatusInfo(const PanelStatusInfo &info)
{
IMSA_HILOGD("InputMethodController start, type: %{public}d, flag: %{public}d, visible: %{public}d, trigger: "
"%{public}d, sessionId: %{public}u, clientSessionId: %{public}d.",
static_cast<PanelType>(info.panelInfo.panelType), static_cast<PanelFlag>(info.panelInfo.panelFlag),
info.visible, static_cast<Trigger>(info.trigger), info.sessionId, info.clientSessionId);
auto listener = GetTextListener();
if (listener == nullptr) {
IMSA_HILOGE("listener is nullptr!");
return;
}
if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD &&
info.panelInfo.panelFlag != PanelFlag::FLG_CANDIDATE_COLUMN) {
info.visible ? SendKeyboardStatus(KeyboardStatus::SHOW) : SendKeyboardStatus(KeyboardStatus::HIDE);
}
if (info.visible || info.sessionId == 0 || info.sessionId == sessionId_) {
listener->NotifyPanelStatusInfoV2(info);
}
if (info.panelInfo.panelType == PanelType::SOFT_KEYBOARD &&
info.panelInfo.panelFlag != PanelFlag::FLG_CANDIDATE_COLUMN && !info.visible) {
std::lock_guard<std::recursive_mutex> lock(clientInfoLock_);
clientInfo_.isShowKeyboard = false;
}
}
void InputMethodController::NotifyKeyboardHeight(uint32_t height)
{
IMSA_HILOGD("InputMethodController start, height: %{public}u.", height);
auto listener = GetTextListener();
if (listener == nullptr) {
IMSA_HILOGE("listener is nullptr!");
return;
}
listener->NotifyKeyboardHeightV2(height);
}
int32_t InputMethodController::SendFunctionKey(int32_t functionKey)
{
IMSA_HILOGD("InputMethodController start, functionKey: %{public}d", static_cast<int32_t>(functionKey));
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or listener is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
FunctionKey funcKey;
funcKey.SetEnterKeyType(static_cast<EnterKeyType>(functionKey));
listener->SendFunctionKeyV2(funcKey);
SendRequestToImeMirrorAgent([&functionKey](std::shared_ptr<IInputMethodAgent> agent) -> int32_t {
return agent->OnFunctionKey(functionKey);
});
return ErrorCode::NO_ERROR;
}
bool InputMethodController::IsInputTypeSupported(InputType type)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
IMSA_HILOGI("type: %{public}d.", static_cast<int32_t>(type));
bool ret = false;
proxy->IsInputTypeSupported(static_cast<int32_t>(type), ret);
return ret;
}
bool InputMethodController::IsCurrentImeByPid(int32_t pid, int32_t userId)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return false;
}
bool ret = false;
proxy->IsCurrentImeByPid(pid, ret, userId);
return ret;
}
int32_t InputMethodController::StartInputType(InputType type, bool isPersistence)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
IMSA_HILOGI("type: %{public}d, isPersistence: %{public}d.", static_cast<int32_t>(type), isPersistence);
return proxy->StartInputType(static_cast<int32_t>(type), isPersistence);
}
int32_t InputMethodController::StartInputTypeAsync(InputType type, bool isPersistence)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
IMSA_HILOGI("type: %{public}d, isPersistence: %{public}d.", static_cast<int32_t>(type), isPersistence);
return proxy->StartInputTypeAsync(static_cast<int32_t>(type), isPersistence);
}
int32_t InputMethodController::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
IMSA_HILOGD("type: %{public}d, flag: %{public}d.", static_cast<int32_t>(panelInfo.panelType),
static_cast<int32_t>(panelInfo.panelFlag));
return proxy->IsPanelShown(panelInfo, isShown);
}
int32_t InputMethodController::IsPanelShown(uint64_t displayId, const PanelInfo &panelInfo, bool &isShown)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
IMSA_HILOGD("displayId/type/flag:%{public}" PRIu64 "/%{public}d/%{public}d.", displayId,
static_cast<int32_t>(panelInfo.panelType), static_cast<int32_t>(panelInfo.panelFlag));
return proxy->IsPanelShown(displayId, panelInfo, isShown);
}
void InputMethodController::SetAgent(const sptr<IRemoteObject> &agentObject, const std::string &bundleName)
{
std::lock_guard<std::mutex> autoLock(agentLock_);
for (auto &agentInfo : agentInfoList_) {
if (agentInfo.agent != nullptr && agentInfo.agentObject.GetRefPtr() == agentObject.GetRefPtr()) {
IMSA_HILOGD("[ImeMirrorTag]agent has already been set.");
return;
}
}
if (agentInfoList_.size() >= MAX_AGENT_NUMBER) {
IMSA_HILOGW("[ImeMirrorTag]agent num is too many");
}
AgentInfo agentInfo;
agentInfo.agent = std::make_shared<InputMethodAgentProxy>(agentObject);
agentInfo.agentObject = agentObject;
agentInfo.imeType = (bundleName == IME_MIRROR_NAME) ? ImeType::IME_MIRROR : ImeType::NONE;
agentInfoList_.push_back(agentInfo);
}
std::shared_ptr<IInputMethodAgent> InputMethodController::GetAgent()
{
std::lock_guard<std::mutex> autoLock(agentLock_);
for (auto &agentInfo : agentInfoList_) {
if (agentInfo.agent != nullptr && agentInfo.imeType != ImeType::IME_MIRROR) {
return agentInfo.agent;
}
}
IMSA_HILOGE("no agent found!");
return nullptr;
}
void InputMethodController::PrintLogIfAceTimeout(int64_t start)
{
int64_t end = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
if (end < start || start < 0) {
return;
}
if (end - start > ACE_DEAL_TIME_OUT) {
IMSA_HILOGW("timeout: [%{public}" PRId64 ", %{public}" PRId64 "].", start, end);
}
}
void InputMethodController::PrintTextChangeLog()
{
std::lock_guard<std::mutex> lock(printTextChangeMutex_);
auto now = steady_clock::now();
if (textChangeCountInPeriod_ == 0) {
textChangeStartLogTime_ = now;
}
textChangeCountInPeriod_++;
if (std::chrono::duration_cast<seconds>(now - textChangeStartLogTime_).count() >= LOG_INSERT_MAX_TIME) {
IMSA_HILOGW("PrintTextChangeLogCount: %{public}d, ACE_InsertText success!", textChangeCountInPeriod_);
textChangeCountInPeriod_ = 0;
}
}
int32_t InputMethodController::ReceivePrivateCommand(
const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
auto listener = GetTextListener();
if (listener == nullptr) {
IMSA_HILOGE("listener is nullptr!");
return ErrorCode::ERROR_EX_NULL_POINTER;
}
IMSA_HILOGD("IMC in.");
auto ret = listener->ReceivePrivateCommandV2(privateCommand);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("ReceivePrivateCommand err, ret: %{public}d!", ret);
return ErrorCode::ERROR_TEXT_LISTENER_ERROR;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::SendPrivateCommand(
const std::unordered_map<std::string, PrivateDataValue> &privateCommand, bool validateDefaultIme)
{
if (!IsBound()) {
IMSA_HILOGD("not bound.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
if (!IsEditable()) {
IMSA_HILOGD("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
IMSA_HILOGE("invalid private command size!");
return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
}
auto agent = GetAgent();
if (agent == nullptr) {
IMSA_HILOGE("agent is nullptr!");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
IMSA_HILOGD("IMC start.");
Value value(privateCommand);
return agent->SendPrivateCommand(value);
}
void InputMethodController::SetBindImeInfo(const std::pair<int64_t, std::string> &imeInfo)
{
std::lock_guard<std::mutex> lock(bindImeInfoLock_);
bindImeInfo_ = imeInfo;
}
std::pair<int64_t, std::string> InputMethodController::GetBindImeInfo()
{
std::lock_guard<std::mutex> lock(bindImeInfoLock_);
return bindImeInfo_;
}
int32_t InputMethodController::SetPreviewTextInner(const std::string &text, const Range &range)
{
InputMethodSyncTrace tracer("IMC_SetPreviewText");
IMSA_HILOGD("IMC start.");
if (!textConfig_.inputAttribute.isTextPreviewSupported) {
IMSA_HILOGE("text preview do not supported!");
return ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED;
}
auto listener = GetTextListener();
if (!IsEditable() || listener == nullptr) {
IMSA_HILOGE("not editable or listener is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
int32_t ret = 0;
int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
{
InputMethodSyncTrace aceTracer("ACE_SetPreviewText");
ret = listener->SetPreviewTextV2(Str8ToStr16(text), range);
}
PrintTextChangeLog();
PrintLogIfAceTimeout(start);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to SetPreviewText: %{public}d!", ret);
return ret == -1 ? ErrorCode::ERROR_INVALID_RANGE : ErrorCode::ERROR_TEXT_LISTENER_ERROR;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::FinishTextPreview()
{
InputMethodSyncTrace tracer("IMC_FinishTextPreview");
IMSA_HILOGD("IMC start.");
if (!textConfig_.inputAttribute.isTextPreviewSupported) {
IMSA_HILOGD("text preview do not supported!");
ReportBaseTextOperation(static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_FINISH_TEXT_PREVIEW),
ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED);
return ErrorCode::ERROR_TEXT_PREVIEW_NOT_SUPPORTED;
}
auto listener = GetTextListener();
if (!isBound_.load() || listener == nullptr) {
IMSA_HILOGW("not bound or listener is nullptr!");
ReportBaseTextOperation(static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_FINISH_TEXT_PREVIEW),
ErrorCode::ERROR_CLIENT_NOT_EDITABLE);
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
{
InputMethodSyncTrace aceTracer("ACE_FinishTextPreview");
listener->FinishTextPreviewV2();
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodController::SendMessage(const ArrayBuffer &arrayBuffer)
{
if (!IsBound()) {
IMSA_HILOGE("not bound.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
if (!IsEditable()) {
IMSA_HILOGE("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
if (!ArrayBuffer::IsSizeValid(arrayBuffer)) {
IMSA_HILOGE("arrayBuffer size is invalid!");
return ErrorCode::ERROR_INVALID_ARRAY_BUFFER_SIZE;
}
auto agent = GetAgent();
if (agent == nullptr) {
IMSA_HILOGE("agent is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return agent->SendMessage(arrayBuffer);
}
int32_t InputMethodController::RecvMessage(const ArrayBuffer &arrayBuffer)
{
if (!IsBound()) {
IMSA_HILOGE("not bound.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
if (!IsEditable()) {
IMSA_HILOGE("not editable.");
return ErrorCode::ERROR_CLIENT_NOT_EDITABLE;
}
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 InputMethodController::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> InputMethodController::GetMsgHandlerCallback()
{
std::lock_guard<decltype(msgHandlerMutex_)> lock(msgHandlerMutex_);
return msgHandler_;
}
int32_t InputMethodController::GetInputMethodState(EnabledStatus &state)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
int32_t stateData = 0;
int32_t ret = proxy->GetInputMethodState(stateData);
state = static_cast<EnabledStatus>(stateData);
return ret;
}
int32_t InputMethodController::SetPreviewText(const std::string &text, const Range &range)
{
auto ret = SetPreviewTextInner(text, range);
ReportBaseTextOperation(static_cast<int32_t>(IInputDataChannelIpcCode::COMMAND_SET_PREVIEW_TEXT), ret);
return ret;
}
int32_t InputMethodController::ShowTextInput(ClientType type)
{
AttachOptions attachOptions;
return ShowTextInput(attachOptions, type);
}
int32_t InputMethodController::ShowTextInput(const AttachOptions &attachOptions, ClientType type)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.showTextInput", 1);
HISTOGRAM_ENUMERATION("imekit.inputMethod.attach.request_keyboard_reason",
static_cast<uint32_t>(attachOptions.requestKeyboardReason),
static_cast<uint32_t>(RequestKeyboardReason::OTHER));
#endif
auto ret = ShowTextInputInner(attachOptions, type);
ReportClientShow(static_cast<int32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT), ret, type);
return ret;
}
int32_t InputMethodController::ShowSoftKeyboard(ClientType type)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.showSoftKeyboard", 1);
#endif
auto ret = ShowSoftKeyboardInner(type);
ReportClientShow(static_cast<int32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT), ret, type);
return ret;
}
int32_t InputMethodController::ShowSoftKeyboard(uint64_t displayId, ClientType type)
{
#ifdef HIVIEWDFX_API_METRICS_EXT_ENABLE
HISTOGRAM_BOOLEAN("imekit.inputMethod.showSoftKeyboard", 1);
#endif
auto ret = ShowSoftKeyboardInner(displayId, type);
ReportClientShow(static_cast<int32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT), ret, type);
return ret;
}
void InputMethodController::ReportClientShow(int32_t eventCode, int32_t errCode, ClientType type)
{
IMSA_HILOGD("HiSysEvent report start!");
auto evenInfo = HiSysOriginalInfo::Builder()
.SetClientType(type)
.SetEventCode(eventCode)
.SetErrCode(errCode)
.Build();
ImcHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_SHOW, *evenInfo);
IMSA_HILOGD("HiSysEvent report end, errCode: %{public}d", errCode);
}
void InputMethodController::ReportBaseTextOperation(int32_t eventCode, int32_t errCode)
{
IMSA_HILOGD("HiSysEvent report start!");
auto imeInfo = GetBindImeInfo();
auto evenInfo = HiSysOriginalInfo::Builder()
.SetEventCode(eventCode)
.SetPeerName(imeInfo.second)
.SetPeerPid(imeInfo.first)
.SetClientType(clientInfo_.type)
.SetErrCode(errCode)
.Build();
ImcHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::BASE_TEXT_OPERATOR, *evenInfo);
IMSA_HILOGD("HiSysEvent report end, errCode: %{public}d", errCode);
}
void InputMethodController::UpdateTextPreviewState(bool isSupport)
{
if (textConfig_.inputAttribute.isTextPreviewSupported == isSupport) {
return;
}
textConfig_.inputAttribute.isTextPreviewSupported = isSupport;
auto agent = GetAgent();
if (agent == nullptr) {
IMSA_HILOGE("agent is nullptr!");
return;
}
InputAttributeInner inner = InputMethodTools::GetInstance().AttributeToInner(textConfig_.inputAttribute);
agent->OnAttributeChange(inner);
}
int32_t InputMethodController::SendPrivateData(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
auto proxy = GetSystemAbilityProxy();
if (proxy == nullptr) {
IMSA_HILOGE("proxy is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
Value value(privateCommand);
return proxy->SendPrivateData(value);
}
int32_t InputMethodController::RegisterWindowScaleCallbackHandler(WindowScaleCallback &&callback)
{
IMSA_HILOGD("isRegister: %{public}d", callback != nullptr);
std::lock_guard<std::mutex> lock(windowScaleCallbackMutex_);
windowScaleCallback_ = std::move(callback);
return static_cast<int32_t>(ErrorCode::NO_ERROR);
}
void InputMethodController::GetWindowScaleCoordinate(uint32_t windowId, CursorInfo &cursorInfo)
{
WindowScaleCallback handler = nullptr;
{
std::lock_guard<std::mutex> lock(windowScaleCallbackMutex_);
handler = windowScaleCallback_;
}
if (handler == nullptr) {
IMSA_HILOGD("handler is nullptr");
return;
}
handler(windowId, cursorInfo);
}
void InputMethodController::ClearAgentInfo()
{
std::lock_guard guard(agentLock_);
for (auto &agentInfo : agentInfoList_) {
agentInfo.agent = nullptr;
agentInfo.agentObject = nullptr;
}
IMSA_HILOGD("Clear all agent info");
agentInfoList_.clear();
}
int32_t InputMethodController::SendRequestToAllAgents(std::function<int32_t(std::shared_ptr<IInputMethodAgent>)> task)
{
std::lock_guard guard(agentLock_);
int32_t finalRet = ErrorCode::NO_ERROR;
for (auto &agentInfo : agentInfoList_) {
if (agentInfo.imeType == ImeType::IME_MIRROR && textConfig_.inputAttribute.IsSecurityImeFlag()) {
IMSA_HILOGW("password not allow send to ime mirror");
continue;
}
if (agentInfo.agent == nullptr) {
if (agentInfo.imeType == ImeType::IME_MIRROR) {
IMSA_HILOGW("ime mirror agent is null");
continue;
}
IMSA_HILOGE("agent is null");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
auto ret = task(agentInfo.agent);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed, ret = %{public}d", ret);
}
if (agentInfo.imeType != ImeType::IME_MIRROR) {
finalRet = ret;
}
}
IMSA_HILOGD("end, finalRet = %{public}d", finalRet);
return finalRet;
}
int32_t InputMethodController::SendRequestToImeMirrorAgent(
std::function<int32_t(std::shared_ptr<IInputMethodAgent>)> task)
{
std::lock_guard guard(agentLock_);
auto itr = std::find_if(agentInfoList_.begin(), agentInfoList_.end(), [](const AgentInfo &info) {
return info.imeType == ImeType::IME_MIRROR;
});
if (itr == agentInfoList_.end()) {
IMSA_HILOGD("ime mirror agent is not exist");
return ErrorCode::ERROR_IME_NOT_FOUND;
}
if (textConfig_.inputAttribute.IsSecurityImeFlag()) {
IMSA_HILOGE("text type is security, can not send function key");
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
return task(itr->agent);
}
void InputMethodController::NotifyAttachFailure(int32_t errCode)
{
auto listener = GetImcInnerListener();
if (listener == nullptr) {
return;
}
AttachFailureReason reason{ AttachFailureReason::SERVICE_ABNORMAL };
auto iter = ATTACH_FAILURE_REASON_MAP.find(errCode);
if (iter != ATTACH_FAILURE_REASON_MAP.end()) {
reason = iter->second;
}
listener->OnAttachmentDidFail(reason);
}
void InputMethodController::SetImcInnerListener(const std::shared_ptr<ImcInnerListener> &imcInnerListener)
{
std::lock_guard<std::mutex> lock(imcInnerListenerLock_);
if (imcInnerListener_ != nullptr) {
return;
}
imcInnerListener_ = imcInnerListener;
}
std::shared_ptr<ImcInnerListener> InputMethodController::GetImcInnerListener()
{
std::lock_guard<std::mutex> lock(imcInnerListenerLock_);
return imcInnerListener_;
}
void OnTextChangedListener::InsertTextV2(const std::u16string &text)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
InsertText(text);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, text]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("InsertTextV2 listener is nullptr!");
return;
}
listener->InsertText(text);
};
eventHandler->PostTask(task, "InsertTextV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::DeleteForwardV2(int32_t length)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
DeleteForward(length);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, length]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("DeleteForwardV2 listener is nullptr!");
return;
}
listener->DeleteForward(length);
};
eventHandler->PostTask(task, "DeleteForwardV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::DeleteBackwardV2(int32_t length)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
DeleteBackward(length);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, length]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("DeleteBackwardV2 listener is nullptr!");
return;
}
listener->DeleteBackward(length);
};
eventHandler->PostTask(task, "DeleteBackwardV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::SendKeyboardStatusV2(const KeyboardStatus &keyboardStatus)
{
auto eventHandler = GetEventHandler();
auto weakPtr = wptr<OnTextChangedListener>(this);
if (eventHandler == nullptr) {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("SendKeyboardStatusV2 listener is nullptr!");
return;
}
SendKeyboardStatus(keyboardStatus);
return;
}
auto task = [weakPtr, keyboardStatus]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("SendKeyboardStatusV2 listener is nullptr!");
return;
}
listener->SendKeyboardStatus(keyboardStatus);
};
eventHandler->PostTask(task, "SendKeyboardStatusV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::SendFunctionKeyV2(const FunctionKey &functionKey)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
SendFunctionKey(functionKey);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, functionKey]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("SendFunctionKeyV2 listener is nullptr!");
return;
}
listener->SendFunctionKey(functionKey);
};
eventHandler->PostTask(task, "SendFunctionKeyV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::MoveCursorV2(const Direction &direction)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
MoveCursor(direction);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, direction]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("MoveCursorV2 listener is nullptr!");
return;
}
listener->MoveCursor(direction);
};
eventHandler->PostTask(task, "MoveCursorV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::HandleExtendActionV2(int32_t action)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
HandleExtendAction(action);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, action]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("HandleExtendActionV2 listener is nullptr!");
return;
}
listener->HandleExtendAction(action);
};
eventHandler->PostTask(task, "HandleExtendActionV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
std::u16string OnTextChangedListener::GetLeftTextOfCursorV2(int32_t number)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
return GetLeftTextOfCursor(number);
}
auto textResultHandler = std::make_shared<BlockData<std::u16string>>(MAX_TIMEOUT);
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, textResultHandler, number]() {
std::u16string text;
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("GetLeftTextOfCursorV2 listener is nullptr!");
} else {
text = listener->GetLeftTextOfCursor(number);
}
if (textResultHandler != nullptr) {
textResultHandler->SetValue(text);
}
};
eventHandler->PostTask(task, "GetLeftTextOfCursorV2", 0, AppExecFwk::EventQueue::Priority::VIP);
std::u16string text;
if (textResultHandler != nullptr && !textResultHandler->GetValue(text)) {
IMSA_HILOGW("GetLeftTextOfCursorV2 timeout");
}
return text;
}
std::u16string OnTextChangedListener::GetRightTextOfCursorV2(int32_t number)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
return GetRightTextOfCursor(number);
}
auto textResultHandler = std::make_shared<BlockData<std::u16string>>(MAX_TIMEOUT);
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, textResultHandler, number]() {
std::u16string text;
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("GetRightTextOfCursorV2 listener is nullptr!");
} else {
text = listener->GetRightTextOfCursor(number);
}
if (textResultHandler != nullptr) {
textResultHandler->SetValue(text);
}
};
eventHandler->PostTask(task, "GetRightTextOfCursorV2", 0, AppExecFwk::EventQueue::Priority::VIP);
std::u16string text;
if (textResultHandler != nullptr && !textResultHandler->GetValue(text)) {
IMSA_HILOGW("GetRightTextOfCursorV2 timeout");
}
return text;
}
int32_t OnTextChangedListener::GetTextIndexAtCursorV2()
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
return GetTextIndexAtCursor();
}
auto textResultHandler = std::make_shared<BlockData<int32_t>>(MAX_TIMEOUT, -1);
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, textResultHandler]() {
int32_t index = -1;
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("GetTextIndexAtCursorV2 listener is nullptr!");
} else {
index = listener->GetTextIndexAtCursor();
}
if (textResultHandler != nullptr) {
textResultHandler->SetValue(index);
}
};
eventHandler->PostTask(task, "GetTextIndexAtCursorV2", 0, AppExecFwk::EventQueue::Priority::VIP);
int32_t index = -1;
if (textResultHandler != nullptr && !textResultHandler->GetValue(index)) {
IMSA_HILOGW("GetTextIndexAtCursorV2 timeout");
}
return index;
}
void OnTextChangedListener::SendKeyEventFromInputMethodV2(const KeyEvent &event)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
SendKeyEventFromInputMethod(event);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, event]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("SendKeyEventFromInputMethodV2 listener is nullptr!");
return;
}
listener->SendKeyEventFromInputMethod(event);
};
eventHandler->PostTask(task, "SendKeyEventFromInputMethodV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::NotifyPanelStatusInfoV2(const PanelStatusInfo &info)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
NotifyPanelStatusInfo(info);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, info]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("NotifyPanelStatusInfoV2 listener is nullptr!");
return;
}
listener->NotifyPanelStatusInfo(info);
};
eventHandler->PostTask(task, "NotifyPanelStatusInfoV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::NotifyKeyboardHeightV2(uint32_t height)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
NotifyKeyboardHeight(height);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, height]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("NotifyKeyboardHeightV2 listener is nullptr!");
return;
}
listener->NotifyKeyboardHeight(height);
};
eventHandler->PostTask(task, "NotifyKeyboardHeightV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::SetKeyboardStatusV2(bool status)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
SetKeyboardStatus(status);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, status]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("SetKeyboardStatusV2 listener is nullptr!");
return;
}
listener->SetKeyboardStatus(status);
};
eventHandler->PostTask(task, "SetKeyboardStatusV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::HandleSetSelectionV2(int32_t start, int32_t end)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
HandleSetSelection(start, end);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, start, end]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("HandleSetSelectionV2 listener is nullptr!");
return;
}
listener->HandleSetSelection(start, end);
};
eventHandler->PostTask(task, "HandleSetSelectionV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::HandleSelectV2(int32_t keyCode, int32_t cursorMoveSkip)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
HandleSelect(keyCode, cursorMoveSkip);
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, keyCode, cursorMoveSkip]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("HandleSelectV2 listener is nullptr!");
return;
}
listener->HandleSelect(keyCode, cursorMoveSkip);
};
eventHandler->PostTask(task, "HandleSelectV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
int32_t OnTextChangedListener::ReceivePrivateCommandV2(
const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
return ReceivePrivateCommand(privateCommand);
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, privateCommand]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("ReceivePrivateCommandV2 listener is nullptr!");
return;
}
listener->ReceivePrivateCommand(privateCommand);
};
eventHandler->PostTask(task, "ReceivePrivateCommandV2", 0, AppExecFwk::EventQueue::Priority::VIP);
return ErrorCode::NO_ERROR;
}
int32_t OnTextChangedListener::SetPreviewTextV2(const std::u16string &text, const Range &range)
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
return SetPreviewText(text, range);
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr, text, range]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("SetPreviewTextV2 listener is nullptr!");
return;
}
listener->SetPreviewText(text, range);
};
eventHandler->PostTask(task, "SetPreviewTextV2", 0, AppExecFwk::EventQueue::Priority::VIP);
return ErrorCode::NO_ERROR;
}
void OnTextChangedListener::FinishTextPreviewV2()
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
FinishTextPreview();
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("FinishTextPreviewV2 listener is nullptr!");
return;
}
listener->FinishTextPreview();
};
eventHandler->PostTask(task, "FinishTextPreviewV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void OnTextChangedListener::OnDetachV2()
{
auto eventHandler = GetEventHandler();
if (eventHandler == nullptr) {
OnDetach();
return;
}
auto weakPtr = wptr<OnTextChangedListener>(this);
auto task = [weakPtr]() {
auto listener = weakPtr.promote();
if (listener == nullptr) {
IMSA_HILOGE("OnDetachV2 listener is nullptr!");
return;
}
listener->OnDetach();
};
eventHandler->PostTask(task, "OnDetachV2", 0, AppExecFwk::EventQueue::Priority::VIP);
}
bool InputMethodController::SubscribeSaStart(std::function<void()> handler, int32_t saId)
{
if (handler == nullptr) {
IMSA_HILOGE("handler is nullptr");
return false;
}
{
std::lock_guard<std::mutex> lockGuard(listenerMapMutex_);
if (saMgrListener_ != nullptr) {
IMSA_HILOGW("saId:%{public}d is already registered", saId);
return true;
}
}
auto abilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (abilityManager == nullptr) {
IMSA_HILOGE("abilityManager is nullptr, saId: %{public}d", saId);
return false;
}
sptr<ISystemAbilityStatusChange> listener = new (std::nothrow) SaMgrListener([handler]() {
if (handler != nullptr) {
handler();
}
});
if (listener == nullptr) {
IMSA_HILOGE("failed to create listener, saId: %{public}d", saId);
return false;
}
int32_t ret = abilityManager->SubscribeSystemAbility(saId, listener);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("subscribe system ability failed, ret: %{public}d, saId: %{public}d", ret, saId);
return false;
}
{
std::lock_guard<std::mutex> lockGuard(listenerMapMutex_);
saMgrListener_ = listener;
}
IMSA_HILOGD("subscribe system ability success, saId: %{public}d", saId);
return true;
}
void SaMgrListener::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
{
IMSA_HILOGD("systemAbilityId: %{public}d.", systemAbilityId);
if (systemAbilityId != INPUT_METHOD_SYSTEM_ABILITY_ID) {
return;
}
if (func_ != nullptr) {
func_();
}
}
}
}