diff --git a/common/include/variant_util.h b/common/include/variant_util.h index 347ba8da8e10edb8bb84add3ef6745411b54d321..1e4cd66704e85b74fe6ee09844d248b75b6ac475 100644 --- a/common/include/variant_util.h +++ b/common/include/variant_util.h @@ -23,6 +23,7 @@ #include "input_method_utils.h" namespace OHOS { namespace MiscServices { +using ContrlToCoreMsgParam = std::variant>; class VariantUtil { public: template @@ -45,6 +46,16 @@ public: output = std::get(input); return true; } + + template + static bool GetContrlToCoreValue(ContrlToCoreMsgParam &input, T &output) + { + if (!std::holds_alternative(input)) { + return false; + } + output = std::get(input); + return true; + } }; } // namespace MiscServices } // namespace OHOS diff --git a/frameworks/js/napi/inputmethodclient/async_call.cpp b/frameworks/js/napi/inputmethodclient/async_call.cpp index 9cb216c17e19e1239f25f795baf975f32eea512a..d542a1fb26414a8ac56a3c87b5ed1e5cf87f99b4 100644 --- a/frameworks/js/napi/inputmethodclient/async_call.cpp +++ b/frameworks/js/napi/inputmethodclient/async_call.cpp @@ -19,6 +19,7 @@ #include "global.h" #include "js_utils.h" +#include "task_manager.h" namespace OHOS { namespace MiscServices { diff --git a/frameworks/js/napi/inputmethodclient/async_call.h b/frameworks/js/napi/inputmethodclient/async_call.h index c2f228d03e30824bf3c08d3b8c029df0d6e7ef82..13a6d554a816705294e99e71e5aacab971367dcc 100644 --- a/frameworks/js/napi/inputmethodclient/async_call.h +++ b/frameworks/js/napi/inputmethodclient/async_call.h @@ -160,13 +160,13 @@ protected: }; static void OnExecuteAsync(napi_env env, AsyncContext *context, Context::CallBackAction cb); static void OnComplete(napi_env env, napi_status status, void *data); + static void OnExecute(napi_env env, void *data); private: virtual void CallImpl(napi_env env, AsyncContext *context, const std::string &resourceName); private: enum Arg : int { ARG_ERROR, ARG_DATA, ARG_BUTT }; - static void OnExecute(napi_env env, void *data); static void OnExecuteSeq(napi_env env, void *data); static void DeleteContext(napi_env env, AsyncContext *context); diff --git a/frameworks/js/napi/inputmethodclient/imc_async_call.h b/frameworks/js/napi/inputmethodclient/imc_async_call.h new file mode 100644 index 0000000000000000000000000000000000000000..8b2d7bfc4b7e95a18c4224ed104fa195acde867b --- /dev/null +++ b/frameworks/js/napi/inputmethodclient/imc_async_call.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025 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 IMC_ASYN_CALL_H +#define IMC_ASYN_CALL_H + +#include "async_call.h" +#include "task_manager.h" +#include "input_method_controller.h" +namespace OHOS { +namespace MiscServices { +class IMCAsyncCall : public AsyncCall { +public: + IMCAsyncCall(napi_env env, napi_callback_info info, std::shared_ptr context, size_t maxParamCount) + : AsyncCall(env, info, context, maxParamCount) {}; + virtual ~IMCAsyncCall(){}; + +public: + static void Request(std::function work, + AsyncCall::Context::CallBackAction completeFunc, std::shared_ptr ctxt, + const std::string errMsg, std::function handler) + { + auto callback = [ctxt, completeFunc, errMsg, handler](int32_t code) -> void { + if (handler != nullptr) { + handler(code); + } else { + if (code == ErrorCode::NO_ERROR) { + ctxt->SetState(napi_ok); + } else { + ctxt->SetErrorCode(code); + ctxt->SetErrorMessage(errMsg); + } + } + completeFunc != nullptr ? completeFunc() : IMSA_HILOGE("completeFunc is nullptr"); + }; + int32_t status = work(callback); + if (status != ErrorCode::NO_ERROR) { + if (handler != nullptr) { + handler(status); + } else { + ctxt->SetErrorCode(status); + ctxt->SetErrorMessage(errMsg); + } + completeFunc != nullptr ? completeFunc() : IMSA_HILOGE("completeFunc is nullptr"); + } + } + +private: + void CallImpl(napi_env env, AsyncContext *context, const std::string &resourceName) override + { + if (context == nullptr || context->ctx == nullptr) { + IMSA_HILOGE("context is nullptr!"); + return; + } + auto cb = [env, context, resourceName]() -> void { + auto task = [env, context]() -> void { + AsyncCall::OnComplete(env, context->ctx->GetState(), context); + }; + auto handler = context->ctx->GetHandler(); + if (handler) { + handler->PostTask(task, "IMF_" + resourceName + "_IMC", 0, AppExecFwk::EventQueue::Priority::VIP); + } + }; + AsyncCall::OnExecuteAsync(env, context, cb); + } +}; +} // namespace MiscServices +} // namespace OHOS +#endif // IMC_ASYN_CALL_H diff --git a/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.cpp b/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.cpp index 8fa0fc6c1fa7b81da8973bc432a35f1f6a127c0a..65eddd9d0ad69f594755028d2f0349d099994954 100644 --- a/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.cpp +++ b/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.cpp @@ -57,8 +57,6 @@ std::mutex JsGetInputMethodController::controllerMutex_; std::shared_ptr JsGetInputMethodController::controller_{ nullptr }; std::mutex JsGetInputMethodController::eventHandlerMutex_; std::shared_ptr JsGetInputMethodController::handler_{ nullptr }; -BlockQueue JsGetInputMethodController::messageHandlerQueue_{ MAX_WAIT_TIME_MESSAGE_HANDLER }; -BlockQueue JsGetInputMethodController::attachQueue_{ MAX_WAIT_TIME_ATTACH }; napi_value JsGetInputMethodController::Init(napi_env env, napi_value info) { napi_property_descriptor descriptor[] = { @@ -521,7 +519,7 @@ napi_value JsGetInputMethodController::CreateSelectMovement(napi_env env, int32_ } napi_value JsGetInputMethodController::HandleSoftKeyboard(napi_env env, napi_callback_info info, - std::function callback, bool isOutput, bool needThrowException) + std::function work, bool isOutput, bool needThrowException) { auto ctxt = std::make_shared(); auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { @@ -535,22 +533,25 @@ napi_value JsGetInputMethodController::HandleSoftKeyboard(napi_env env, napi_cal IMSA_HILOGE("output get boolean != nullptr[%{public}d]", result != nullptr); return status; }; - auto exec = [ctxt, callback, needThrowException](AsyncCall::Context *ctx) { - int errCode = callback(); - if (errCode == ErrorCode::NO_ERROR) { - IMSA_HILOGI("exec success."); - ctxt->status = napi_ok; - ctxt->isHandle = true; - ctxt->SetState(ctxt->status); - return; - } - if (needThrowException) { - ctxt->SetErrorCode(errCode); - } + auto exec = [ctxt, work, needThrowException](AsyncCall::Context *ctx, + AsyncCall::Context::CallBackAction completeFunc) { + auto handler = [ctxt, needThrowException](int32_t code) { + if (code == ErrorCode::NO_ERROR) { + IMSA_HILOGI("exec success."); + ctxt->status = napi_ok; + ctxt->isHandle = true; + ctxt->SetState(ctxt->status); + return; + } + if (needThrowException) { + ctxt->SetErrorCode(code); + } + }; + IMCAsyncCall::Request(work, completeFunc, ctxt, "handleSoftKeyboard error", handler); }; ctxt->SetAction(std::move(input), std::move(output)); // 1 means JsAPI has 1 param at most. - AsyncCall asyncCall(env, info, ctxt, 1); + IMCAsyncCall asyncCall(env, info, ctxt, 1); return asyncCall.Call(env, exec, "handleSoftKeyboard"); } @@ -653,43 +654,42 @@ napi_value JsGetInputMethodController::Attach(napi_env env, napi_callback_info i } } ctxt->info = { std::chrono::system_clock::now(), ctxt->attribute}; - attachQueue_.Push(ctxt->info); ctxt->textListener = JsGetInputMethodTextChangedListener::GetTextListener(GetEventHandler(), ctxt->textConfig.newEditBox); return napi_ok; }; - auto exec = [ctxt, env](AsyncCall::Context *ctx) { - attachQueue_.Wait(ctxt->info); + auto exec = [ctxt, env](AsyncCall::Context *ctx, AsyncCall::Context::CallBackAction completeFunc) { OHOS::MiscServices::AttachOptions attachOptions; attachOptions.isShowKeyboard = ctxt->showKeyboard; attachOptions.requestKeyboardReason = static_cast(ctxt->requestKeyboardReason); - int32_t status = ErrorCode::ERROR_CLIENT_NULL_POINTER; - auto instance = InputMethodController::GetInstance(); - if (instance != nullptr) { - status = instance->Attach(ctxt->textListener, attachOptions, ctxt->textConfig, ClientType::JS); - } - attachQueue_.Pop(); - ctxt->SetErrorCode(status); - CHECK_RETURN_VOID(status == ErrorCode::NO_ERROR, "attach return error!"); - ctxt->SetState(napi_ok); + auto work = [ctxt, &attachOptions](AsyncCallback callback) -> int32_t { + int32_t status = ErrorCode::ERROR_CLIENT_NULL_POINTER; + auto instance = InputMethodController::GetInstance(); + if (instance != nullptr && callback != nullptr) { + status = instance->AttachAsync(ctxt->textListener, attachOptions, ctxt->textConfig, ClientType::JS, + callback); + } + return status; + }; + IMCAsyncCall::Request(work, completeFunc, ctxt, "attach return error!", nullptr); }; ctxt->SetAction(std::move(input)); // 3 means JsAPI:attach has 3 params at most. - AsyncCall asyncCall(env, info, ctxt, 3); + IMCAsyncCall asyncCall(env, info, ctxt, 3); return asyncCall.Call(env, exec, "attach"); } napi_value JsGetInputMethodController::Detach(napi_env env, napi_callback_info info) { return HandleSoftKeyboard( - env, info, [] () -> int32_t { + env, info, [] (AsyncCallback callback) -> int32_t { auto instance = InputMethodController::GetInstance(); if (instance == nullptr) { IMSA_HILOGE("GetInstance return nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } - return instance->Close(); + return instance->CloseAsync(callback); }, false, true); } @@ -701,13 +701,13 @@ napi_value JsGetInputMethodController::ShowTextInput(napi_env env, napi_callback InputMethodSyncTrace tracer("JsGetInputMethodController_ShowTextInput"); return HandleSoftKeyboard( env, info, - [attachOptions] () -> int32_t { + [attachOptions] (AsyncCallback callback) -> int32_t { auto instance = InputMethodController::GetInstance(); if (instance == nullptr) { IMSA_HILOGE("GetInstance return nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } - return instance->ShowTextInput(attachOptions, ClientType::JS); + return instance->ShowTextInputAsync(callback, attachOptions, ClientType::JS); }, false, true); } @@ -741,13 +741,13 @@ napi_value JsGetInputMethodController::HideTextInput(napi_env env, napi_callback InputMethodSyncTrace tracer("JsGetInputMethodController_HideTextInput"); return HandleSoftKeyboard( env, info, - [] () -> int32_t { + [] (AsyncCallback callbac) -> int32_t { auto instance = InputMethodController::GetInstance(); if (instance == nullptr) { IMSA_HILOGE("GetInstance return nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } - return instance->HideTextInput(); + return instance->HideTextInputAsync(callbac); }, false, true); } @@ -756,14 +756,14 @@ napi_value JsGetInputMethodController::DiscardTypingText(napi_env env, napi_call { InputMethodSyncTrace tracer("JsGetInputMethodController_DiscardTypingText"); return HandleSoftKeyboard( - env, info - , [] { + env, info, + [] (AsyncCallback callbac) { auto instance = InputMethodController::GetInstance(); if (instance == nullptr) { IMSA_HILOGE("GetInstance return nullptr!"); return static_cast(ErrorCode::ERROR_CLIENT_NULL_POINTER); } - return instance->DiscardTypingText(); + return instance->DiscardTypingTextAsync(callbac); }, false, true); } @@ -778,19 +778,20 @@ napi_value JsGetInputMethodController::SetCallingWindow(napi_env env, napi_callb PARAM_CHECK_RETURN(env, status == napi_ok, "windowId type must be number", TYPE_NONE, status); return status; }; - auto exec = [ctxt](AsyncCall::Context *ctx) { - int32_t errcode = ErrorCode::ERROR_CLIENT_NULL_POINTER; - auto instance = InputMethodController::GetInstance(); - if (instance != nullptr) { - errcode = instance->SetCallingWindow(ctxt->windID); - } - ctxt->SetErrorCode(errcode); - CHECK_RETURN_VOID(errcode == ErrorCode::NO_ERROR, "setCallingWindow return error!"); - ctxt->SetState(napi_ok); + auto exec = [ctxt](AsyncCall::Context *ctx, AsyncCall::Context::CallBackAction completeFunc) { + auto work = [ctxt](AsyncCallback callback) -> int32_t { + int32_t status = ErrorCode::ERROR_CLIENT_NULL_POINTER; + auto instance = InputMethodController::GetInstance(); + if (instance != nullptr && callback != nullptr) { + status = instance->SetCallingWindowAsync(ctxt->windID, callback); + } + return status; + }; + IMCAsyncCall::Request(work, completeFunc, ctxt, "setCallingWindow return error!", nullptr); }; ctxt->SetAction(std::move(input)); // 2 means JsAPI:setCallingWindow has 2 params at most. - AsyncCall asyncCall(env, info, ctxt, 2); + IMCAsyncCall asyncCall(env, info, ctxt, 2); return asyncCall.Call(env, exec, "setCallingWindow"); } @@ -815,19 +816,20 @@ napi_value JsGetInputMethodController::UpdateCursor(napi_env env, napi_callback_ napi_generic_failure); return napi_ok; }; - auto exec = [ctxt](AsyncCall::Context *ctx) { - int32_t errcode = ErrorCode::ERROR_CLIENT_NULL_POINTER; - auto instance = InputMethodController::GetInstance(); - if (instance != nullptr) { - errcode = instance->OnCursorUpdate(ctxt->cursorInfo); - } - ctxt->SetErrorCode(errcode); - CHECK_RETURN_VOID(errcode == ErrorCode::NO_ERROR, "updateCursor return error!"); - ctxt->SetState(napi_ok); + auto exec = [ctxt](AsyncCall::Context *ctx, AsyncCall::Context::CallBackAction completeFunc) { + auto work = [ctxt](AsyncCallback callback) -> int32_t { + int32_t status = ErrorCode::ERROR_CLIENT_NULL_POINTER; + auto instance = InputMethodController::GetInstance(); + if (instance != nullptr && callback != nullptr) { + status = instance->OnCursorUpdateAsync(ctxt->cursorInfo, callback); + } + return status; + }; + IMCAsyncCall::Request(work, completeFunc, ctxt, "updateCursor return error!", nullptr); }; ctxt->SetAction(std::move(input)); // 2 means JsAPI:updateCursor has 2 params at most. - AsyncCall asyncCall(env, info, ctxt, 2); + IMCAsyncCall asyncCall(env, info, ctxt, 2); return asyncCall.Call(env, exec, "updateCursor"); } @@ -844,19 +846,20 @@ napi_value JsGetInputMethodController::ChangeSelection(napi_env env, napi_callba napi_generic_failure); return napi_ok; }; - auto exec = [ctxt](AsyncCall::Context *ctx) { - int32_t errcode = ErrorCode::ERROR_CLIENT_NULL_POINTER; - auto instance = InputMethodController::GetInstance(); - if (instance != nullptr) { - errcode = instance->OnSelectionChange(ctxt->text, ctxt->start, ctxt->end); - } - ctxt->SetErrorCode(errcode); - CHECK_RETURN_VOID(errcode == ErrorCode::NO_ERROR, "changeSelection return error!"); - ctxt->SetState(napi_ok); + auto exec = [ctxt](AsyncCall::Context *ctx, AsyncCall::Context::CallBackAction completeFunc) { + auto work = [ctxt](AsyncCallback callback) -> int32_t { + int32_t status = ErrorCode::ERROR_CLIENT_NULL_POINTER; + auto instance = InputMethodController::GetInstance(); + if (instance != nullptr && callback != nullptr) { + status = instance->OnSelectionChangeAsync(ctxt->text, ctxt->start, ctxt->end, callback); + } + return status; + }; + IMCAsyncCall::Request(work, completeFunc, ctxt, "changeSelection return error!", nullptr); }; ctxt->SetAction(std::move(input)); // 4 means JsAPI:changeSelection has 4 params at most. - AsyncCall asyncCall(env, info, ctxt, 4); + IMCAsyncCall asyncCall(env, info, ctxt, 4); return asyncCall.Call(env, exec, "changeSelection"); } @@ -884,19 +887,20 @@ napi_value JsGetInputMethodController::UpdateAttribute(napi_env env, napi_callba ctxt->configuration.SetEnterKeyType(static_cast(ctxt->attribute.enterKeyType)); return napi_ok; }; - auto exec = [ctxt](AsyncCall::Context *ctx) { - int32_t errcode = ErrorCode::ERROR_CLIENT_NULL_POINTER; - auto instance = InputMethodController::GetInstance(); - if (instance != nullptr) { - errcode = instance->OnConfigurationChange(ctxt->configuration); - } - ctxt->SetErrorCode(errcode); - CHECK_RETURN_VOID(errcode == ErrorCode::NO_ERROR, "updateAttribute return error!"); - ctxt->SetState(napi_ok); + auto exec = [ctxt](AsyncCall::Context *ctx, AsyncCall::Context::CallBackAction completeFunc) { + auto work = [ctxt](AsyncCallback callback) -> int32_t { + int32_t status = ErrorCode::ERROR_CLIENT_NULL_POINTER; + auto instance = InputMethodController::GetInstance(); + if (instance != nullptr && callback != nullptr) { + status = instance->OnConfigurationChangeAsync(ctxt->configuration, callback); + } + return status; + }; + IMCAsyncCall::Request(work, completeFunc, ctxt, "updateAttribute return error!", nullptr); }; ctxt->SetAction(std::move(input)); // 2 means JsAPI:updateAttribute has 2 params at most. - AsyncCall asyncCall(env, info, ctxt, 2); + IMCAsyncCall asyncCall(env, info, ctxt, 2); return asyncCall.Call(env, exec, "updateAttribute"); } @@ -905,13 +909,13 @@ napi_value JsGetInputMethodController::ShowSoftKeyboard(napi_env env, napi_callb InputMethodSyncTrace tracer("JsGetInputMethodController_ShowSoftKeyboard"); return HandleSoftKeyboard( env, info, - [] () -> int32_t { + [] (AsyncCallback callback) -> int32_t { auto instance = InputMethodController::GetInstance(); if (instance == nullptr) { IMSA_HILOGE("GetInstance return nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } - return instance->ShowSoftKeyboard(ClientType::JS); + return instance->ShowSoftKeyboardAsync(callback, ClientType::JS); }, false, true); } @@ -921,13 +925,13 @@ napi_value JsGetInputMethodController::HideSoftKeyboard(napi_env env, napi_callb InputMethodSyncTrace tracer("JsGetInputMethodController_HideSoftKeyboard"); return HandleSoftKeyboard( env, info, - [] () -> int32_t { + [] (AsyncCallback callbac) -> int32_t { auto instance = InputMethodController::GetInstance(); if (instance == nullptr) { IMSA_HILOGE("GetInstance return nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } - return instance->HideSoftKeyboard(); + return instance->HideSoftKeyboardAsync(callbac); }, false, true); } @@ -936,13 +940,13 @@ napi_value JsGetInputMethodController::StopInputSession(napi_env env, napi_callb { return HandleSoftKeyboard( env, info, - [] () -> int32_t { + [] (AsyncCallback callbac) -> int32_t { auto instance = InputMethodController::GetInstance(); if (instance == nullptr) { IMSA_HILOGE("GetInstance return nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } - return instance->StopInputSession(); + return instance->StopInputSessionAsync(callbac); }, true, true); } @@ -951,13 +955,13 @@ napi_value JsGetInputMethodController::StopInput(napi_env env, napi_callback_inf { return HandleSoftKeyboard( env, info, - []() -> int32_t { + [](AsyncCallback callbac) -> int32_t { auto instance = InputMethodController::GetInstance(); if (instance == nullptr) { IMSA_HILOGE("GetInstance return nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } - return instance->HideCurrentInput(); + return instance->HideCurrentInputAsync(callbac); }, true, false); } @@ -1366,27 +1370,30 @@ napi_value JsGetInputMethodController::SendMessage(napi_env env, napi_callback_i PARAM_CHECK_RETURN(env, ArrayBuffer::IsSizeValid(ctxt->arrayBuffer), "msgId limit 256B and msgParam limit 128KB.", TYPE_NONE, napi_generic_failure); ctxt->info = { std::chrono::system_clock::now(), ctxt->arrayBuffer }; - messageHandlerQueue_.Push(ctxt->info); return napi_ok; }; - auto exec = [ctxt](AsyncCall::Context *ctx) { - messageHandlerQueue_.Wait(ctxt->info); - int32_t code = ErrorCode::ERROR_CLIENT_NULL_POINTER; - auto instance = InputMethodController::GetInstance(); - if (instance != nullptr) { - code = instance->SendMessage(ctxt->arrayBuffer); - } - messageHandlerQueue_.Pop(); - if (code == ErrorCode::NO_ERROR) { - ctxt->status = napi_ok; - ctxt->SetState(ctxt->status); - } else { - ctxt->SetErrorCode(code); - } + auto exec = [ctxt](AsyncCall::Context *ctx, AsyncCall::Context::CallBackAction completeFunc) { + auto work = [ctxt](AsyncCallback callback) -> int32_t { + int32_t status = ErrorCode::ERROR_CLIENT_NULL_POINTER; + auto instance = InputMethodController::GetInstance(); + if (instance != nullptr && callback != nullptr) { + status = instance->SendMessageAsync(ctxt->arrayBuffer, callback); + } + return status; + }; + auto handler = [ctxt](int32_t code) { + if (code == ErrorCode::NO_ERROR) { + ctxt->status = napi_ok; + ctxt->SetState(ctxt->status); + } else { + ctxt->SetErrorCode(code); + } + }; + IMCAsyncCall::Request(work, completeFunc, ctxt, "sendMessage return error!", handler); }; ctxt->SetAction(std::move(input), nullptr); // 2 means JsAPI:sendMessage has 2 params at most. - AsyncCall asyncCall(env, info, ctxt, 2); + IMCAsyncCall asyncCall(env, info, ctxt, 2); return asyncCall.Call(env, exec, "imcSendMessage"); } diff --git a/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.h b/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.h index da9589ba8ffa2d9cfb2d62308c5fedd121c608f8..97396ffafc1aceefc6c00b22099e2d34628b273c 100644 --- a/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.h +++ b/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.h @@ -15,7 +15,7 @@ #ifndef INTERFACE_KITS_JS_GET_INPUT_METHOD_CONTROLLER_H #define INTERFACE_KITS_JS_GET_INPUT_METHOD_CONTROLLER_H -#include "async_call.h" +#include "imc_async_call.h" #include "controller_listener.h" #include "event_handler.h" #include "global.h" @@ -172,8 +172,8 @@ public: static napi_value GetController(napi_env env, napi_callback_info cbInfo); static napi_value GetInputMethodController(napi_env env, napi_callback_info cbInfo); static std::shared_ptr GetInstance(); - static napi_value HandleSoftKeyboard(napi_env env, napi_callback_info info, std::function callback, - bool isOutput, bool needThrowException); + static napi_value HandleSoftKeyboard(napi_env env, napi_callback_info info, + std::function work, bool isOutput, bool needThrowException); static napi_value Attach(napi_env env, napi_callback_info info); static napi_value Detach(napi_env env, napi_callback_info info); static napi_value ShowTextInput(napi_env env, napi_callback_info info); diff --git a/frameworks/native/inputmethod_ability/IInputControlChannel.idl b/frameworks/native/inputmethod_ability/IInputControlChannel.idl index af5015425d1bab2aa4c840e51b5926d838f64f97..bc90f37ef568c1480992ea1b7afd67774c00a9c1 100644 --- a/frameworks/native/inputmethod_ability/IInputControlChannel.idl +++ b/frameworks/native/inputmethod_ability/IInputControlChannel.idl @@ -12,7 +12,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + +sequenceable OHOS.IRemoteObject; interface OHOS.MiscServices.IInputControlChannel { - void HideKeyboardSelf(); + [ipccode 0] void HideKeyboardSelf(); + [oneway] void ToCoreOnConnectSystemCmd([in] long id, [in] int code, [in] IRemoteObject agent); + [oneway] void ToCoreIsEnable([in] long id, [in] int code, [in] boolean resultValue); + [oneway] void ToCoreIsPanelShown([in] long id, [in] int code, [in] boolean isShown); } diff --git a/frameworks/native/inputmethod_ability/IInputMethodCore.idl b/frameworks/native/inputmethod_ability/IInputMethodCore.idl index aa7aef25795e5398ac454885bbe5faaad9aa7954..4152e58d07850ea673443539b04ab794d3692d27 100644 --- a/frameworks/native/inputmethod_ability/IInputMethodCore.idl +++ b/frameworks/native/inputmethod_ability/IInputMethodCore.idl @@ -27,10 +27,10 @@ interface OHOS.MiscServices.IInputMethodCore { void InitInputControlChannel([in] IInputControlChannel inputControlChannel); void StopInputService([in] boolean isTerminateIme); void SetSubtype([in] SubProperty property); - void IsEnable([out] boolean resultValue); - void IsPanelShown([in] PanelInfo panelInfo, [out] boolean isShown); + [oneway] void IsEnable([in] long id); + [oneway] void IsPanelShown([in] long id, [in] PanelInfo panelInfo); void OnSecurityChange([in] int security); - void OnConnectSystemCmd([in] IRemoteObject channel, [out] IRemoteObject agent); + [oneway] void OnConnectSystemCmd([in] long id, [in] IRemoteObject channel); [oneway] void OnClientInactive([in] IRemoteObject channel); [oneway] void OnSetInputType([in] int inputType); void OnCallingDisplayIdChanged([in] unsigned long dispalyId); diff --git a/frameworks/native/inputmethod_ability/include/input_method_ability.h b/frameworks/native/inputmethod_ability/include/input_method_ability.h index d212c80f2efed16ce27ae65f4c6f124c2058eda6..9846c677047dda3227ae65e5d94294f7d3e4a057 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_ability.h +++ b/frameworks/native/inputmethod_ability/include/input_method_ability.h @@ -110,6 +110,9 @@ public: int32_t OnSendPrivateData(const std::unordered_map &privateCommand); bool HandleUnconsumedKey(const std::shared_ptr &keyEvent); int32_t OnResponse(uint64_t msgId, int32_t code, const ResponseData &data); + void ReplyIsEnable(int64_t id, int32_t code, bool &enbale); + void ReplyIsPanelShown(int64_t id, int32_t code, bool &isShown); + void ReplyOnConnectSystemCmd(int64_t id, int32_t code, const sptr &agent); int32_t IsCapacitySupport(int32_t capacity, bool &isSupport); public: diff --git a/frameworks/native/inputmethod_ability/include/input_method_core_service_impl.h b/frameworks/native/inputmethod_ability/include/input_method_core_service_impl.h index dda07ef7a592d3582bd75ba32ffd801c35e55891..2bfffaea0e775a57a3c18cfe9c1fa823901072be 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_core_service_impl.h +++ b/frameworks/native/inputmethod_ability/include/input_method_core_service_impl.h @@ -39,10 +39,10 @@ public: ErrCode InitInputControlChannel(const sptr &inputControlChannel) override; ErrCode StopInputService(bool isTerminateIme) override; ErrCode SetSubtype(const SubProperty &property) override; - ErrCode IsEnable(bool &resultValue) override; - ErrCode IsPanelShown(const PanelInfo &panelInfo, bool &isShown) override; + ErrCode IsEnable(int64_t id) override; + ErrCode IsPanelShown(int64_t id, const PanelInfo &panelInfo) override; ErrCode OnSecurityChange(int32_t security) override; - ErrCode OnConnectSystemCmd(const sptr &channel, sptr &agent) override; + ErrCode OnConnectSystemCmd(int64_t id, const sptr &channel) override; ErrCode OnClientInactive(const sptr &channel) override; ErrCode OnSetInputType(int32_t inputType) override; ErrCode OnCallingDisplayIdChanged(uint64_t dispalyId) override; diff --git a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp index 0c4a5317525390afac7aeb7007e17d0731a3377b..cece024fc8f3ada3b2451dbde4e420cacef833df 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp @@ -1822,6 +1822,42 @@ int32_t InputMethodAbility::OnResponse(uint64_t msgId, int32_t code, const Respo return ErrorCode::NO_ERROR; } +void InputMethodAbility::ReplyIsEnable(int64_t id, int32_t code, bool &enbale) +{ + auto controlChannel = GetInputControlChannel(); + if (controlChannel != nullptr) { + return; + } + int32_t ret = controlChannel->ToCoreIsEnable(id, code, enbale); + if (ret != ERR_OK) { + IMSA_HILOGE("ToCoreIsEnable code: %{public}d", ret); + } +} + +void InputMethodAbility::ReplyIsPanelShown(int64_t id, int32_t code, bool &isShown) +{ + auto controlChannel = GetInputControlChannel(); + if (controlChannel != nullptr) { + return; + } + int32_t ret = controlChannel->ToCoreIsPanelShown(id, code, isShown); + if (ret != ERR_OK) { + IMSA_HILOGE("ToCoreIsPanelShown code: %{public}d", ret); + } +} + +void InputMethodAbility::ReplyOnConnectSystemCmd(int64_t id, int32_t code, const sptr &agent) +{ + auto controlChannel = GetInputControlChannel(); + if (controlChannel != nullptr) { + return; + } + int32_t ret = controlChannel->ToCoreOnConnectSystemCmd(id, code, agent); + if (ret != ERR_OK) { + IMSA_HILOGE("ToCoreOnConnectSystemCmd code: %{public}d", ret); + } +} + int32_t InputMethodAbility::IsCapacitySupport(int32_t capacity, bool &isSupport) { auto proxy = GetImsaProxy(); diff --git a/frameworks/native/inputmethod_ability/src/input_method_core_service_impl.cpp b/frameworks/native/inputmethod_ability/src/input_method_core_service_impl.cpp index 2b563cf6c3c387bc3c20eaa35eba7621a735fc68..a03142c0f07f570c09badd78caa1f6b2b8ff12f3 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_core_service_impl.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_core_service_impl.cpp @@ -63,10 +63,12 @@ ErrCode InputMethodCoreServiceImpl::StopInputService(bool isTerminateIme) return ERR_OK; } -ErrCode InputMethodCoreServiceImpl::OnConnectSystemCmd( - const sptr &channel, sptr &agent) +ErrCode InputMethodCoreServiceImpl::OnConnectSystemCmd(int64_t id, const sptr &channel) { - return InputMethodAbility::GetInstance().OnConnectSystemCmd(channel, agent); + sptr agent = nullptr; + int32_t code = InputMethodAbility::GetInstance().OnConnectSystemCmd(channel, agent); + InputMethodAbility::GetInstance().ReplyOnConnectSystemCmd(id, code, agent); + return code; } ErrCode InputMethodCoreServiceImpl::StartInput(const InputClientInfoInner &clientInfoInner, bool isBindFromClient) @@ -103,15 +105,19 @@ ErrCode InputMethodCoreServiceImpl::StopInput(const sptr &channel return ERR_OK; } -ErrCode InputMethodCoreServiceImpl::IsEnable(bool &resultValue) +ErrCode InputMethodCoreServiceImpl::IsEnable(int64_t id) { - resultValue = InputMethodAbility::GetInstance().IsEnable(); + bool resultValue = InputMethodAbility::GetInstance().IsEnable(); + InputMethodAbility::GetInstance().ReplyIsEnable(id, ERR_OK, resultValue); return ERR_OK; } -ErrCode InputMethodCoreServiceImpl::IsPanelShown(const PanelInfo &panelInfo, bool &isShown) +ErrCode InputMethodCoreServiceImpl::IsPanelShown(int64_t id, const PanelInfo &panelInfo) { - return InputMethodAbility::GetInstance().IsPanelShown(panelInfo, isShown); + bool isShown = false; + int32_t code = InputMethodAbility::GetInstance().IsPanelShown(panelInfo, isShown); + InputMethodAbility::GetInstance().ReplyIsPanelShown(id, code, isShown); + return code; } ErrCode InputMethodCoreServiceImpl::OnClientInactive(const sptr &channel) @@ -132,6 +138,5 @@ ErrCode InputMethodCoreServiceImpl::OnSendPrivateData(const Value &Value) privateCommand = Value.valueMap; return InputMethodAbility::GetInstance().OnSendPrivateData(privateCommand); } - } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/include/task_sequencing.h b/frameworks/native/inputmethod_controller/include/task_sequencing.h new file mode 100644 index 0000000000000000000000000000000000000000..7939ff350460124744752ac60397f4e0b2a71446 --- /dev/null +++ b/frameworks/native/inputmethod_controller/include/task_sequencing.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2025 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 INPUTMETHOD_IMF_TASK_SEQUENCING_H +#define INPUTMETHOD_IMF_TASK_SEQUENCING_H +#include +#include +#include +#include "event_handler.h" +#include "global.h" + +namespace OHOS { +namespace MiscServices { +using SyncTaskFunc = std::function; +using AsyncTaskFunc = std::function; + +class TaskSequencing { +public: + enum TaskStatus : int32_t { + TS_WAIT = 0, + TS_RUN, + TS_TERMINATE, + }; + + TaskSequencing(){}; + virtual ~TaskSequencing(){}; + + int32_t LineUp(SyncTaskFunc sync); + int32_t LineUp(AsyncTaskFunc async); + void LeaveLine(uint32_t id); +private: + struct TaskInfo { + bool isMainThread = false; + uint32_t id = 0; + SyncTaskFunc sync = nullptr; + AsyncTaskFunc async = nullptr; + std::mutex taskMutex; + std::shared_ptr cv = nullptr; + + TaskInfo(uint32_t id, SyncTaskFunc sync, AsyncTaskFunc async) + { + this->id = id; + this->sync = sync; + this->async = async; + if (sync) { + auto mainEventRunner = AppExecFwk::EventRunner::GetMainEventRunner(); + if (!mainEventRunner) { + IMSA_HILOGW("mainEventRunner is nullptr"); + } + auto Current = AppExecFwk::EventHandler::Current(); + if (!Current) { + IMSA_HILOGW("Current is nullptr"); + } + if (Current && !Current->GetEventRunner()) { + IMSA_HILOGW("GetEventRunner is nullptr"); + } + if (mainEventRunner && Current && Current->GetEventRunner()) { + uint64_t mtid = mainEventRunner->GetThreadId(); + uint64_t ctid = Current->GetEventRunner()->GetThreadId(); + isMainThread = (mtid == ctid); + } + cv = std::make_shared(); + } + SetStatus(TaskStatus::TS_WAIT); + } + void SetStatus(TaskStatus ts) + { + status.store(ts); + } + TaskStatus GetStatus() + { + return status.load(); + } + static uint32_t GetTaskId() + { + static uint32_t taskId = 0; + return ++taskId; + } + private: + std::atomic status; + }; + +private: + bool Clear(uint32_t id); + void ExecuteWaitTasks(std::shared_ptr info, TaskStatus status = TS_RUN); + //-1 failed. 0 success,msg is not the team leader. 1 success,team leader + int32_t PushTask(SyncTaskFunc sync, AsyncTaskFunc aysnc, std::shared_ptr &info); + +private: + std::mutex taskQueueMutex_; + std::list> taskQueue_; +}; +} // namespace MiscServices +} // namespace OHOS +#endif // INPUTMETHOD_IMF_TASK_SEQUENCING_H \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp index 632c53c333691c7d806c2b368d9684d4a6e5687e..9cbd3bec8d68d3dcfb49469f43cfcab7edf692af 100644 --- a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp +++ b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp @@ -40,6 +40,7 @@ #include "system_ability_definition.h" #include "system_cmd_channel_stub.h" #include "input_method_tools.h" +#include "ffrt.h" namespace OHOS { namespace MiscServices { @@ -299,7 +300,7 @@ int32_t InputMethodController::IsValidTextConfig(const TextConfig &textConfig) return ErrorCode::NO_ERROR; } -int32_t InputMethodController::Attach(sptr listener, const AttachOptions &attachOptions, +int32_t InputMethodController::AttachInner(sptr listener, const AttachOptions &attachOptions, const TextConfig &textConfig, ClientType type) { IMSA_HILOGI("isShowKeyboard %{public}d.", attachOptions.isShowKeyboard); @@ -350,6 +351,54 @@ int32_t InputMethodController::Attach(sptr listener, cons return ErrorCode::NO_ERROR; } +int32_t InputMethodController::Attach(sptr listener, const AttachOptions &attachOptions, + const TextConfig &textConfig, ClientType type) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return AttachInner(listener, attachOptions, textConfig, type); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::AttachAsync(sptr listener, const AttachOptions &attachOptions, + const TextConfig &textConfig, ClientType type, AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [=]() -> void { + callback(AttachInner(listener, attachOptions, textConfig, type)); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::SubmitSyncTask(std::function work) +{ + SyncTaskFunc task = [this, work](uint32_t id) -> int32_t { + int32_t ret = work(); + taskSeq_.LeaveLine(id); + return ret; + }; + return taskSeq_.LineUp(task); +} + +int32_t InputMethodController::SubmitAsyncTask(std::function work, std::function callback) +{ + AsyncTaskFunc task = [work, callback, this](uint32_t id, bool waitTimeout) -> void { + ffrt::submit([id, waitTimeout, work, callback, this]() { + if (waitTimeout) { + callback(ErrorCode::ERROR_CLIENT_NULL_POINTER); + return; + } + work(); + taskSeq_.LeaveLine(id); + }); + }; + return taskSeq_.LineUp(task); +} + int32_t InputMethodController::ShowTextInputInner(const AttachOptions &attachOptions, ClientType type) { InputMethodSyncTrace tracer("IMC_ShowTextInput"); @@ -373,7 +422,7 @@ int32_t InputMethodController::ShowTextInputInner(const AttachOptions &attachOpt return ret; } -int32_t InputMethodController::HideTextInput() +int32_t InputMethodController::HideTextInputInner() { InputMethodSyncTrace tracer("IMC_HideTextInput"); if (!IsBound()) { @@ -386,7 +435,28 @@ int32_t InputMethodController::HideTextInput() return HideInput(clientInfo_.client); } -int32_t InputMethodController::HideCurrentInput() +int32_t InputMethodController::HideTextInput() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return HideTextInputInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::HideTextInputAsync(AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, callback]() -> void { + callback(HideTextInputInner()); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::HideCurrentInputInner() { InputMethodSyncTrace tracer("IMC_HideCurrentInput"); IMSA_HILOGD("InputMethodController::HideCurrentInput"); @@ -407,6 +477,27 @@ int32_t InputMethodController::HideCurrentInput() return proxy->HideCurrentInputDeprecated(); } +int32_t InputMethodController::HideCurrentInput() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return HideCurrentInputInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::HideCurrentInputAsync(AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, callback]() -> void { + callback(HideCurrentInputInner()); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::ShowCurrentInput() { InputMethodSyncTrace tracer("IMC_ShowCurrentInput"); @@ -429,6 +520,27 @@ int32_t InputMethodController::ShowCurrentInput() } int32_t InputMethodController::Close() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return CloseInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::CloseAsync(AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, callback]() -> void { + callback(CloseInner()); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::CloseInner() { if (IsBound()) { IMSA_HILOGI("start."); @@ -752,7 +864,7 @@ void InputMethodController::RestoreClientInfoInSaDied() } } -int32_t InputMethodController::DiscardTypingText() +int32_t InputMethodController::DiscardTypingTextInner() { if (!IsBound()) { IMSA_HILOGE("not bound."); @@ -766,7 +878,28 @@ int32_t InputMethodController::DiscardTypingText() return agent->DiscardTypingText(); } -int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo) +int32_t InputMethodController::DiscardTypingText() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return DiscardTypingTextInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::DiscardTypingTextAsync(AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, callback]() -> void { + callback(DiscardTypingTextInner()); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::OnCursorUpdateInner(CursorInfo cursorInfo) { if (!IsBound()) { IMSA_HILOGD("not bound."); @@ -809,7 +942,28 @@ int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo) return ErrorCode::NO_ERROR; } -int32_t InputMethodController::OnSelectionChange(std::u16string text, int start, int end) +int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this, cursorInfo]() -> int32_t { + return OnCursorUpdateInner(cursorInfo); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::OnCursorUpdateAsync(CursorInfo cursorInfo, AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, cursorInfo, callback]() -> void { + callback(OnCursorUpdateInner(cursorInfo)); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::OnSelectionChangeInner(std::u16string text, int start, int end) { if (!IsBound()) { IMSA_HILOGD("not bound."); @@ -845,7 +999,28 @@ int32_t InputMethodController::OnSelectionChange(std::u16string text, int start, return ErrorCode::NO_ERROR; } -int32_t InputMethodController::OnConfigurationChange(Configuration info) +int32_t InputMethodController::OnSelectionChange(std::u16string text, int start, int end) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this, text, start, end]() -> int32_t { + return OnSelectionChangeInner(text, start, end); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::OnSelectionChangeAsync(std::u16string text, int start, int end, AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, text, start, end, callback]() -> void { + callback(OnSelectionChangeInner(text, start, end)); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::OnConfigurationChangeInner(Configuration info) { if (!IsBound()) { IMSA_HILOGD("not bound."); @@ -885,6 +1060,27 @@ int32_t InputMethodController::OnConfigurationChange(Configuration info) return ErrorCode::NO_ERROR; } +int32_t InputMethodController::OnConfigurationChange(Configuration info) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this, info]() -> int32_t { + return OnConfigurationChangeInner(info); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::OnConfigurationChangeAsync(Configuration info, AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, info, callback]() -> void { + callback(OnConfigurationChangeInner(info)); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::GetLeft(int32_t length, std::u16string &text) { InputMethodSyncTrace tracer("IMC_GetForward"); @@ -1031,7 +1227,7 @@ int32_t InputMethodController::GetTextConfig(TextTotalConfig &config) return ErrorCode::NO_ERROR; } -int32_t InputMethodController::SetCallingWindow(uint32_t windowId) +int32_t InputMethodController::SetCallingWindowInner(uint32_t windowId) { if (!IsBound()) { IMSA_HILOGD("not bound."); @@ -1059,6 +1255,27 @@ int32_t InputMethodController::SetCallingWindow(uint32_t windowId) return ErrorCode::NO_ERROR; } +int32_t InputMethodController::SetCallingWindow(uint32_t windowId) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this, windowId]() -> int32_t { + return SetCallingWindowInner(windowId); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::SetCallingWindowAsync(uint32_t windowId, AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, windowId, callback]() -> void { + callback(SetCallingWindowInner(windowId)); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::ShowSoftKeyboardInner(ClientType type) { auto proxy = GetSystemAbilityProxy(); @@ -1075,7 +1292,7 @@ int32_t InputMethodController::ShowSoftKeyboardInner(ClientType type) return proxy->ShowCurrentInput(type); } -int32_t InputMethodController::HideSoftKeyboard() +int32_t InputMethodController::HideSoftKeyboardInner() { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1091,7 +1308,28 @@ int32_t InputMethodController::HideSoftKeyboard() return proxy->HideCurrentInput(); } -int32_t InputMethodController::StopInputSession() +int32_t InputMethodController::HideSoftKeyboard() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return HideSoftKeyboardInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::HideSoftKeyboardAsync(AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, callback]() -> void { + callback(HideSoftKeyboardInner()); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::StopInputSessionInner() { IMSA_HILOGI("start."); isEditable_.store(false); @@ -1103,6 +1341,27 @@ int32_t InputMethodController::StopInputSession() return proxy->StopInputSession(); } +int32_t InputMethodController::StopInputSession() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return StopInputSessionInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::StopInputSessionAsync(AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, callback]() -> void { + callback(StopInputSessionInner()); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::ShowOptionalInputMethod() { auto proxy = GetSystemAbilityProxy(); @@ -1623,7 +1882,7 @@ int32_t InputMethodController::FinishTextPreview() return ErrorCode::NO_ERROR; } -int32_t InputMethodController::SendMessage(const ArrayBuffer &arrayBuffer) +int32_t InputMethodController::SendMessageInner(const ArrayBuffer &arrayBuffer) { if (!IsBound()) { IMSA_HILOGE("not bound."); @@ -1645,6 +1904,27 @@ int32_t InputMethodController::SendMessage(const ArrayBuffer &arrayBuffer) return agent->SendMessage(arrayBuffer); } +int32_t InputMethodController::SendMessage(const ArrayBuffer &arrayBuffer) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this, arrayBuffer]() -> int32_t { + return SendMessageInner(arrayBuffer); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::SendMessageAsync(const ArrayBuffer &arrayBuffer, AsyncCallback callback) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, arrayBuffer, callback]() -> void { + callback(SendMessageInner(arrayBuffer)); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::RecvMessage(const ArrayBuffer &arrayBuffer) { if (!IsBound()) { @@ -1713,16 +1993,54 @@ int32_t InputMethodController::ShowTextInput(ClientType type) int32_t InputMethodController::ShowTextInput(const AttachOptions &attachOptions, ClientType type) { - auto ret = ShowTextInputInner(attachOptions, type); - ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT), ret, type); - return ret; + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this, attachOptions, type]() -> int32_t { + auto ret = ShowTextInputInner(attachOptions, type); + ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT), ret, type); + return ret; + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::ShowTextInputAsync(AsyncCallback callback, const AttachOptions &attachOptions, + ClientType type) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, attachOptions, type, callback]() -> int32_t { + auto ret = ShowTextInputInner(attachOptions, type); + ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT), ret, type); + callback(ret); + return ret; + }; + return SubmitAsyncTask(work, callback); } int32_t InputMethodController::ShowSoftKeyboard(ClientType type) { - auto ret = ShowSoftKeyboardInner(type); - ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT), ret, type); - return ret; + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this, type]() -> int32_t { + auto ret = ShowSoftKeyboardInner(type); + ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT), ret, type); + return ret; + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::ShowSoftKeyboardAsync(AsyncCallback callback, ClientType type) +{ + if (callback == nullptr) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + IMSA_HILOGD("%{public}s async.", __FUNCTION__); + auto work = [this, type, callback]() -> void { + auto ret = ShowSoftKeyboardInner(type); + ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT), ret, type); + callback(ret); + }; + return SubmitAsyncTask(work, callback); } void InputMethodController::ReportClientShow(int32_t eventCode, int32_t errCode, ClientType type) diff --git a/frameworks/native/inputmethod_controller/src/task_sequencing.cpp b/frameworks/native/inputmethod_controller/src/task_sequencing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2f61f7e9622e1a22bc7fb8b96c3e1b53bc3efc7 --- /dev/null +++ b/frameworks/native/inputmethod_controller/src/task_sequencing.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2025 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 "global.h" +#include "task_sequencing.h" +#include + +namespace OHOS { +namespace MiscServices { +constexpr uint32_t SYNC_MAIN_THREAD_TIMEOUT = 1000; +constexpr uint32_t SYNC_NON_MAIN_THREAD_TIMEOUT = 2000; +constexpr std::size_t MAX_MSG_NUMBER = 1000; + +int32_t TaskSequencing::LineUp(SyncTaskFunc sync) +{ + IMSA_HILOGD("sync run"); + if (sync == nullptr) { + IMSA_HILOGE("parameter is empty"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + std::shared_ptr info = nullptr; + int ret = PushTask(sync, nullptr, info); + if (ret == -1) { + IMSA_HILOGE("sync queue full"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + if (ret == 0) { + uint32_t sync_timeout = SYNC_NON_MAIN_THREAD_TIMEOUT; + std::unique_lock lock(info->taskMutex); + if (info->isMainThread) { + sync_timeout = SYNC_MAIN_THREAD_TIMEOUT; + } + std::cv_status status = info->cv->wait_for(lock, std::chrono::milliseconds(sync_timeout)); + if (status == std::cv_status::timeout) { + if (!Clear(info->id)) { + IMSA_HILOGW("not cleared to message id:%{public}u", info->id); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + } + } + + if (info->GetStatus() != TS_WAIT) { + IMSA_HILOGW("sync current state is not TS_WAIT id:%{public}u", info->id); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + info->SetStatus(TS_RUN); + return info->sync(info->id); +} + +int32_t TaskSequencing::LineUp(AsyncTaskFunc async) +{ + IMSA_HILOGD("async run"); + if (async == nullptr) { + IMSA_HILOGE("parameter is empty"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + std::shared_ptr info = nullptr; + int ret = PushTask(nullptr, async, info); + if (ret == -1) { + IMSA_HILOGW("async queue full"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + if (ret == 0) { + return ErrorCode::NO_ERROR; + } + if (info->GetStatus() != TS_WAIT) { + IMSA_HILOGW("async current state is not TS_WAIT id:%{public}u", info->id); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + info->SetStatus(TS_RUN); + info->async(info->id, false); + return ErrorCode::NO_ERROR; +} + +void TaskSequencing::LeaveLine(uint32_t id) +{ + std::unique_lock lock(taskQueueMutex_); + if (taskQueue_.empty() || taskQueue_.front()->id != id) { + IMSA_HILOGW("queue is empty or id:%{public}u not equal", id); + return; + } + taskQueue_.pop_front(); + if (taskQueue_.empty()) { + return; + } + ExecuteWaitTasks(taskQueue_.front()); +} + +bool TaskSequencing::Clear(uint32_t id) +{ + IMSA_HILOGW("start clear id:%{public}u", id); + std::unique_lock lock(taskQueueMutex_); + if (taskQueue_.empty()) { + return false; + } + auto it = std::find_if(taskQueue_.begin(), taskQueue_.end(), + [id](const std::shared_ptr &info) { return info->id == id; }); + if (it == taskQueue_.end()) { + return false; + } + + std::shared_ptr info = taskQueue_.front(); + while (info->id != id) { + if (info->GetStatus() == TS_WAIT) { + ExecuteWaitTasks(info, TS_TERMINATE); + } + taskQueue_.pop_front(); + if (taskQueue_.empty()) { + break; + } + info = taskQueue_.front(); + } + return true; +} + +void TaskSequencing::ExecuteWaitTasks(std::shared_ptr info, TaskStatus status) +{ + info->SetStatus(status); + if (info->async) { + info->async(info->id, info->GetStatus() == TS_TERMINATE); + } else if (info->cv) { + info->cv->notify_one(); + } +} + +int32_t TaskSequencing::PushTask(SyncTaskFunc sync, AsyncTaskFunc async, std::shared_ptr &info) +{ + bool immediateExec = false; + { + std::unique_lock lock(taskQueueMutex_); + if (taskQueue_.size() > MAX_MSG_NUMBER) { + IMSA_HILOGW("queue full"); + return -1; + } + immediateExec = taskQueue_.empty(); + info = std::make_shared(TaskInfo::GetTaskId(), sync, async); + taskQueue_.push_back(info); + } + IMSA_HILOGD("push task id:%{public}u", info->id); + return immediateExec ? 1 : 0; +} +} // namespace MiscServices +} // namespace OHOS diff --git a/interfaces/inner_api/inputmethod_controller/BUILD.gn b/interfaces/inner_api/inputmethod_controller/BUILD.gn index 073fcbae3996e067428861ef40d0cfc3f569fe1e..6a5893ff3b9be155c2696fdec6bc0ddf26192d7d 100644 --- a/interfaces/inner_api/inputmethod_controller/BUILD.gn +++ b/interfaces/inner_api/inputmethod_controller/BUILD.gn @@ -170,6 +170,7 @@ ohos_shared_library("inputmethod_client") { "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_method_utils.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/keyevent_consumer_service_impl.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/system_cmd_channel_service_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/task_sequencing.cpp", ] cflags_cc = [ @@ -218,6 +219,7 @@ ohos_shared_library("inputmethod_client") { "cJSON:cjson", "c_utils:utils", "eventhandler:libeventhandler", + "ffrt:libffrt", "hilog:libhilog", "input:libmmi-client", "ipc:ipc_single", @@ -268,6 +270,7 @@ ohos_static_library("inputmethod_client_static") { "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_method_utils.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/keyevent_consumer_service_impl.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/system_cmd_channel_service_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/task_sequencing.cpp", ] public_configs = [ ":inputmethod_client_native_public_config" ] @@ -290,6 +293,7 @@ ohos_static_library("inputmethod_client_static") { "cJSON:cjson", "c_utils:utils", "eventhandler:libeventhandler", + "ffrt:libffrt", "hilog:libhilog", "input:libmmi-client", "ipc:ipc_single", @@ -336,6 +340,7 @@ ohos_static_library("inputmethod_client_fuzz_static") { "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_method_utils.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/keyevent_consumer_service_impl.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/system_cmd_channel_service_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/task_sequencing.cpp", ] public_configs = [ ":inputmethod_client_native_public_config" ] @@ -358,6 +363,7 @@ ohos_static_library("inputmethod_client_fuzz_static") { "cJSON:cjson", "c_utils:utils", "eventhandler:libeventhandler", + "ffrt:libffrt", "hilog:libhilog", "input:libmmi-client", "ipc:ipc_single", diff --git a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h index b6a613968442d66f36bb0d6e5bf69d0a3ea80355..cf6763ab8f921a46a76e1f5c449c519916794517 100644 --- a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h +++ b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h @@ -44,6 +44,7 @@ #include "panel_info.h" #include "private_command_interface.h" #include "visibility.h" +#include "task_sequencing.h" namespace OHOS { namespace MiscServices { @@ -146,6 +147,7 @@ private: using PrivateDataValue = std::variant; using KeyEventCallback = std::function &keyEvent, bool isConsumed)>; using WindowScaleCallback = std::function; +using AsyncCallback = std::function; class InputMethodController : public RefBase, public PrivateCommandInterface { public: /** @@ -218,12 +220,10 @@ public: */ IMF_API int32_t Attach(sptr listener, bool isShowKeyboard, const TextConfig &textConfig, ClientType type = ClientType::INNER_KIT); - /** * @brief Set listener and bind IMSA with given states and textConfig. * - * This function is used to set listener and bind IMSA. - * Show soft keyboard when state is true, and customized attribute. + * Implement Attach interface, used for asynchronous calls * * @param listener Indicates the listener in order to manipulate text. * @param attachOptions Indicates the attachOptions, if you want to show soft keyboard, @@ -236,6 +236,23 @@ public: */ IMF_API int32_t Attach(sptr listener, const AttachOptions &attachOptions, const TextConfig &textConfig, ClientType type = ClientType::INNER_KIT); + /** + * @brief Asynchronous set listener and bind IMSA with given states and textConfig. + * + * Implement Attach interface, used for asynchronous calls + * + * @param listener Indicates the listener in order to manipulate text. + * @param attachOptions Indicates the attachOptions, if you want to show soft keyboard, + * please pass in true. + * @param textConfig Indicates the textConfig, such as input attribute, cursorInfo, range of + * text selection,windowId. + * @param type Indicates the type of caller. + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 15 + */ + IMF_API int32_t AttachAsync(sptr listener, const AttachOptions &attachOptions, + const TextConfig &textConfig, ClientType type, AsyncCallback callback); /** * @brief Show soft keyboard. * @@ -256,6 +273,18 @@ public: * @since 15 */ IMF_API int32_t ShowTextInput(const AttachOptions &attachOptions, ClientType type = ClientType::INNER_KIT); + /** + * @brief Asynchronous show soft keyboard. + * + * This function is used to show soft keyboard of current client. + * + * @param attachOptions Indicates the attachOptions, such as requestKeyboardReason + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 15 + */ + IMF_API int32_t ShowTextInputAsync(AsyncCallback callback, const AttachOptions &attachOptions, + ClientType type = ClientType::INNER_KIT); /** * @brief Hide soft keyboard. * @@ -266,6 +295,17 @@ public: */ IMF_API int32_t HideTextInput(); + /** + * @brief Asynchronous hide soft keyboard. + * + * This function is used to hide soft keyboard of current client, and keep binding. + * + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 6 + */ + IMF_API int32_t HideTextInputAsync(AsyncCallback callback); + /** * @brief Hide current input method, clear text listener and unbind IMSA. * @@ -277,6 +317,18 @@ public: */ IMF_API int32_t Close(); + /** + * @brief Asynchronous hide current input method, clear text listener and unbind IMSA. + * + * This function is used to stop input, whick will set listener to nullptr, + * hide current soft keyboard and unbind IMSA. + * + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 15 + */ + IMF_API int32_t CloseAsync(AsyncCallback callback); + /** * @brief A callback function when the cursor changes. * @@ -288,6 +340,17 @@ public: */ IMF_API int32_t OnCursorUpdate(CursorInfo cursorInfo); + /** + * @brief Asynchronous callback function when the cursor changes. + * + * This function is the callback when the cursor changes. + * + * @param cursorInfo Indicates the information of current cursor changes. + * @return Returns 0 for success, others for failure. + * @since 15 + */ + IMF_API int32_t OnCursorUpdateAsync(CursorInfo cursorInfo, AsyncCallback callback); + /** * @brief Discard the typing text. * @@ -296,6 +359,15 @@ public: */ IMF_API int32_t DiscardTypingText(); + /** + * @brief Asynchronous discard the typing text. + * + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 16 + */ + IMF_API int32_t DiscardTypingTextAsync(AsyncCallback callback); + /** * @brief A callback function when the cursor changes. * @@ -309,6 +381,20 @@ public: */ IMF_API int32_t OnSelectionChange(std::u16string text, int start, int end); + /** + * @brief Asynchronous callback function when the cursor changes. + * + * This function is the callback when the cursor changes. + * + * @param text Indicates the currently selected text. + * @param start Indicates the coordinates of the current start. + * @param end Indicates the coordinates of the current end. + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 15 + */ + IMF_API int32_t OnSelectionChangeAsync(std::u16string text, int start, int end, AsyncCallback callback); + /** * @brief Changing the configuration of soft keyboard. * @@ -319,6 +405,18 @@ public: * @since 6 */ IMF_API int32_t OnConfigurationChange(Configuration info); + + /** + * @brief Asynchronous changing the configuration of soft keyboard. + * + * This function is used to change the configuration of soft keyboard. + * + * @param info Indicates the current configuration. + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 6 + */ + IMF_API int32_t OnConfigurationChangeAsync(Configuration info, AsyncCallback callback); IMF_API void SetControllerListener(std::shared_ptr controllerListener); /** @@ -472,6 +570,18 @@ public: */ IMF_API int32_t SetCallingWindow(uint32_t windowId); + /** + * @brief Asynchronous set calling window id. + * + * This function is used to set calling window id to input method. + * + * @param windowId Indicates the window id. + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 6 + */ + IMF_API int32_t SetCallingWindowAsync(uint32_t windowId, AsyncCallback callback); + /** * @brief Switch input method or subtype. * @@ -495,6 +605,18 @@ public: */ IMF_API int32_t ShowSoftKeyboard(ClientType type = ClientType::INNER_KIT); + /** + * @brief Asynchronous show soft keyboard. + * + * This function is used to show soft keyboard of current client. + * + * @param type Indicates the type of caller. + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 6 + */ + IMF_API int32_t ShowSoftKeyboardAsync(AsyncCallback callback, ClientType type = ClientType::INNER_KIT); + /** * @brief Hide soft keyboard. * @@ -505,6 +627,17 @@ public: */ IMF_API int32_t HideSoftKeyboard(); + /** + * @brief Hide soft keyboard. + * + * This function is used to hide soft keyboard of current client, and keep binding. + * + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 6 + */ + IMF_API int32_t HideSoftKeyboardAsync(AsyncCallback callback); + /** * @brief Stop current input session. * @@ -515,6 +648,17 @@ public: */ IMF_API int32_t StopInputSession(); + /** + * @brief Stop current input session. + * + * This function is used to stop current input session. + * + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 6 + */ + IMF_API int32_t StopInputSessionAsync(AsyncCallback callback); + /** * @brief Show input method setting extension dialog. * @@ -549,6 +693,17 @@ public: */ IMF_API int32_t HideCurrentInput(); + /** + * @brief Hide soft keyboard. + * + * This function is used to hide soft keyboard of current client, and keep binding. + * + * @return Returns 0 for success, others for failure. + * @deprecated since 9 + * @since 6 + */ + IMF_API int32_t HideCurrentInputAsync(AsyncCallback callback); + /** * @brief Request to show input method. * @@ -917,6 +1072,19 @@ public: * @since 16 */ IMF_API int32_t SendMessage(const ArrayBuffer &arrayBuffer); + + /** + * @brief Asynchronous send ArrayBuffer message to ime. + * + * This function is used to Send ArrayBuffer message to ime. + * + * @param arrayBuffer Indicates the ArrayBuffer message that will be send to the ime. + * The member msgId limit 256B, and member msgParam limit 128KB. + * @param callback Indicates the callback interface, return value execution code. + * @return Returns 0 for success, others for failure. + * @since 16 + */ + IMF_API int32_t SendMessageAsync(const ArrayBuffer &arrayBuffer, AsyncCallback callback); int32_t RecvMessage(const ArrayBuffer &arrayBuffer); /** @@ -1005,9 +1173,24 @@ private: int32_t SetPreviewTextInner(const std::string &text, const Range &range); int32_t ShowTextInputInner(const AttachOptions &attachOptions, ClientType type); int32_t ShowSoftKeyboardInner(ClientType type); + int32_t AttachInner(sptr listener, const AttachOptions &attachOptions, + const TextConfig &textConfig, ClientType type = ClientType::INNER_KIT); + int32_t CloseInner(); + int32_t HideTextInputInner(); + int32_t DiscardTypingTextInner(); + int32_t SetCallingWindowInner(uint32_t windowId); + int32_t OnCursorUpdateInner(CursorInfo cursorInfo); + int32_t OnSelectionChangeInner(std::u16string text, int start, int end); + int32_t OnConfigurationChangeInner(Configuration info); + int32_t HideSoftKeyboardInner(); + int32_t HideCurrentInputInner(); + int32_t StopInputSessionInner(); + int32_t SendMessageInner(const ArrayBuffer &arrayBuffer); void ReportClientShow(int32_t eventCode, int32_t errCode, ClientType type); void GetWindowScaleCoordinate(int32_t& x, int32_t& y, uint32_t windowId); int32_t ResponseDataChannel(uint64_t msgId, int32_t code, const ResponseData &data); + int32_t SubmitSyncTask(std::function work); + int32_t SubmitAsyncTask(std::function work, std::function callback); void CalibrateImmersiveParam(InputAttribute &inputAttribute); friend class InputDataChannelServiceImpl; @@ -1065,6 +1248,7 @@ private: static constexpr int32_t MAX_WAIT_TIME = 5000; BlockQueue keyEventQueue_{ MAX_WAIT_TIME }; + TaskSequencing taskSeq_; std::mutex msgHandlerMutex_; std::shared_ptr msgHandler_ = nullptr; std::mutex bindImeInfoLock_; diff --git a/services/include/input_control_channel_service_impl.h b/services/include/input_control_channel_service_impl.h index 8fbc6e6e4af8b0e367bd12e010776e0598c38eb5..0e85f6b2632848a9852cb59aa90f5c4624b122c4 100644 --- a/services/include/input_control_channel_service_impl.h +++ b/services/include/input_control_channel_service_impl.h @@ -22,6 +22,7 @@ #include "input_control_channel_stub.h" #include "iremote_object.h" #include "inputmethod_message_handler.h" +#include "variant_util.h" namespace OHOS { namespace MiscServices { @@ -34,8 +35,12 @@ public: explicit InputControlChannelServiceImpl(int32_t userId); virtual ~InputControlChannelServiceImpl(); ErrCode HideKeyboardSelf() override; + ErrCode ToCoreOnConnectSystemCmd(int64_t id, int32_t code, const sptr &agent) override; + ErrCode ToCoreIsEnable(int64_t id, int32_t code, bool resultValue) override; + ErrCode ToCoreIsPanelShown(int64_t id, int32_t code, bool isShown) override; private: + void ContrlToCoreResponse(int64_t id, int32_t code, ContrlToCoreMsgParam &value); int32_t userId_; }; } // namespace MiscServices diff --git a/services/include/input_method_system_ability.h b/services/include/input_method_system_ability.h index 88d3184107533e2507d0a3e2af3c34df6da9bdcc..d687bf573db1ae1a87b0135bcfa6dc8842001d43 100644 --- a/services/include/input_method_system_ability.h +++ b/services/include/input_method_system_ability.h @@ -25,6 +25,7 @@ #include "input_method_types.h" #include "user_session_manager.h" #include "input_type_manager.h" +#include "variant_util.h" namespace OHOS { namespace MiscServices { diff --git a/services/include/peruser_session.h b/services/include/peruser_session.h index 29c619691101820a7ca580235fbeef1f1b3ce060..ce0fb4fadaa5778f28d2826c4517e26dd00b18ca 100644 --- a/services/include/peruser_session.h +++ b/services/include/peruser_session.h @@ -17,6 +17,7 @@ #define SERVICES_INCLUDE_PERUSER_SESSION_H #include +#include #include "block_queue.h" #include "client_group.h" @@ -28,6 +29,7 @@ #include "inputmethod_message_handler.h" #include "inputmethod_sysevent.h" #include "want.h" +#include "variant_util.h" #include "ime_state_manager.h" namespace OHOS { @@ -148,6 +150,7 @@ public: int32_t SpecialSendPrivateData(const std::unordered_map &privateCommand); uint64_t GetDisplayGroupId(uint64_t displayId); bool IsDefaultDisplayGroup(uint64_t displayId); + void ContrlToCoreResponse(uint32_t id, int32_t code, ContrlToCoreMsgParam &value); bool IsNumkeyAutoInputApp(const std::string &bundleName); std::pair GetCurrentInputPattern(); @@ -278,6 +281,21 @@ private: std::atomic agentDisplayId_{ DEFAULT_DISPLAY_ID }; std::mutex clientGroupLock_{}; std::unordered_map> clientGroupMap_; + + struct ContrlToCoreMsg { + uint32_t msgId = 0; + int32_t code = 0; + std::condition_variable cv; + ContrlToCoreMsgParam value; + static uint32_t GetId() + { + static uint32_t id = 0; + return ++id; + } + }; + int32_t AsyncRequest(std::function work, ContrlToCoreMsgParam &value); + std::mutex msgMutex_; + std::unordered_map> msgQueue_; }; } // namespace MiscServices } // namespace OHOS diff --git a/services/src/input_control_channel_service_impl.cpp b/services/src/input_control_channel_service_impl.cpp index 49e65de28bb5490d9ff40faec4c868f4185a8a2a..bf4bcf861f6240e42ba264b3a91187c5743e88fe 100644 --- a/services/src/input_control_channel_service_impl.cpp +++ b/services/src/input_control_channel_service_impl.cpp @@ -19,6 +19,7 @@ #include "inputmethod_message_handler.h" #include "message_parcel.h" #include "os_account_adapter.h" +#include "user_session_manager.h" namespace OHOS { namespace MiscServices { @@ -48,5 +49,42 @@ ErrCode InputControlChannelServiceImpl::HideKeyboardSelf() MessageHandler::Instance()->SendMessage(msg); return ERR_OK; } + +ErrCode InputControlChannelServiceImpl::ToCoreOnConnectSystemCmd( + int64_t id, int32_t code, const sptr &agent) +{ + //InputMethodSystemAbility ContrlToCoreResponse + ContrlToCoreMsgParam value = agent; + ContrlToCoreResponse(id, code, value); + return ERR_OK; +} + +ErrCode InputControlChannelServiceImpl::ToCoreIsEnable(int64_t id, int32_t code, bool resultValue) +{ + ContrlToCoreMsgParam value = resultValue; + ContrlToCoreResponse(id, code, value); + return ERR_OK; +} + +ErrCode InputControlChannelServiceImpl::ToCoreIsPanelShown(int64_t id, int32_t code, bool isShown) +{ + ContrlToCoreMsgParam value = isShown; + ContrlToCoreResponse(id, code, value); + return ERR_OK; +} + +void InputControlChannelServiceImpl::ContrlToCoreResponse(int64_t id, int32_t code, ContrlToCoreMsgParam &value) +{ + const uint32_t OFFSET = 32; + int32_t userId = static_cast(id >> OFFSET); + uint32_t msgId = static_cast(id & std::numeric_limits::max()); + IMSA_HILOGD("Response userId: %{public}d msgId: %{public}u code: %{public}d", userId, msgId, code); + auto session = UserSessionManager::GetInstance().GetUserSession(userId); + if (session == nullptr) { + IMSA_HILOGE("UserId: %{public}d session is nullptr!", userId); + return; + } + session->ContrlToCoreResponse(msgId, code, value); +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index 685f09b7e8081bf9c9a983bab9d8f2f44989a348..4fcaa4eecdc6af617c39f26341c9587d98a11aa0 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -16,6 +16,7 @@ #include "input_method_system_ability.h" #include +#include #include "securec.h" #include "unordered_map" diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp index 8d64d2f5dcb336c8c7216f5a47d9f2b7af72052d..82365c83e925cc845d099d802d68010bf1ab5ed7 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -509,11 +509,19 @@ void PerUserSession::DeactivateClient(const sptr &client) bool PerUserSession::IsProxyImeEnable() { auto data = GetReadyImeData(ImeType::PROXY_IME); - bool ret = false; if (data == nullptr || data->core == nullptr) { return false; } - data->core->IsEnable(ret); + + bool ret = false; + ContrlToCoreMsgParam value; + int32_t code = AsyncRequest([data](int64_t id) { return data->core->IsEnable(id);}, value); + if (code != ErrorCode::NO_ERROR) { + return ret; + } + if (!VariantUtil::GetContrlToCoreValue(value, ret)) { + IMSA_HILOGE("GetContrlToCoreValue failed"); + } return ret; } @@ -1443,8 +1451,21 @@ int32_t PerUserSession::IsPanelShown(const PanelInfo &panelInfo, bool &isShown) IMSA_HILOGE("ime not started!"); return ErrorCode::ERROR_IME_NOT_STARTED; } - return RequestIme(ime, RequestType::NORMAL, - [&ime, &panelInfo, &isShown] { return ime->core->IsPanelShown(panelInfo, isShown); }); + + auto exec = [&ime, &panelInfo, &isShown, this]() ->int32_t { + ContrlToCoreMsgParam value; + int32_t ret = AsyncRequest( + [&ime, &panelInfo, &isShown](int64_t id) { return ime->core->IsPanelShown(id, panelInfo); }, value); + if (ret != ErrorCode::NO_ERROR) { + return ret; + } + if (VariantUtil::GetContrlToCoreValue(value, isShown)) { + return ret; + } + IMSA_HILOGE("GetContrlToCoreValue failed"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + }; + return RequestIme(ime, RequestType::NORMAL, exec); } bool PerUserSession::CheckSecurityMode() @@ -1483,8 +1504,20 @@ int32_t PerUserSession::OnConnectSystemCmd(const sptr &channel, s IMSA_HILOGE("ime: %{public}d is not exist!", ImeType::IME); return ErrorCode::ERROR_IME_NOT_STARTED; } - auto ret = RequestIme(data, RequestType::NORMAL, - [&data, &channel, &agent] { return data->core->OnConnectSystemCmd(channel, agent); }); + auto exec = [&data, &channel, &agent, this]() ->int32_t { + ContrlToCoreMsgParam value; + int32_t ret = AsyncRequest( + [&data, &channel, &agent](int64_t id) { return data->core->OnConnectSystemCmd(id, channel); }, value); + if (ret != ErrorCode::NO_ERROR) { + return ret; + } + if (VariantUtil::GetContrlToCoreValue(value, agent)) { + return ret; + } + IMSA_HILOGE("GetContrlToCoreValue failed"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + }; + auto ret = RequestIme(data, RequestType::NORMAL, exec); IMSA_HILOGD("on connect systemCmd, ret: %{public}d.", ret); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("bind failed, ret: %{public}d!", ret); @@ -1493,6 +1526,47 @@ int32_t PerUserSession::OnConnectSystemCmd(const sptr &channel, s return ErrorCode::NO_ERROR; } +int32_t PerUserSession::AsyncRequest(std::function work, ContrlToCoreMsgParam &value) +{ + const uint32_t OFFSET = 32; + const uint32_t WAIT_TIMEOUT = 600; + int32_t ret = 0; + std::shared_ptr msg = std::make_shared(); + { + std::unique_lock insertLock(msgMutex_); + msg->msgId = ContrlToCoreMsg::GetId(); + msgQueue_.insert(std::make_pair(msg->msgId, msg)); + } + int64_t id = static_cast(userId_) << OFFSET; + id |= static_cast(msg->msgId); + IMSA_HILOGD("async request userid: %{public}d msgId: %{public}u id: %{public}" PRIu64 "", userId_, msg->msgId, id); + ret = work(id); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGW("task exec filed! userid: %{public}d msgId: %{public}u", userId_, msg->msgId); + msgQueue_.erase(msg->msgId); + return ret; + } + std::unique_lock lock(msgMutex_); + do { + if (std::cv_status::timeout == msg->cv.wait_for(lock, std::chrono::milliseconds(WAIT_TIMEOUT))) { + ret = ErrorCode::ERROR_CLIENT_NULL_POINTER; + IMSA_HILOGW("async task timeout"); + break; + } + auto it = msgQueue_.find(msg->msgId); + if (it == msgQueue_.end()) { + ret = ErrorCode::ERROR_CLIENT_NULL_POINTER; + break; + } + ret = it->second->code; + if (ret == ErrorCode::NO_ERROR) { + value = it->second->value; + } + } while (false); + msgQueue_.erase(msg->msgId); + return ret; +} + bool PerUserSession::WaitForCurrentImeStop() { IMSA_HILOGI("start."); @@ -2261,6 +2335,21 @@ void PerUserSession::ClearRequestKeyboardReason(std::shared_ptr clientInfo->requestKeyboardReason = RequestKeyboardReason::NONE; } +void PerUserSession::ContrlToCoreResponse(uint32_t id, int32_t code, ContrlToCoreMsgParam &value) +{ + std::unique_lock lock(msgMutex_); + auto it = msgQueue_.find(id); + if (it == msgQueue_.end()) { + IMSA_HILOGW("not found id: %{public}u!", id); + return; + } + it->second->code = code; + if (code == ErrorCode::NO_ERROR) { + it->second->value = value; + } + it->second->cv.notify_one(); +} + bool PerUserSession::IsNumkeyAutoInputApp(const std::string &bundleName) { return NumkeyAppsManager::GetInstance().NeedAutoNumKeyInput(userId_, bundleName); diff --git a/test/fuzztest/controlchannelstub_fuzzer/BUILD.gn b/test/fuzztest/controlchannelstub_fuzzer/BUILD.gn index 0ee0423fdac6c05c4f5ef67fae3a3fb630895e6e..cc1b2b6fc8f4103175214f603d01cf1699207e23 100644 --- a/test/fuzztest/controlchannelstub_fuzzer/BUILD.gn +++ b/test/fuzztest/controlchannelstub_fuzzer/BUILD.gn @@ -42,7 +42,10 @@ ohos_fuzztest("ControlChannelStubFuzzTest") { deps = [ "${inputmethod_path}/services:inputmethod_service_static" ] external_deps = [ + "ability_base:want", "c_utils:utils", + "data_share:datashare_common", + "data_share:datashare_consumer", "hilog:libhilog", "input:libmmi-client", "ipc:ipc_single", diff --git a/test/unittest/cpp_test/BUILD.gn b/test/unittest/cpp_test/BUILD.gn index c9f8858c87f57d156c452277c336f91799740377..bc1486ba5f98d0ba51ddea1116b058d657fc9433 100644 --- a/test/unittest/cpp_test/BUILD.gn +++ b/test/unittest/cpp_test/BUILD.gn @@ -561,6 +561,7 @@ ohos_unittest("ITypesUtilTest") { "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:input_method_agent_proxy", "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:input_method_agent_stub", "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static", + "${inputmethod_path}/services/adapter/settings_data_provider:settings_data_static", "${inputmethod_path}/test/common:inputmethod_test_common", "${inputmethod_path}/test/unittest/cpp_test/common:inputmethod_tdd_util", ] @@ -571,7 +572,10 @@ ohos_unittest("ITypesUtilTest") { "ability_runtime:ability_manager", "ability_runtime:runtime", "bundle_framework:appexecfwk_base", + "cJSON:cjson", "c_utils:utils", + "data_share:datashare_common", + "data_share:datashare_consumer", "googletest:gtest_main", "hilog:libhilog", "image_framework:image_native", @@ -1490,8 +1494,9 @@ ohos_unittest("InputMethodManagerCommandTest") { ] deps = [ + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client", "${inputmethod_path}/test/unittest/cpp_test/common:inputmethod_tdd_util", - "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client" ] + ] external_deps = [ "bundle_framework:appexecfwk_core",