mirror of
https://gitee.com/openharmony/inputmethod_imf
synced 2024-11-23 14:49:59 +00:00
mod
Signed-off-by: cy7717 <chenyu301@huawei.com>
This commit is contained in:
parent
971fabbf7a
commit
9015661b8b
2
BUILD.gn
2
BUILD.gn
@ -23,7 +23,7 @@ group("imf_packages") {
|
||||
"etc/para:inputmethod_para",
|
||||
"frameworks/js/napi/inputmethodability:inputmethodengine",
|
||||
"frameworks/js/napi/inputmethodclient:inputmethod",
|
||||
"frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"interfaces/inner_api/inputmethod_controller:inputmethod_client",
|
||||
"profile:inputmethod_inputmethod_sa_profiles",
|
||||
"services:inputmethod_service",
|
||||
|
13
bundle.json
13
bundle.json
@ -64,9 +64,9 @@
|
||||
"//base/inputmethod/imf/etc/init:inputmethodservice.cfg",
|
||||
"//base/inputmethod/imf/etc/para:inputmethod.para.dac",
|
||||
"//base/inputmethod/imf/etc/para:inputmethod.para",
|
||||
"//base/inputmethod/imf/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"//base/inputmethod/imf/profile:inputmethod_inputmethod_sa_profiles",
|
||||
"//base/inputmethod/imf/services:inputmethod_service",
|
||||
"//base/inputmethod/imf/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"//base/inputmethod/imf/frameworks/kits/extension:inputmethod_extension",
|
||||
"//base/inputmethod/imf/frameworks/kits/extension:inputmethod_extension_module",
|
||||
"//base/inputmethod/imf/frameworks/js/napi/inputmethodability:inputmethodengine",
|
||||
@ -86,6 +86,17 @@
|
||||
],
|
||||
"header_base": "//base/inputmethod/imf/interfaces/inner_api/inputmethod_controller/include"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "//base/inputmethod/imf/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"header": {
|
||||
"header_files": [
|
||||
"../../../../frameworks/native/inputmethod_ability/include/input_method_engine_listener.h",
|
||||
"../../../../frameworks/native/inputmethod_ability/include/keyboard_listener.h",
|
||||
"input_method_ability_interface.h"
|
||||
],
|
||||
"header_base": "//base/inputmethod/imf/interfaces/inner_api/inputmethod_ability/include"
|
||||
}
|
||||
}
|
||||
],
|
||||
"test": [
|
||||
|
@ -62,7 +62,7 @@ ohos_shared_library("inputmethodengine") {
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/js/napi/common:inputmethod_js_common",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/services/dfx:inputmethod_dfx_static",
|
||||
]
|
||||
|
||||
|
@ -51,7 +51,7 @@ ohos_shared_library("inputmethod_extension") {
|
||||
public_configs = [ ":ability_public_config" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/services/dfx:inputmethod_dfx_static",
|
||||
]
|
||||
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
SET_SUBTYPE,
|
||||
START_INPUT,
|
||||
STOP_INPUT,
|
||||
IS_ENABLE,
|
||||
};
|
||||
|
||||
DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.IInputMethodCore");
|
||||
@ -54,6 +55,7 @@ public:
|
||||
sptr<IInputControlChannel> &inputControlChannel, const std::string &imeId) = 0;
|
||||
virtual void StopInputService(std::string imeId) = 0;
|
||||
virtual int32_t SetSubtype(const SubProperty &property) = 0;
|
||||
virtual bool IsEnable() = 0;
|
||||
};
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
|
@ -39,10 +39,6 @@
|
||||
|
||||
namespace OHOS {
|
||||
namespace MiscServices {
|
||||
struct InputStartNotifier {
|
||||
bool isNotify{ false };
|
||||
bool isShowKeyboard{ false };
|
||||
};
|
||||
class MessageHandler;
|
||||
class InputMethodAbility : public RefBase {
|
||||
public:
|
||||
@ -50,6 +46,7 @@ public:
|
||||
~InputMethodAbility();
|
||||
static sptr<InputMethodAbility> GetInstance();
|
||||
int32_t SetCoreAndAgent();
|
||||
int32_t ClearCoreAndAgent();
|
||||
int32_t InsertText(const std::string text);
|
||||
void SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener);
|
||||
void SetKdListener(std::shared_ptr<KeyboardListener> kdListener);
|
||||
@ -77,6 +74,7 @@ public:
|
||||
std::shared_ptr<InputMethodPanel> &inputMethodPanel);
|
||||
int32_t DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel);
|
||||
bool IsCurrentIme();
|
||||
bool IsEnable();
|
||||
|
||||
private:
|
||||
std::thread workThreadHandler;
|
||||
@ -93,8 +91,8 @@ private:
|
||||
std::shared_ptr<InputDataChannelProxy> dataChannelProxy_ = nullptr;
|
||||
std::shared_ptr<InputMethodEngineListener> imeListener_;
|
||||
std::shared_ptr<KeyboardListener> kdListener_;
|
||||
static std::mutex instanceLock_;
|
||||
|
||||
static std::mutex instanceLock_;
|
||||
static sptr<InputMethodAbility> instance_;
|
||||
std::mutex abilityLock_;
|
||||
sptr<IInputMethodSystemAbility> abilityManager_{ nullptr };
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
int32_t InitInputControlChannel(sptr<IInputControlChannel> &inputControlChannel, const std::string &imeId) override;
|
||||
void StopInputService(std::string imeId) override;
|
||||
int32_t SetSubtype(const SubProperty &property) override;
|
||||
bool IsEnable() override;
|
||||
|
||||
private:
|
||||
static inline BrokerDelegator<InputMethodCoreProxy> delegator_;
|
||||
|
@ -46,6 +46,7 @@ public:
|
||||
int32_t InitInputControlChannel(sptr<IInputControlChannel> &inputControlChannel, const std::string &imeId) override;
|
||||
void StopInputService(std::string imeId) override;
|
||||
int32_t SetSubtype(const SubProperty &property) override;
|
||||
bool IsEnable() override;
|
||||
void SetMessageHandler(MessageHandler *msgHandler);
|
||||
|
||||
private:
|
||||
|
@ -28,6 +28,10 @@ public:
|
||||
virtual void OnInputStop(const std::string &imeId) = 0;
|
||||
virtual void OnSetCallingWindow(uint32_t windowId) = 0;
|
||||
virtual void OnSetSubtype(const SubProperty &property) = 0;
|
||||
virtual bool IsEnable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
|
@ -16,8 +16,8 @@
|
||||
#ifndef INPUTMETHOD_IMF_KEYBOARD_LISTENER_H
|
||||
#define INPUTMETHOD_IMF_KEYBOARD_LISTENER_H
|
||||
|
||||
#include "input_attribute.h"
|
||||
#include "key_event.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace MiscServices {
|
||||
class KeyboardListener {
|
||||
|
@ -141,6 +141,11 @@ int32_t InputMethodAbility::SetCoreAndAgent()
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t InputMethodAbility::ClearCoreAndAgent()
|
||||
{
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
void InputMethodAbility::Initialize()
|
||||
{
|
||||
IMSA_HILOGI("InputMethodAbility::Initialize");
|
||||
@ -276,8 +281,8 @@ void InputMethodAbility::ClearDataChannel(const sptr<IRemoteObject> &channel)
|
||||
int32_t InputMethodAbility::StopInput(const sptr<IRemoteObject> &channelObject)
|
||||
{
|
||||
IMSA_HILOGI("run in");
|
||||
ClearDataChannel(channelObject);
|
||||
HideKeyboard();
|
||||
ClearDataChannel(channelObject);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
@ -764,5 +769,13 @@ bool InputMethodAbility::IsCurrentIme()
|
||||
}
|
||||
return proxy->IsCurrentIme();
|
||||
}
|
||||
|
||||
bool InputMethodAbility::IsEnable()
|
||||
{
|
||||
if (imeListener_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return imeListener_->IsEnable();
|
||||
}
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "input_method_ability_interface.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "input_method_ability.h"
|
||||
namespace OHOS {
|
||||
namespace MiscServices {
|
||||
std::mutex InputMethodAbilityInterface::instanceLock_;
|
||||
std::shared_ptr<InputMethodAbilityInterface> InputMethodAbilityInterface::instance_;
|
||||
std::shared_ptr<InputMethodAbilityInterface> InputMethodAbilityInterface::GetInstance()
|
||||
{
|
||||
if (instance_ == nullptr) {
|
||||
std::lock_guard<std::mutex> lock(instanceLock_);
|
||||
if (instance_ == nullptr) {
|
||||
IMSA_HILOGI("InputMethodAbility::GetInstance need new IMA");
|
||||
instance_ = std::make_shared<InputMethodAbilityInterface>();
|
||||
}
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int32_t InputMethodAbilityInterface::RegisteredProxy()
|
||||
{
|
||||
return InputMethodAbility::GetInstance()->SetCoreAndAgent();
|
||||
}
|
||||
|
||||
int32_t InputMethodAbilityInterface::UnRegisterProxy(uint32_t type)
|
||||
{
|
||||
return InputMethodAbility::GetInstance()->ClearCoreAndAgent();
|
||||
}
|
||||
|
||||
int32_t InputMethodAbilityInterface::ChangeProxyStatus(bool isEnable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t InputMethodAbilityInterface::InsertText(const std::string &text)
|
||||
{
|
||||
return InputMethodAbility::GetInstance()->InsertText(text);
|
||||
}
|
||||
|
||||
int32_t InputMethodAbilityInterface::DeleteForward(int32_t length)
|
||||
{
|
||||
return InputMethodAbility::GetInstance()->DeleteForward(length);
|
||||
}
|
||||
|
||||
int32_t InputMethodAbilityInterface::DeleteBackward(int32_t length)
|
||||
{
|
||||
return InputMethodAbility::GetInstance()->DeleteBackward(length);
|
||||
}
|
||||
|
||||
int32_t InputMethodAbilityInterface::MoveCursor(int32_t keyCode)
|
||||
{
|
||||
return InputMethodAbility::GetInstance()->MoveCursor(keyCode);
|
||||
}
|
||||
|
||||
void InputMethodAbilityInterface::SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener)
|
||||
{
|
||||
InputMethodAbility::GetInstance()->SetImeListener(imeListener);
|
||||
}
|
||||
|
||||
void InputMethodAbilityInterface::SetKdListener(std::shared_ptr<KeyboardListener> kdListener)
|
||||
{
|
||||
InputMethodAbility::GetInstance()->SetKdListener(kdListener);
|
||||
}
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
@ -75,6 +75,14 @@ int32_t InputMethodCoreProxy::StopInput(const sptr<IInputDataChannel> &channel)
|
||||
STOP_INPUT, [&channel](MessageParcel &data) { return ITypesUtil::Marshal(data, channel->AsObject()); });
|
||||
}
|
||||
|
||||
bool InputMethodCoreProxy::IsEnable()
|
||||
{
|
||||
bool isEnable = false;
|
||||
SendRequest(
|
||||
IS_ENABLE, nullptr, [&isEnable](MessageParcel &reply) { return ITypesUtil::Unmarshal(reply, isEnable); });
|
||||
return isEnable;
|
||||
}
|
||||
|
||||
int32_t InputMethodCoreProxy::SendRequest(int code, ParcelHandler input, ParcelHandler output)
|
||||
{
|
||||
IMSA_HILOGI("InputMethodCoreProxy, run in, code = %{public}d", code);
|
||||
|
@ -200,6 +200,11 @@ int32_t InputMethodCoreStub::StopInput(const sptr<IInputDataChannel> &channel)
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
bool InputMethodCoreStub::IsEnable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t InputMethodCoreStub::SendMessage(int code, ParcelHandler input)
|
||||
{
|
||||
IMSA_HILOGD("InputMethodCoreStub::SendMessage");
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "input_method_property.h"
|
||||
#include "input_window_info.h"
|
||||
#include "iremote_broker.h"
|
||||
|
||||
#include "unbind_cause.h"
|
||||
/**
|
||||
* brief Definition of interface IInputClient
|
||||
* It defines the remote calls from input method management service to input client.
|
||||
@ -36,7 +36,7 @@ public:
|
||||
DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.InputClient");
|
||||
|
||||
virtual int32_t OnInputReady(const sptr<IInputMethodAgent> &agent) = 0;
|
||||
virtual int32_t OnInputStop() = 0;
|
||||
virtual int32_t OnInputStop(UnBindCause cause) = 0;
|
||||
virtual int32_t OnSwitchInput(const Property &property, const SubProperty &subProperty) = 0;
|
||||
virtual int32_t OnPanelStatusChange(
|
||||
const InputWindowStatus &status, const std::vector<InputWindowInfo> &windowInfo) = 0;
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
DISALLOW_COPY_AND_MOVE(InputClientProxy);
|
||||
|
||||
int32_t OnInputReady(const sptr<IInputMethodAgent> &agent) override;
|
||||
int32_t OnInputStop() override;
|
||||
int32_t OnInputStop(UnBindCause cause) override;
|
||||
int32_t OnSwitchInput(const Property &property, const SubProperty &subProperty) override;
|
||||
int32_t OnPanelStatusChange(
|
||||
const InputWindowStatus &status, const std::vector<InputWindowInfo> &windowInfo) override;
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
~InputClientStub();
|
||||
|
||||
int32_t OnInputReady(const sptr<IInputMethodAgent> &agent) override;
|
||||
int32_t OnInputStop() override;
|
||||
int32_t OnInputStop(UnBindCause cause) override;
|
||||
int32_t OnSwitchInput(const Property &property, const SubProperty &subProperty) override;
|
||||
int32_t OnPanelStatusChange(
|
||||
const InputWindowStatus &status, const std::vector<InputWindowInfo> &windowInfo) override;
|
||||
|
@ -57,11 +57,13 @@ public:
|
||||
int32_t SwitchInputMethod(const std::string &name, const std::string &subName) override;
|
||||
int32_t DisplayOptionalInputMethod() override;
|
||||
int32_t SetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent) override;
|
||||
int32_t ClearCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent) override;
|
||||
int32_t ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps) override;
|
||||
int32_t ListInputMethodSubtype(const std::string &name, std::vector<SubProperty> &subProps) override;
|
||||
int32_t PanelStatusChange(const InputWindowStatus &status, const InputWindowInfo &windowInfo) override;
|
||||
int32_t UpdateListenEventFlag(InputClientInfo &clientInfo, EventType eventType) override;
|
||||
bool IsCurrentIme() override;
|
||||
int32_t ChangeProxyStatus(bool isEnable) override; //todo 不一定需要
|
||||
|
||||
// Deprecated because of no permission check, kept for compatibility
|
||||
int32_t HideCurrentInputDeprecated() override;
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#ifndef FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_UNBIND_CAUSE_H
|
||||
#define FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_UNBIND_CAUSE_H
|
||||
|
||||
namespace OHOS {
|
||||
namespace MiscServices {
|
||||
enum class UnBindCause : uint32_t {
|
||||
CLIENT_DIED = 0, //IMA停止输入core->StopInput(),removeclient()
|
||||
CLIENT_UNFOCUSED, // 清理imc的agent、监听、绑定标记等等(client->OnInputStop),core->StopInput(), removeclient()
|
||||
CLIENT_CLOSE_SELF, //清理imc的agent、监听、绑定标记等等(发起close时已清理),core->StopInput(), removeclient()
|
||||
IME_DIED, //清理imc的agent
|
||||
IME_SWITCH, //清理imc的agent,core->StopInput()
|
||||
};
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
#endif
|
@ -33,9 +33,10 @@ int32_t InputClientProxy::OnInputReady(const sptr<IInputMethodAgent> &agent)
|
||||
ON_INPUT_READY, [agent](MessageParcel &data) { return ITypesUtil::Marshal(data, agent->AsObject()); });
|
||||
}
|
||||
|
||||
int32_t InputClientProxy::OnInputStop()
|
||||
int32_t InputClientProxy::OnInputStop(UnBindCause cause)
|
||||
{
|
||||
return SendRequest(ON_INPUT_STOP);
|
||||
return SendRequest(
|
||||
ON_INPUT_STOP, [&cause](MessageParcel &data) { return data.WriteUint32(static_cast<uint32_t>(cause)); });
|
||||
}
|
||||
|
||||
int32_t InputClientProxy::OnSwitchInput(const Property &property, const SubProperty &subProperty)
|
||||
|
@ -71,7 +71,9 @@ void InputClientStub::OnInputReadyOnRemote(MessageParcel &data, MessageParcel &r
|
||||
|
||||
int32_t InputClientStub::OnInputStopOnRemote(MessageParcel &data, MessageParcel &reply)
|
||||
{
|
||||
return reply.WriteInt32(OnInputStop()) ? ErrorCode::NO_ERROR : ErrorCode::ERROR_EX_PARCELABLE;
|
||||
auto cause = data.ReadUint32();
|
||||
return reply.WriteInt32(OnInputStop(static_cast<UnBindCause>(cause))) ? ErrorCode::NO_ERROR
|
||||
: ErrorCode::ERROR_EX_PARCELABLE;
|
||||
}
|
||||
|
||||
int32_t InputClientStub::OnSwitchInputOnRemote(MessageParcel &data, MessageParcel &reply)
|
||||
@ -106,9 +108,9 @@ int32_t InputClientStub::OnInputReady(const sptr<IInputMethodAgent> &agent)
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t InputClientStub::OnInputStop()
|
||||
int32_t InputClientStub::OnInputStop(UnBindCause cause)
|
||||
{
|
||||
InputMethodController::GetInstance()->OnInputStop();
|
||||
InputMethodController::GetInstance()->OnInputStop(cause);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
|
@ -842,12 +842,18 @@ void InputMethodController::OnInputReady(sptr<IRemoteObject> agentObject)
|
||||
agent_ = agent;
|
||||
}
|
||||
|
||||
void InputMethodController::OnInputStop()
|
||||
void InputMethodController::OnInputStop(UnBindCause cause)
|
||||
{
|
||||
if (cause == UnBindCause::IME_DIED || cause == UnBindCause::IME_SWITCH) {
|
||||
std::lock_guard<std::mutex> autoLock(agentLock_);
|
||||
agent_ = nullptr;
|
||||
agentObject_ = nullptr;
|
||||
return;
|
||||
}
|
||||
auto listener = GetTextListener();
|
||||
if (listener != nullptr) {
|
||||
IMSA_HILOGD("textListener_ is not nullptr");
|
||||
listener->SendKeyboardStatus(KeyboardStatus::HIDE);
|
||||
listener->SendKeyboardStatus(KeyboardStatus::HIDE); //todo 此处DC是否要做特殊处理
|
||||
}
|
||||
isBound_.store(false);
|
||||
isEditable_.store(false);
|
||||
|
@ -196,6 +196,17 @@ bool InputMethodSystemAbilityProxy::IsCurrentIme()
|
||||
return isCurrentIme;
|
||||
}
|
||||
|
||||
int32_t InputMethodSystemAbilityProxy::ClearCoreAndAgent(
|
||||
const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent)
|
||||
{
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t InputMethodSystemAbilityProxy::ChangeProxyStatus(bool isEnable)
|
||||
{
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t InputMethodSystemAbilityProxy::SendRequest(int code, ParcelHandler input, ParcelHandler output)
|
||||
{
|
||||
IMSA_HILOGI("InputMethodSystemAbilityProxy run in, code = %{public}d", code);
|
||||
|
@ -18,6 +18,7 @@ config("inputmethod_ability_native_config") {
|
||||
visibility = [ ":*" ]
|
||||
include_dirs = [
|
||||
"include",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/include",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_controller/include",
|
||||
"${inputmethod_path}/frameworks/common",
|
||||
"${inputmethod_path}/services/dfx/include",
|
||||
@ -28,6 +29,7 @@ config("inputmethod_ability_native_public_config") {
|
||||
visibility = [ "./*" ]
|
||||
include_dirs = [
|
||||
"include",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/include",
|
||||
"${inputmethod_path}/frameworks/common",
|
||||
"${inputmethod_path}/services/dfx/include",
|
||||
"${inputmethod_path}/services/include",
|
||||
@ -39,6 +41,14 @@ config("inputmethod_ability_native_public_config") {
|
||||
|
||||
ohos_shared_library("inputmethod_ability") {
|
||||
sources = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability_interface.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability_utils.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_agent_proxy.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_agent_stub.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_core_proxy.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_core_stub.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_panel.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_client_proxy.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_data_channel_proxy.cpp",
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_death_recipient.cpp",
|
||||
@ -49,15 +59,10 @@ ohos_shared_library("inputmethod_ability") {
|
||||
"${inputmethod_path}/services/src/input_control_channel_proxy.cpp",
|
||||
"${inputmethod_path}/services/src/message.cpp",
|
||||
"${inputmethod_path}/services/src/message_handler.cpp",
|
||||
"src/input_method_ability.cpp",
|
||||
"src/input_method_ability_utils.cpp",
|
||||
"src/input_method_agent_proxy.cpp",
|
||||
"src/input_method_agent_stub.cpp",
|
||||
"src/input_method_core_proxy.cpp",
|
||||
"src/input_method_core_stub.cpp",
|
||||
"src/input_method_panel.cpp",
|
||||
]
|
||||
|
||||
version_script = "inputmethod_ability.versionscript"
|
||||
|
||||
configs = [ ":inputmethod_ability_native_config" ]
|
||||
|
||||
external_deps = [
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#ifndef FRAMEWORKS_INPUTMETHOD_ABILITY_INCLUDE_INPUT_METHOD_ABILITY_INTERFACE_H
|
||||
#define FRAMEWORKS_INPUTMETHOD_ABILITY_INCLUDE_INPUT_METHOD_ABILITY_INTERFACE_H
|
||||
|
||||
#include "input_method_engine_listener.h"
|
||||
#include "keyboard_listener.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace OHOS {
|
||||
namespace MiscServices {
|
||||
class InputMethodAbilityInterface {
|
||||
public:
|
||||
InputMethodAbilityInterface() = default;
|
||||
~InputMethodAbilityInterface()= default;
|
||||
static std::shared_ptr<InputMethodAbilityInterface> GetInstance();
|
||||
int32_t RegisteredProxy();
|
||||
int32_t UnRegisterProxy(uint32_t type);
|
||||
int32_t ChangeProxyStatus(bool isEnable);
|
||||
int32_t InsertText(const std::string &text);
|
||||
int32_t DeleteForward(int32_t length);
|
||||
int32_t DeleteBackward(int32_t length);
|
||||
int32_t MoveCursor(int32_t keyCode);
|
||||
void SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener);
|
||||
void SetKdListener(std::shared_ptr<KeyboardListener> kdListener);
|
||||
private:
|
||||
static std::mutex instanceLock_;
|
||||
static std::shared_ptr<InputMethodAbilityInterface> instance_;
|
||||
};
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
#endif // FRAMEWORKS_INPUTMETHOD_ABILITY_INCLUDE_INPUT_METHOD_ABILITY_INTERFACE_H
|
@ -0,0 +1,26 @@
|
||||
# Copyright (c) 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.
|
||||
|
||||
1.0 {
|
||||
global:
|
||||
*InputDataChannelProxy*;
|
||||
*InputMethodAbility*;
|
||||
*InputMethodAbilityInterface*;
|
||||
*InputMethodAgentProxy*;
|
||||
*InputMethodCoreProxy*;
|
||||
*InputMethodPanel*;
|
||||
*InputMethodSystemAbilityProxy*;
|
||||
*ITypesUtil*;
|
||||
local:
|
||||
*;
|
||||
};
|
@ -436,7 +436,7 @@ public:
|
||||
*
|
||||
* @since 10
|
||||
*/
|
||||
IMF_API void OnInputStop();
|
||||
IMF_API void OnInputStop(UnBindCause cause);
|
||||
|
||||
/**
|
||||
* @brief Insert text.
|
||||
|
@ -60,7 +60,7 @@ ohos_shared_library("inputmethod_service") {
|
||||
public_configs = [ ":inputmethod_services_native_config" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/services/adapter/keyboard:keboard_event_static",
|
||||
"${inputmethod_path}/services/dfx:inputmethod_dfx_static",
|
||||
]
|
||||
|
@ -30,6 +30,7 @@ public:
|
||||
virtual bool IsCurrentIme(uint32_t tokenId, const std::string ¤tBundleName) = 0;
|
||||
virtual bool HasPermission(uint32_t tokenId, const std::string &permission) = 0;
|
||||
virtual bool IsBroker(Security::AccessToken::AccessTokenID tokenId) = 0;
|
||||
virtual bool IsNativeSa(Security::AccessToken::AccessTokenID tokenId) = 0;
|
||||
};
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
|
@ -27,6 +27,7 @@ public:
|
||||
bool IsCurrentIme(uint32_t tokenId, const std::string ¤tBundleName) override;
|
||||
bool HasPermission(uint32_t tokenId, const std::string &permission) override;
|
||||
bool IsBroker(Security::AccessToken::AccessTokenID tokenId) override;
|
||||
bool IsNativeSa(Security::AccessToken::AccessTokenID tokenId) override;
|
||||
|
||||
private:
|
||||
static std::string GetBundleNameByToken(uint32_t tokenId);
|
||||
|
@ -86,6 +86,11 @@ bool IdentityCheckerImpl::IsBroker(AccessTokenID tokenId)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IdentityCheckerImpl::IsNativeSa(AccessTokenID tokenId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string IdentityCheckerImpl::GetBundleNameByToken(uint32_t tokenId)
|
||||
{
|
||||
auto tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId);
|
||||
|
@ -53,12 +53,14 @@ public:
|
||||
virtual int32_t ListInputMethod(InputMethodStatus status, std::vector<Property> &props) = 0;
|
||||
virtual int32_t DisplayOptionalInputMethod() = 0;
|
||||
virtual int32_t SetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent) = 0;
|
||||
virtual int32_t ClearCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent) = 0;
|
||||
virtual int32_t ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps) = 0;
|
||||
virtual int32_t ListInputMethodSubtype(const std::string &name, std::vector<SubProperty> &subProps) = 0;
|
||||
virtual int32_t SwitchInputMethod(const std::string &bundleName, const std::string &name) = 0;
|
||||
virtual int32_t PanelStatusChange(const InputWindowStatus &status, const InputWindowInfo &windowInfo) = 0;
|
||||
virtual int32_t UpdateListenEventFlag(InputClientInfo &clientInfo, EventType eventType) = 0;
|
||||
virtual bool IsCurrentIme() = 0;
|
||||
virtual int32_t ChangeProxyStatus(bool isEnable) = 0; // todo 不一定需要
|
||||
|
||||
// Deprecated because of no permission check, and keep for compatibility
|
||||
virtual int32_t HideCurrentInputDeprecated() = 0;
|
||||
|
@ -75,9 +75,11 @@ public:
|
||||
int32_t SwitchInputMethod(const std::string &bundleName, const std::string &subName) override;
|
||||
int32_t DisplayOptionalInputMethod() override;
|
||||
int32_t SetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent) override;
|
||||
int32_t ClearCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent) override;
|
||||
int32_t PanelStatusChange(const InputWindowStatus &status, const InputWindowInfo &windowInfo) override;
|
||||
int32_t UpdateListenEventFlag(InputClientInfo &clientInfo, EventType eventType) override;
|
||||
bool IsCurrentIme() override;
|
||||
int32_t ChangeProxyStatus(bool isEnable) override; //todo 不一定需要
|
||||
|
||||
// Deprecated because of no permission check, kept for compatibility
|
||||
int32_t HideCurrentInputDeprecated() override;
|
||||
|
@ -59,6 +59,8 @@ private:
|
||||
|
||||
int32_t SetCoreAndAgentOnRemote(MessageParcel &data, MessageParcel &reply);
|
||||
|
||||
int32_t ClearCoreAndAgentOnRemote(MessageParcel &data, MessageParcel &reply);
|
||||
|
||||
int32_t ListInputMethodSubtypeOnRemote(MessageParcel &data, MessageParcel &reply);
|
||||
|
||||
int32_t ListCurrentInputMethodSubtypeOnRemote(MessageParcel &data, MessageParcel &reply);
|
||||
@ -69,6 +71,8 @@ private:
|
||||
|
||||
int32_t IsCurrentImeOnRemote(MessageParcel &data, MessageParcel &reply);
|
||||
|
||||
int32_t ChangeProxyStatusOnRemote(MessageParcel &data, MessageParcel &reply); // todo 不一定需要
|
||||
|
||||
// Deprecated because of no permission check, kept for compatibility
|
||||
int32_t DisplayInputOnRemoteDeprecated(MessageParcel &data, MessageParcel &reply);
|
||||
|
||||
@ -122,6 +126,10 @@ private:
|
||||
&InputMethodSystemAbilityStub::UpdateListenEventFlagOnRemote,
|
||||
[static_cast<uint32_t>(InputMethodInterfaceCode::IS_CURRENT_IME)] =
|
||||
&InputMethodSystemAbilityStub::IsCurrentImeOnRemote,
|
||||
[static_cast<uint32_t>(InputMethodInterfaceCode::CLEAR_CORE_AND_AGENT)] =
|
||||
&InputMethodSystemAbilityStub::ClearCoreAndAgentOnRemote,
|
||||
[static_cast<uint32_t>(InputMethodInterfaceCode::CHANGE_PROXY_STATUS)] =
|
||||
&InputMethodSystemAbilityStub::ChangeProxyStatusOnRemote, // todo 不一定需要
|
||||
};
|
||||
};
|
||||
} // namespace OHOS::MiscServices
|
||||
|
@ -42,6 +42,8 @@ enum class InputMethodInterfaceCode {
|
||||
PANEL_STATUS_CHANGE,
|
||||
UPDATE_LISTEN_EVENT_FLAG,
|
||||
IS_CURRENT_IME,
|
||||
CLEAR_CORE_AND_AGENT,
|
||||
CHANGE_PROXY_STATUS,
|
||||
IMS_CMD_LAST
|
||||
};
|
||||
} // namespace MiscServices
|
||||
|
@ -43,17 +43,13 @@
|
||||
#include "iremote_object.h"
|
||||
#include "message.h"
|
||||
#include "message_handler.h"
|
||||
|
||||
#include "unbind_cause.h"
|
||||
namespace OHOS {
|
||||
namespace MiscServices {
|
||||
struct ResetManager {
|
||||
uint32_t num{ 0 };
|
||||
time_t last{};
|
||||
};
|
||||
enum class UnBindCause : uint32_t {
|
||||
CLIENT_DIED,
|
||||
UNFOCUSED,
|
||||
SELF_CLOSE,
|
||||
struct ImeData {
|
||||
sptr<IInputMethodCore> core{ nullptr };
|
||||
sptr<IInputMethodAgent> agent{ nullptr };
|
||||
sptr<InputDeathRecipient> deathRecipient{ nullptr };
|
||||
};
|
||||
/**@class PerUserSession
|
||||
*
|
||||
@ -62,17 +58,6 @@ enum class UnBindCause : uint32_t {
|
||||
* This class manages the sessions between input clients and input method engines for each unlocked user.
|
||||
*/
|
||||
class PerUserSession {
|
||||
enum : int32_t {
|
||||
CURRENT_IME = 0, // index for current ime
|
||||
SECURITY_IME, // index for security ime
|
||||
MAX_IME // the maximum count of ime started for a user
|
||||
};
|
||||
|
||||
enum ClientAddEvent : int32_t {
|
||||
PREPARE_INPUT = 0,
|
||||
START_LISTENING,
|
||||
};
|
||||
|
||||
public:
|
||||
explicit PerUserSession(int userId);
|
||||
~PerUserSession();
|
||||
@ -81,6 +66,8 @@ public:
|
||||
int32_t OnStartInput(const sptr<IInputClient> &client, bool isShowKeyboard);
|
||||
int32_t OnReleaseInput(const sptr<IInputClient> &client);
|
||||
int32_t OnSetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent);
|
||||
int32_t OnClearCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent);
|
||||
int32_t RegisterProxy(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent);
|
||||
int OnHideCurrentInput();
|
||||
int OnShowCurrentInput();
|
||||
int32_t OnShowInput(sptr<IInputClient> client);
|
||||
@ -96,24 +83,26 @@ public:
|
||||
bool StartInputService(const std::string &imeName, bool isRetry);
|
||||
|
||||
private:
|
||||
struct ResetManager {
|
||||
uint32_t num{ 0 };
|
||||
time_t last{};
|
||||
};
|
||||
enum ClientAddEvent : int32_t {
|
||||
PREPARE_INPUT = 0,
|
||||
START_LISTENING,
|
||||
};
|
||||
enum ImeType : int32_t { IMA = 0, PROXY, END };
|
||||
|
||||
int32_t userId_; // the id of the user to whom the object is linking
|
||||
std::recursive_mutex mtx;
|
||||
std::map<sptr<IRemoteObject>, std::shared_ptr<InputClientInfo>> mapClients_;
|
||||
static const int MAX_RESTART_NUM = 3;
|
||||
static const int IME_RESET_TIME_OUT = 3;
|
||||
static const int MAX_IME_START_TIME = 1000;
|
||||
|
||||
std::mutex imsCoreLock_;
|
||||
sptr<IInputMethodCore> imsCore[MAX_IME]; // the remote handlers of input method service
|
||||
|
||||
std::mutex agentLock_;
|
||||
sptr<IInputMethodAgent> agent_;
|
||||
std::mutex clientLock_;
|
||||
sptr<IInputClient> currentClient_; // the current input client
|
||||
|
||||
sptr<InputDeathRecipient> imsDeathRecipient_ = nullptr;
|
||||
std::recursive_mutex mtx; // mutex to lock the operations among multi work threads
|
||||
std::mutex resetLock;
|
||||
ResetManager manager[MAX_IME];
|
||||
ResetManager manager;
|
||||
|
||||
PerUserSession(const PerUserSession &);
|
||||
PerUserSession &operator=(const PerUserSession &);
|
||||
@ -122,47 +111,43 @@ private:
|
||||
|
||||
void OnClientDied(sptr<IInputClient> remote);
|
||||
void OnImsDied(const sptr<IInputMethodCore> &remote);
|
||||
void OnProxyDied(const sptr<IInputMethodCore> &remote);
|
||||
|
||||
int AddClientInfo(sptr<IRemoteObject> inputClient, const InputClientInfo &clientInfo, ClientAddEvent event);
|
||||
std::shared_ptr<InputClientInfo> GetClientInfo(sptr<IRemoteObject> inputClient);
|
||||
void UpdateClientInfo(const sptr<IRemoteObject> &client,
|
||||
const std::unordered_map<UpdateFlag, std::variant<bool, uint32_t, BindStatus>> &updateInfos);
|
||||
void RemoveClientInfo(const sptr<IRemoteObject> &client, bool isClientDied);
|
||||
|
||||
int32_t ClearClient(const sptr<IInputClient> &client, UnBindCause cause);
|
||||
int32_t UnBindClient(const sptr<IInputClient> &client, UnBindCause cause);
|
||||
void UnBindImcWithIma(const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, UnBindCause cause);
|
||||
int32_t StopImaInput(const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel);
|
||||
void UnBindImcWithProxy(const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, UnBindCause cause);
|
||||
int32_t RemoveClient(const sptr<IRemoteObject> &client);
|
||||
void ClearIme(const sptr<IInputMethodCore> &core, ImeType type);
|
||||
|
||||
int32_t UnBindClient(const sptr<IInputClient> &client, UnBindCause cause);
|
||||
void UnBindClient(
|
||||
const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, UnBindCause cause, ImeType type);
|
||||
|
||||
int AddClient(sptr<IRemoteObject> inputClient, const InputClientInfo &clientInfo, ClientAddEvent event);
|
||||
int32_t BindClient(const sptr<IInputClient> &client, bool isShowKeyboard);
|
||||
int32_t BindImcWitchIma(
|
||||
const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, bool isShowKeyboard);
|
||||
int32_t SendAgentToImc(const sptr<IInputClient> &client);
|
||||
int32_t StartImaInput(
|
||||
const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, bool isShowKeyboard);
|
||||
int32_t BindImcWitchProxy();
|
||||
int32_t BindClient(
|
||||
const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, bool isShowKeyboard, ImeType type);
|
||||
|
||||
int32_t HideKeyboard(const sptr<IInputClient> &inputClient);
|
||||
int32_t ShowKeyboard(const sptr<IInputClient> &inputClient);
|
||||
|
||||
int32_t InitInputControlChannel();
|
||||
bool IsReadyToStartIme();
|
||||
bool IsRestartIme(uint32_t index);
|
||||
void ClearImeData(uint32_t index);
|
||||
bool IsRestartIme();
|
||||
|
||||
void SetCurrentClient(sptr<IInputClient> client);
|
||||
sptr<IInputClient> GetCurrentClient();
|
||||
void SetImsCore(int32_t index, sptr<IInputMethodCore> core);
|
||||
sptr<IInputMethodCore> GetImsCore(int32_t index);
|
||||
void SetAgent(sptr<IInputMethodAgent> agent);
|
||||
sptr<IInputMethodAgent> GetAgent();
|
||||
bool IsCurrentClient(int32_t pid, int32_t uid);
|
||||
|
||||
static inline bool IsValid(int32_t index)
|
||||
{
|
||||
return index >= CURRENT_IME && index <= SECURITY_IME;
|
||||
}
|
||||
int32_t StorageImeData(ImeType type, sptr<IInputMethodCore> core, sptr<IInputMethodAgent> agent);
|
||||
std::shared_ptr<ImeData> GetImeData(ImeType type);
|
||||
void ClearImeData(ImeType type);
|
||||
|
||||
BlockData<bool> isImeStarted_{ MAX_IME_START_TIME, false };
|
||||
std::mutex imeDataLock_;
|
||||
std::unordered_map<ImeType, std::shared_ptr<ImeData>> imeData_;
|
||||
};
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
|
@ -309,6 +309,7 @@ int32_t InputMethodSystemAbility::SetCoreAndAgent(
|
||||
const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent)
|
||||
{
|
||||
IMSA_HILOGD("InputMethodSystemAbility run in");
|
||||
// todo 此处权限校验
|
||||
if (!IsCurrentIme()) {
|
||||
return ErrorCode::ERROR_NOT_CURRENT_IME;
|
||||
}
|
||||
@ -316,6 +317,7 @@ int32_t InputMethodSystemAbility::SetCoreAndAgent(
|
||||
IMSA_HILOGE("InputMethodSystemAbility::core or agent is nullptr");
|
||||
return ErrorCode::ERROR_NULL_POINTER;
|
||||
}
|
||||
// todo 可以在此处根据是否当前ime或者native,区分ima和proxy
|
||||
return userSession_->OnSetCoreAndAgent(core, agent);
|
||||
}
|
||||
|
||||
@ -798,5 +800,18 @@ void InputMethodSystemAbility::InitSystemLanguageMonitor()
|
||||
SystemLanguageObserver::GetInstance().Watch(
|
||||
[this]() { ImeInfoInquirer::GetInstance().UpdateCurrentImeInfo(userId_); });
|
||||
}
|
||||
|
||||
int32_t InputMethodSystemAbility::ClearCoreAndAgent(
|
||||
const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent)
|
||||
{
|
||||
// todo 权限校验
|
||||
userSession_->OnClearCoreAndAgent(core, agent);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t InputMethodSystemAbility::ChangeProxyStatus(bool isEnable)
|
||||
{
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
|
@ -271,5 +271,15 @@ int32_t InputMethodSystemAbilityStub::IsCurrentImeOnRemote(MessageParcel &data,
|
||||
bool ret = IsCurrentIme();
|
||||
return ITypesUtil::Marshal(reply, ErrorCode::NO_ERROR, ret) ? ErrorCode::NO_ERROR : ErrorCode::ERROR_EX_PARCELABLE;
|
||||
}
|
||||
|
||||
int32_t InputMethodSystemAbilityStub::ClearCoreAndAgentOnRemote(MessageParcel &data, MessageParcel &reply)
|
||||
{
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t InputMethodSystemAbilityStub::ChangeProxyStatusOnRemote(MessageParcel &data, MessageParcel &reply)
|
||||
{
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
} // namespace MiscServices
|
||||
} // namespace OHOS
|
||||
|
@ -41,16 +41,15 @@ using namespace MessageID;
|
||||
constexpr uint32_t IME_RESTART_TIMES = 5;
|
||||
constexpr uint32_t IME_RESTART_INTERVAL = 300;
|
||||
constexpr int64_t INVALID_PID = -1;
|
||||
PerUserSession::PerUserSession(int32_t userId) : userId_(userId), imsDeathRecipient_(new InputDeathRecipient())
|
||||
PerUserSession::PerUserSession(int32_t userId) : userId_(userId)
|
||||
{
|
||||
}
|
||||
|
||||
PerUserSession::~PerUserSession()
|
||||
{
|
||||
imsDeathRecipient_ = nullptr;
|
||||
}
|
||||
|
||||
int PerUserSession::AddClient(sptr<IRemoteObject> inputClient, const InputClientInfo &clientInfo, ClientAddEvent event)
|
||||
int PerUserSession::AddClientInfo(sptr<IRemoteObject> inputClient, const InputClientInfo &clientInfo, ClientAddEvent event)
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession, run in");
|
||||
auto cacheInfo = GetClientInfo(inputClient);
|
||||
@ -81,13 +80,18 @@ int PerUserSession::AddClient(sptr<IRemoteObject> inputClient, const InputClient
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::RemoveClient(const sptr<IRemoteObject> &client)
|
||||
void PerUserSession::RemoveClientInfo(const sptr<IRemoteObject> &client, bool isClientDied)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
auto clientInfo = GetClientInfo(client);
|
||||
if (clientInfo == nullptr) {
|
||||
IMSA_HILOGD("client already removed");
|
||||
return ErrorCode::NO_ERROR;
|
||||
return;
|
||||
}
|
||||
// if client is subscriber and the release is not because of the client died, do not remove
|
||||
if (clientInfo->eventFlag != EventStatusManager::NO_EVENT_ON && !isClientDied) {
|
||||
IMSA_HILOGD("is subscriber, do not remove");
|
||||
return;
|
||||
}
|
||||
if (clientInfo->deathRecipient != nullptr) {
|
||||
IMSA_HILOGI("deathRecipient remove");
|
||||
@ -96,48 +100,6 @@ int32_t PerUserSession::RemoveClient(const sptr<IRemoteObject> &client)
|
||||
}
|
||||
mapClients_.erase(client);
|
||||
IMSA_HILOGD("client[%{public}d] is removed successfully", clientInfo->pid);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::StartImaInput(
|
||||
const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, bool isShowKeyboard)
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession, run in");
|
||||
if (client == nullptr) {
|
||||
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
|
||||
}
|
||||
auto core = GetImsCore(CURRENT_IME);
|
||||
if (core == nullptr) {
|
||||
IMSA_HILOGE("Aborted! imsCore[%{public}d] is nullptr", CURRENT_IME);
|
||||
return ErrorCode::ERROR_IME_NOT_STARTED;
|
||||
}
|
||||
int32_t ret = core->StartInput(channel, isShowKeyboard);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
IMSA_HILOGE("failed to show keyboard, ret: %{public}d", ret);
|
||||
return ErrorCode::ERROR_KBD_SHOW_FAILED;
|
||||
}
|
||||
UpdateClientInfo(client->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, isShowKeyboard } });
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::StopImaInput(const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel)
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession, run in");
|
||||
if (client == nullptr) {
|
||||
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
|
||||
}
|
||||
auto core = GetImsCore(CURRENT_IME);
|
||||
if (core == nullptr) {
|
||||
IMSA_HILOGE("Aborted! imsCore[%{public}d] is nullptr", CURRENT_IME);
|
||||
return ErrorCode::ERROR_IME_NOT_STARTED;
|
||||
}
|
||||
int32_t ret = core->StopInput(channel);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
IMSA_HILOGE("failed to show keyboard, ret: %{public}d", ret);
|
||||
return ErrorCode::ERROR_KBD_SHOW_FAILED;
|
||||
}
|
||||
UpdateClientInfo(client->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, false } });
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
void PerUserSession::UpdateClientInfo(const sptr<IRemoteObject> &client,
|
||||
@ -172,28 +134,19 @@ void PerUserSession::UpdateClientInfo(const sptr<IRemoteObject> &client,
|
||||
}
|
||||
}
|
||||
|
||||
/** hide keyboard
|
||||
* @param inputClient the remote object handler of the input client.
|
||||
* @return ErrorCode::NO_ERROR no error
|
||||
* @return ErrorCode::ERROR_IME_NOT_STARTED ime not started
|
||||
* @return ErrorCode::ERROR_KBD_IS_NOT_SHOWING keyboard has not been showing
|
||||
* @return ErrorCode::ERROR_CLIENT_NOT_FOUND the input client is not found
|
||||
* @return ErrorCode::ERROR_KBD_HIDE_FAILED failed to hide keyboard
|
||||
* @return other errors returned by binder driver
|
||||
*/
|
||||
int32_t PerUserSession::HideKeyboard(const sptr<IInputClient> &inputClient)
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession::HideKeyboard");
|
||||
sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
|
||||
if (core == nullptr) {
|
||||
IMSA_HILOGE("imsCore is nullptr");
|
||||
auto data = GetImeData(ImeType::IMA);
|
||||
if (data == nullptr || data->core == nullptr) {
|
||||
IMSA_HILOGE("ime: %{public}d is not exist or core is nullptr", ImeType::IMA);
|
||||
return ErrorCode::ERROR_IME_NOT_STARTED;
|
||||
}
|
||||
if (inputClient != nullptr) {
|
||||
bool isShowKeyboard = false;
|
||||
UpdateClientInfo(inputClient->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, isShowKeyboard } });
|
||||
}
|
||||
auto ret = core->HideKeyboard();
|
||||
auto ret = data->core->HideKeyboard();
|
||||
IMSA_HILOGD("HideKeyboard end, ret = %{public}d", ret);
|
||||
return ret;
|
||||
}
|
||||
@ -201,12 +154,12 @@ int32_t PerUserSession::HideKeyboard(const sptr<IInputClient> &inputClient)
|
||||
int32_t PerUserSession::ShowKeyboard(const sptr<IInputClient> &inputClient)
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession::HideKeyboard");
|
||||
sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
|
||||
if (core == nullptr) {
|
||||
IMSA_HILOGE("imsCore is nullptr");
|
||||
auto data = GetImeData(ImeType::IMA);
|
||||
if (data == nullptr || data->core == nullptr) {
|
||||
IMSA_HILOGE("ime: %{public}d is not exist or core is nullptr", ImeType::IMA);
|
||||
return ErrorCode::ERROR_IME_NOT_STARTED;
|
||||
}
|
||||
auto ret = core->ShowKeyboard();
|
||||
auto ret = data->core->ShowKeyboard();
|
||||
IMSA_HILOGD("HideKeyboard end, ret = %{public}d", ret);
|
||||
bool isShowKeyboard = true;
|
||||
UpdateClientInfo(inputClient->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, isShowKeyboard } });
|
||||
@ -232,11 +185,8 @@ void PerUserSession::OnClientDied(sptr<IInputClient> remote)
|
||||
*/
|
||||
void PerUserSession::OnImsDied(const sptr<IInputMethodCore> &remote)
|
||||
{
|
||||
if (remote == nullptr) {
|
||||
return;
|
||||
}
|
||||
ClearImeData(CURRENT_IME);
|
||||
if (!IsRestartIme(CURRENT_IME)) {
|
||||
ClearIme(remote, ImeType::IMA);
|
||||
if (!IsRestartIme()) {
|
||||
IMSA_HILOGI("ime deaths over max num");
|
||||
return;
|
||||
}
|
||||
@ -247,14 +197,34 @@ void PerUserSession::OnImsDied(const sptr<IInputMethodCore> &remote)
|
||||
StartInputService(ImeInfoInquirer::GetInstance().GetStartedIme(userId_), true);
|
||||
}
|
||||
|
||||
void PerUserSession::OnProxyDied(const sptr<IInputMethodCore> &remote)
|
||||
{
|
||||
ClearIme(remote, ImeType::PROXY);
|
||||
}
|
||||
|
||||
void PerUserSession::ClearIme(const sptr<IInputMethodCore> &core, ImeType type)
|
||||
{
|
||||
if (core == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto data = GetImeData(type);
|
||||
if (data == nullptr || data->core == nullptr || data->core->AsObject() != core->AsObject()) {
|
||||
return;
|
||||
}
|
||||
ClearImeData(type);
|
||||
sptr<IInputClient> client = GetCurrentClient();
|
||||
if (client == nullptr) {
|
||||
IMSA_HILOGE("current client is nullptr");
|
||||
return;
|
||||
}
|
||||
UnBindClient(client, UnBindCause::IME_DIED);
|
||||
}
|
||||
|
||||
void PerUserSession::UpdateCurrentUserId(int32_t userId)
|
||||
{
|
||||
userId_ = userId;
|
||||
}
|
||||
|
||||
/** Hide current keyboard
|
||||
* @param flag the flag to hide keyboard.
|
||||
*/
|
||||
int PerUserSession::OnHideCurrentInput()
|
||||
{
|
||||
IMSA_HILOGI("PerUserSession::OnHideCurrentInput");
|
||||
@ -320,30 +290,10 @@ std::shared_ptr<InputClientInfo> PerUserSession::GetClientInfo(sptr<IRemoteObjec
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/** Prepare input. Called by an input client.
|
||||
\n Run in work thread of this user
|
||||
\param the parameters from remote client
|
||||
\return ErrorCode
|
||||
*/
|
||||
int32_t PerUserSession::OnPrepareInput(const InputClientInfo &clientInfo)
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession::OnPrepareInput Start\n");
|
||||
return AddClient(clientInfo.client->AsObject(), clientInfo, PREPARE_INPUT);
|
||||
}
|
||||
|
||||
int32_t PerUserSession::SendAgentToImc(const sptr<IInputClient> &client)
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession::SendAgentToImc");
|
||||
if (client == nullptr) {
|
||||
IMSA_HILOGE("client is nullptr");
|
||||
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
|
||||
}
|
||||
auto agent = GetAgent();
|
||||
if (agent == nullptr) {
|
||||
IMSA_HILOGI("agent is nullptr");
|
||||
return ErrorCode::ERROR_NULL_POINTER;
|
||||
}
|
||||
return client->OnInputReady(agent);
|
||||
return AddClientInfo(clientInfo.client->AsObject(), clientInfo, PREPARE_INPUT);
|
||||
}
|
||||
|
||||
/** Release input. Called by an input client.Run in work thread of this user
|
||||
@ -353,7 +303,7 @@ int32_t PerUserSession::SendAgentToImc(const sptr<IInputClient> &client)
|
||||
int32_t PerUserSession::OnReleaseInput(const sptr<IInputClient> &client)
|
||||
{
|
||||
IMSA_HILOGI("PerUserSession::Start");
|
||||
return ClearClient(client, UnBindCause::SELF_CLOSE);
|
||||
return ClearClient(client, UnBindCause::CLIENT_CLOSE_SELF);
|
||||
}
|
||||
|
||||
int32_t PerUserSession::ClearClient(const sptr<IInputClient> &client, UnBindCause cause)
|
||||
@ -361,23 +311,13 @@ int32_t PerUserSession::ClearClient(const sptr<IInputClient> &client, UnBindCaus
|
||||
if (client == nullptr) {
|
||||
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
|
||||
}
|
||||
auto clientObject = client->AsObject();
|
||||
auto clientInfo = GetClientInfo(clientObject);
|
||||
if (clientInfo == nullptr) {
|
||||
IMSA_HILOGD("client already removed");
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
// if client is current client, unbind
|
||||
// if client is current client, unbind firstly
|
||||
auto currentClient = GetCurrentClient();
|
||||
if (currentClient != nullptr && client->AsObject() == currentClient->AsObject()) {
|
||||
UnBindClient(client, cause);
|
||||
SetCurrentClient(nullptr); //只有当前客户端要被移除,才能置位当前客户端为空,此处位置最合适
|
||||
}
|
||||
// if client is subscriber and the release is not because of the client died, do not remove
|
||||
if (clientInfo->eventFlag != EventStatusManager::NO_EVENT_ON && cause != UnBindCause::CLIENT_DIED) {
|
||||
IMSA_HILOGD("is subscriber, do not remove");
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
RemoveClient(clientObject);
|
||||
RemoveClientInfo(client->AsObject(), cause == UnBindCause::CLIENT_DIED);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
@ -398,72 +338,88 @@ int32_t PerUserSession::BindClient(const sptr<IInputClient> &client, bool isShow
|
||||
IMSA_HILOGE("client not found");
|
||||
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
|
||||
}
|
||||
bool isProxyEnable = false;
|
||||
auto ret = isProxyEnable ? BindImcWitchProxy() : BindImcWitchIma(client, clientInfo->channel, isShowKeyboard);
|
||||
ImeType type = ImeType::IMA;
|
||||
auto data = GetImeData(ImeType::PROXY);
|
||||
if (data != nullptr && data->core != nullptr && data->core->IsEnable()) {
|
||||
type = ImeType::PROXY;
|
||||
}
|
||||
return BindClient(client, clientInfo->channel, isShowKeyboard, type);
|
||||
}
|
||||
|
||||
int32_t PerUserSession::BindClient(
|
||||
const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, bool isShowKeyboard, ImeType type)
|
||||
{
|
||||
if (client == nullptr || channel == nullptr) {
|
||||
IMSA_HILOGE("client or channel is nullptr");
|
||||
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
|
||||
}
|
||||
auto data = GetImeData(type);
|
||||
if (data == nullptr && type == ImeType::IMA) {
|
||||
IMSA_HILOGI("current ime is empty, try to restart it");
|
||||
if (!StartInputService(ImeInfoInquirer::GetInstance().GetStartedIme(userId_), true)) {
|
||||
IMSA_HILOGE("failed to restart ime");
|
||||
return ErrorCode::ERROR_IME_START_FAILED;
|
||||
}
|
||||
data = GetImeData(type);
|
||||
}
|
||||
if (data->agent == nullptr || data->core == nullptr) {
|
||||
return ErrorCode::ERROR_IME_START_FAILED;
|
||||
}
|
||||
auto ret = client->OnInputReady(data->agent);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
IMSA_HILOGE("bind Client failed");
|
||||
return ret;
|
||||
}
|
||||
ret = data->core->StartInput(channel, isShowKeyboard);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
IMSA_HILOGE("failed to show keyboard, ret: %{public}d", ret);
|
||||
return ErrorCode::ERROR_KBD_SHOW_FAILED;
|
||||
}
|
||||
BindStatus status = type == ImeType::IMA ? BindStatus::BIND_WITH_IMA : BindStatus::BIND_WITH_PROXY;
|
||||
UpdateClientInfo(
|
||||
client->AsObject(), { { UpdateFlag::BINDSTATUS, status }, { UpdateFlag::ISSHOWKEYBOARD, isShowKeyboard } });
|
||||
SetCurrentClient(client);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::UnBindClient(const sptr<IInputClient> &client, UnBindCause cause)
|
||||
{
|
||||
if (client == nullptr) {
|
||||
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
|
||||
}
|
||||
auto clientInfo = GetClientInfo(client->AsObject());
|
||||
if (clientInfo == nullptr) {
|
||||
IMSA_HILOGD("client already removed");
|
||||
return ErrorCode::NO_ERROR;
|
||||
IMSA_HILOGD("clientInfo not find");
|
||||
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
|
||||
}
|
||||
if (clientInfo->bindStatus == BindStatus::BIND_WITH_IMA) {
|
||||
UnBindImcWithIma(client, clientInfo->channel, cause);
|
||||
UnBindClient(client, clientInfo->channel, cause, ImeType::IMA);
|
||||
} else if (clientInfo->bindStatus == BindStatus::BIND_WITH_PROXY) {
|
||||
UnBindImcWithProxy(client, clientInfo->channel, cause);
|
||||
UnBindClient(client, clientInfo->channel, cause, ImeType::PROXY);
|
||||
}
|
||||
SetCurrentClient(nullptr);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::BindImcWitchIma(
|
||||
const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, bool isShowKeyboard)
|
||||
void PerUserSession::UnBindClient(
|
||||
const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, UnBindCause cause, ImeType type)
|
||||
{
|
||||
if (GetImsCore(CURRENT_IME) == nullptr) {
|
||||
IMSA_HILOGI("current ime is empty, try to restart it");
|
||||
if (!StartInputService(ImeInfoInquirer::GetInstance().GetStartedIme(userId_), true)) {
|
||||
IMSA_HILOGE("failed to restart ime");
|
||||
return ErrorCode::ERROR_IME_START_FAILED;
|
||||
}
|
||||
IMSA_HILOGD("PerUserSession, run in");
|
||||
if (client == nullptr) {
|
||||
return;
|
||||
}
|
||||
int32_t ret = SendAgentToImc(client);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
return ret;
|
||||
}
|
||||
ret = StartImaInput(client, channel, isShowKeyboard);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
return ret;
|
||||
}
|
||||
UpdateClientInfo(client->AsObject(), { { UpdateFlag::BINDSTATUS, BindStatus::BIND_WITH_IMA } });
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::BindImcWitchProxy()
|
||||
{
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
void PerUserSession::UnBindImcWithIma(const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, UnBindCause cause)
|
||||
{
|
||||
if (cause == UnBindCause::UNFOCUSED) {
|
||||
int32_t ret = client->OnInputStop();
|
||||
if (cause != UnBindCause::CLIENT_DIED) {
|
||||
int32_t ret = client->OnInputStop(cause);
|
||||
IMSA_HILOGI("OnInputStop ret: %{public}d", ret);
|
||||
}
|
||||
auto ret = StopImaInput(client, channel);
|
||||
IMSA_HILOGI("stop ima input ret: %{public}d", ret);
|
||||
UpdateClientInfo(client->AsObject(), { { UpdateFlag::BINDSTATUS, BindStatus::NO_BIND } });
|
||||
}
|
||||
|
||||
void PerUserSession::UnBindImcWithProxy(const sptr<IInputClient> &client, const sptr<IInputDataChannel> &channel, UnBindCause cause)
|
||||
{
|
||||
auto data = GetImeData(type);
|
||||
if (data != nullptr && data->core != nullptr && cause != UnBindCause::IME_DIED) {
|
||||
int32_t ret = data->core->StopInput(channel);
|
||||
IMSA_HILOGE("stop ime input, ret: %{public}d", ret);
|
||||
}
|
||||
/* CLIENT_DIED, CLIENT_UNFOCUSED, CLIENT_CLOSE_SELF:the client will be removed, has no point in updating
|
||||
IME_DIED: The update will causes the client can't be rebind after ime reboot */
|
||||
if (cause == UnBindCause::IME_SWITCH) {
|
||||
UpdateClientInfo(client->AsObject(), { { UpdateFlag::BINDSTATUS, BindStatus::NO_BIND } });
|
||||
}
|
||||
}
|
||||
|
||||
int32_t PerUserSession::OnSetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent)
|
||||
@ -473,82 +429,93 @@ int32_t PerUserSession::OnSetCoreAndAgent(const sptr<IInputMethodCore> &core, co
|
||||
IMSA_HILOGE("PerUserSession::SetCoreAndAgent core or agent nullptr");
|
||||
return ErrorCode::ERROR_EX_NULL_POINTER;
|
||||
}
|
||||
if (imsDeathRecipient_ == nullptr || core->AsObject() == nullptr) {
|
||||
IMSA_HILOGE("imsDeathRecipient_ or core as object is nullptr");
|
||||
return ErrorCode::ERROR_NULL_POINTER;
|
||||
auto ret = StorageImeData(ImeType::IMA, core, agent);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
return ret;
|
||||
}
|
||||
imsDeathRecipient_->SetDeathRecipient([this, core](const wptr<IRemoteObject> &) { this->OnImsDied(core); });
|
||||
if (!core->AsObject()->AddDeathRecipient(imsDeathRecipient_)) {
|
||||
IMSA_HILOGE("failed to add death recipient");
|
||||
return ErrorCode::ERROR_ADD_DEATH_RECIPIENT_FAILED;
|
||||
}
|
||||
SetImsCore(CURRENT_IME, core);
|
||||
SetAgent(agent);
|
||||
|
||||
int ret = InitInputControlChannel();
|
||||
ret = InitInputControlChannel();
|
||||
IMSA_HILOGI("init input control channel ret: %{public}d", ret);
|
||||
auto client = GetCurrentClient();
|
||||
if (client != nullptr) {
|
||||
auto clientInfo = GetClientInfo(client->AsObject());
|
||||
if (clientInfo != nullptr) {
|
||||
ret = BindClient(clientInfo->client, clientInfo->isShowKeyboard);
|
||||
if (clientInfo != nullptr && clientInfo->bindStatus != BindStatus::BIND_WITH_PROXY) {
|
||||
ret = BindClient(clientInfo->client, clientInfo->channel, clientInfo->isShowKeyboard, ImeType::IMA);
|
||||
IMSA_HILOGI("client bind ret: %{public}d", ret);
|
||||
}
|
||||
}
|
||||
bool isStarted = GetImsCore(CURRENT_IME) != nullptr && GetAgent() != nullptr;
|
||||
bool isStarted = false;
|
||||
auto imeData = GetImeData(ImeType::IMA);
|
||||
if (imeData != nullptr && imeData->core != nullptr && imeData->agent != nullptr) {
|
||||
isStarted = true;
|
||||
}
|
||||
isImeStarted_.SetValue(isStarted);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::RegisterProxy(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent)
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession::Start");
|
||||
if (core == nullptr || agent == nullptr) {
|
||||
IMSA_HILOGE("PerUserSession::core or agent nullptr");
|
||||
return ErrorCode::ERROR_EX_NULL_POINTER;
|
||||
}
|
||||
auto ret = StorageImeData(ImeType::PROXY, core, agent);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
return ret;
|
||||
}
|
||||
auto client = GetCurrentClient();
|
||||
if (client != nullptr) {
|
||||
auto clientInfo = GetClientInfo(client->AsObject());
|
||||
if (clientInfo != nullptr && clientInfo->bindStatus == BindStatus::BIND_WITH_IMA) {
|
||||
UnBindClient(clientInfo->client, clientInfo->channel, UnBindCause::IME_SWITCH, ImeType::IMA);
|
||||
ret = BindClient(clientInfo->client, clientInfo->channel, clientInfo->isShowKeyboard, ImeType::PROXY);
|
||||
IMSA_HILOGI("client bind ret: %{public}d", ret);
|
||||
}
|
||||
}
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::OnClearCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent)
|
||||
{
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t PerUserSession::InitInputControlChannel()
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession::InitInputControlChannel");
|
||||
sptr<IInputControlChannel> inputControlChannel = new InputControlChannelStub(userId_);
|
||||
auto core = GetImsCore(CURRENT_IME);
|
||||
if (core == nullptr) {
|
||||
IMSA_HILOGE("PerUserSession::InitInputControlChannel core is nullptr");
|
||||
auto data = GetImeData(ImeType::IMA);
|
||||
if (data == nullptr || data->core == nullptr) {
|
||||
IMSA_HILOGE("ime: %{public}d is not exist or core is nullptr", ImeType::IMA);
|
||||
return ErrorCode::ERROR_IME_NOT_STARTED;
|
||||
}
|
||||
return core->InitInputControlChannel(
|
||||
return data->core->InitInputControlChannel(
|
||||
inputControlChannel, ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->imeId);
|
||||
}
|
||||
|
||||
void PerUserSession::StopInputService(std::string imeId)
|
||||
{
|
||||
IMSA_HILOGI("PerUserSession::StopInputService");
|
||||
sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
|
||||
if (core == nullptr) {
|
||||
IMSA_HILOGE("imsCore[0] is nullptr");
|
||||
auto data = GetImeData(ImeType::IMA);
|
||||
if (data == nullptr || data->core == nullptr) {
|
||||
IMSA_HILOGE("ime: %{public}d is not exist or core is nullptr", ImeType::IMA);
|
||||
return;
|
||||
}
|
||||
IMSA_HILOGI("Remove death recipient");
|
||||
core->AsObject()->RemoveDeathRecipient(imsDeathRecipient_);
|
||||
core->StopInputService(imeId);
|
||||
SetImsCore(CURRENT_IME, nullptr);
|
||||
SetAgent(nullptr);
|
||||
data->core->StopInputService(imeId);
|
||||
ClearImeData(ImeType::IMA);
|
||||
}
|
||||
|
||||
bool PerUserSession::IsRestartIme(uint32_t index)
|
||||
bool PerUserSession::IsRestartIme()
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession::IsRestartIme");
|
||||
std::lock_guard<std::mutex> lock(resetLock);
|
||||
auto now = time(nullptr);
|
||||
if (difftime(now, manager[index].last) > IME_RESET_TIME_OUT) {
|
||||
manager[index] = { 0, now };
|
||||
if (difftime(now, manager.last) > IME_RESET_TIME_OUT) {
|
||||
manager = { 0, now };
|
||||
}
|
||||
++manager[index].num;
|
||||
return manager[index].num <= MAX_RESTART_NUM;
|
||||
}
|
||||
|
||||
void PerUserSession::ClearImeData(uint32_t index)
|
||||
{
|
||||
IMSA_HILOGI("Clear ime...index = %{public}d", index);
|
||||
auto core = GetImsCore(index);
|
||||
if (core != nullptr) {
|
||||
core->AsObject()->RemoveDeathRecipient(imsDeathRecipient_);
|
||||
SetImsCore(index, nullptr);
|
||||
}
|
||||
SetAgent(nullptr);
|
||||
++manager.num;
|
||||
return manager.num <= MAX_RESTART_NUM;
|
||||
}
|
||||
|
||||
void PerUserSession::SetCurrentClient(sptr<IInputClient> client)
|
||||
@ -568,12 +535,12 @@ int32_t PerUserSession::OnSwitchIme(const Property &property, const SubProperty
|
||||
{
|
||||
IMSA_HILOGD("PerUserSession::OnSwitchIme");
|
||||
if (isSubtypeSwitch) {
|
||||
sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
|
||||
if (core == nullptr) {
|
||||
IMSA_HILOGE("imsCore is nullptr");
|
||||
auto data = GetImeData(ImeType::IMA);
|
||||
if (data == nullptr || data->core == nullptr) {
|
||||
IMSA_HILOGE("core is nullptr");
|
||||
return ErrorCode::ERROR_IME_NOT_STARTED;
|
||||
}
|
||||
int32_t ret = core->SetSubtype(subProperty);
|
||||
int32_t ret = data->core->SetSubtype(subProperty);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
IMSA_HILOGE("PerUserSession::SetSubtype failed, ret %{public}d", ret);
|
||||
return ret;
|
||||
@ -596,34 +563,55 @@ int32_t PerUserSession::OnSwitchIme(const Property &property, const SubProperty
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
sptr<IInputMethodCore> PerUserSession::GetImsCore(int32_t index)
|
||||
int32_t PerUserSession::StorageImeData(ImeType type, sptr<IInputMethodCore> core, sptr<IInputMethodAgent> agent)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(imsCoreLock_);
|
||||
if (!IsValid(index)) {
|
||||
sptr<InputDeathRecipient> deathRecipient = new (std::nothrow) InputDeathRecipient();
|
||||
if (deathRecipient == nullptr) {
|
||||
IMSA_HILOGE("failed to new deathRecipient");
|
||||
return ErrorCode::ERROR_EX_NULL_POINTER;
|
||||
}
|
||||
deathRecipient->SetDeathRecipient([this, core, type](const wptr<IRemoteObject> &) {
|
||||
type == ImeType::IMA ? this->OnImsDied(core) : this->OnProxyDied(core);
|
||||
});
|
||||
auto coreObject = core->AsObject();
|
||||
if (coreObject == nullptr || !coreObject->AddDeathRecipient(deathRecipient)) {
|
||||
IMSA_HILOGE("failed to add death recipient");
|
||||
return ErrorCode::ERROR_ADD_DEATH_RECIPIENT_FAILED;
|
||||
}
|
||||
auto data = std::make_shared<ImeData>();
|
||||
data->deathRecipient = deathRecipient;
|
||||
data->agent = agent;
|
||||
data->core = core;
|
||||
std::lock_guard<std::mutex> lock(imeDataLock_);
|
||||
imeData_.insert_or_assign(type, data);
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
||||
std::shared_ptr<ImeData> PerUserSession::GetImeData(ImeType type)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(imeDataLock_);
|
||||
auto it = imeData_.find(type);
|
||||
if (it == imeData_.end()) {
|
||||
IMSA_HILOGD("imeData not found");
|
||||
return nullptr;
|
||||
}
|
||||
return imsCore[index];
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void PerUserSession::SetImsCore(int32_t index, sptr<IInputMethodCore> core)
|
||||
void PerUserSession::ClearImeData(ImeType type)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(imsCoreLock_);
|
||||
if (!IsValid(index)) {
|
||||
std::lock_guard<std::mutex> lock(imeDataLock_);
|
||||
auto it = imeData_.find(type);
|
||||
if (it == imeData_.end()) {
|
||||
IMSA_HILOGD("imeData not found");
|
||||
return;
|
||||
}
|
||||
imsCore[index] = core;
|
||||
}
|
||||
|
||||
sptr<IInputMethodAgent> PerUserSession::GetAgent()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(agentLock_);
|
||||
return agent_;
|
||||
}
|
||||
|
||||
void PerUserSession::SetAgent(sptr<IInputMethodAgent> agent)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(agentLock_);
|
||||
agent_ = agent;
|
||||
auto data = it->second;
|
||||
if (data->core != nullptr && data->core->AsObject() != nullptr) {
|
||||
data->core->AsObject()->RemoveDeathRecipient(data->deathRecipient);
|
||||
}
|
||||
data->deathRecipient = nullptr;
|
||||
imeData_.erase(type);
|
||||
}
|
||||
|
||||
void PerUserSession::OnFocused(int32_t pid, int32_t uid)
|
||||
@ -638,7 +626,7 @@ void PerUserSession::OnFocused(int32_t pid, int32_t uid)
|
||||
return;
|
||||
}
|
||||
IMSA_HILOGI("focus shifts to pid: %{public}d, start clear unfocused client info", pid);
|
||||
ClearClient(client, UnBindCause::UNFOCUSED);
|
||||
ClearClient(client, UnBindCause::CLIENT_UNFOCUSED);
|
||||
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNFOCUSED);
|
||||
}
|
||||
|
||||
@ -652,7 +640,7 @@ void PerUserSession::OnUnfocused(int32_t pid, int32_t uid)
|
||||
for (const auto &mapClient : mapClients_) {
|
||||
if (mapClient.second->pid == pid) {
|
||||
IMSA_HILOGI("clear unfocused client info: %{public}d", pid);
|
||||
ClearClient(mapClient.second->client, UnBindCause::UNFOCUSED);
|
||||
ClearClient(mapClient.second->client, UnBindCause::CLIENT_UNFOCUSED);
|
||||
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNFOCUSED);
|
||||
break;
|
||||
}
|
||||
@ -750,9 +738,9 @@ int32_t PerUserSession::OnPanelStatusChange(const InputWindowStatus &status, con
|
||||
int32_t PerUserSession::OnUpdateListenEventFlag(const InputClientInfo &clientInfo)
|
||||
{
|
||||
auto remoteClient = clientInfo.client->AsObject();
|
||||
auto ret = AddClient(remoteClient, clientInfo, START_LISTENING);
|
||||
auto ret = AddClientInfo(remoteClient, clientInfo, START_LISTENING);
|
||||
if (ret != ErrorCode::NO_ERROR) {
|
||||
IMSA_HILOGE("AddClient failed");
|
||||
IMSA_HILOGE("AddClientInfo failed");
|
||||
return ret;
|
||||
}
|
||||
auto info = GetClientInfo(remoteClient);
|
||||
@ -760,11 +748,8 @@ int32_t PerUserSession::OnUpdateListenEventFlag(const InputClientInfo &clientInf
|
||||
IMSA_HILOGE("info is nullptr");
|
||||
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
|
||||
}
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
if (info->eventFlag == EventStatusManager::NO_EVENT_ON && info->bindStatus == BindStatus::NO_BIND) {
|
||||
remoteClient->RemoveDeathRecipient(info->deathRecipient);
|
||||
info->deathRecipient = nullptr;
|
||||
mapClients_.erase(remoteClient);
|
||||
RemoveClientInfo(remoteClient, false);
|
||||
}
|
||||
return ErrorCode::NO_ERROR;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ ohos_static_library("inputmethod_test_common") {
|
||||
configs = [ ":test_common_config" ]
|
||||
public_configs = [ ":test_common_public_config" ]
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
]
|
||||
external_deps = [ "hilog:libhilog" ]
|
||||
|
@ -38,7 +38,7 @@ ohos_fuzztest("AgentStubFuzzTest") {
|
||||
|
||||
sources = [ "agentstub_fuzzer.cpp" ]
|
||||
|
||||
deps = [ "${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability" ]
|
||||
deps = [ "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability" ]
|
||||
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
|
@ -39,7 +39,7 @@ ohos_fuzztest("CoreStubFuzzTest") {
|
||||
|
||||
sources = [ "corestub_fuzzer.cpp" ]
|
||||
|
||||
deps = [ "${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability" ]
|
||||
deps = [ "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability" ]
|
||||
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
|
@ -37,7 +37,7 @@ ohos_fuzztest("InputClientStubFuzzTest") {
|
||||
sources = [ "inputclientstub_fuzzer.cpp" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
]
|
||||
|
@ -37,7 +37,7 @@ ohos_fuzztest("InputMethodAbilityFuzzTest") {
|
||||
sources = [ "inputmethodability_fuzzer.cpp" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/common:inputmethod_test_common",
|
||||
]
|
||||
|
@ -41,7 +41,7 @@ ohos_fuzztest("PerUserSessionFuzzTest") {
|
||||
sources = [ "perusersession_fuzzer.cpp" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"//third_party/jsoncpp:jsoncpp",
|
||||
|
@ -33,7 +33,7 @@ ohos_unittest("InputMethodControllerTest") {
|
||||
configs = [ ":module_private_config" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/common:inputmethod_test_common",
|
||||
@ -67,7 +67,7 @@ ohos_unittest("InputMethodAttachTest") {
|
||||
configs = [ ":module_private_config" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/common:inputmethod_test_common",
|
||||
@ -102,7 +102,7 @@ ohos_unittest("InputMethodAbilityTest") {
|
||||
]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/common:inputmethod_test_common",
|
||||
@ -139,7 +139,7 @@ ohos_unittest("InputMethodServiceTest") {
|
||||
]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/common:inputmethod_test_common",
|
||||
@ -170,7 +170,7 @@ ohos_unittest("InputMethodDfxTest") {
|
||||
configs = [ ":module_private_config" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/services/dfx:inputmethod_dfx_static",
|
||||
@ -209,7 +209,7 @@ ohos_unittest("InputMethodPanelTest") {
|
||||
]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/unittest/cpp_test/common:inputmethod_tdd_util",
|
||||
@ -279,7 +279,7 @@ ohos_unittest("InputMethodPrivateMemberTest") {
|
||||
configs = [ ":module_private_config" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/unittest/cpp_test/common:inputmethod_tdd_util",
|
||||
@ -309,7 +309,7 @@ ohos_unittest("InputMethodEditorTest") {
|
||||
configs = [ ":module_private_config" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/common:inputmethod_test_common",
|
||||
@ -368,7 +368,7 @@ ohos_unittest("IdentityCheckerTest") {
|
||||
]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/common:inputmethod_test_common",
|
||||
@ -400,7 +400,7 @@ ohos_unittest("TextListenerInnerApiTest") {
|
||||
configs = [ ":module_private_config" ]
|
||||
|
||||
deps = [
|
||||
"${inputmethod_path}/frameworks/native/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability",
|
||||
"${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static",
|
||||
"${inputmethod_path}/services:inputmethod_service",
|
||||
"${inputmethod_path}/test/common:inputmethod_test_common",
|
||||
|
Loading…
Reference in New Issue
Block a user