diff --git a/common/include/variant_util.h b/common/include/variant_util.h index 347ba8da8e10edb8bb84add3ef6745411b54d321..aa0182a8b858dc4da5dc71af1fe572cf57777dc8 100644 --- a/common/include/variant_util.h +++ b/common/include/variant_util.h @@ -21,6 +21,7 @@ #include "global.h" #include "input_client_info.h" #include "input_method_utils.h" +#include "imf_event_notification.h" namespace OHOS { namespace MiscServices { class VariantUtil { @@ -45,6 +46,16 @@ public: output = std::get(input); return true; } + + template + static bool GetContrlToCoreValue(NotificationValue &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..979a60c407f85c43512acaf9252b597bcf61eebb --- /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" +#include +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 sharedMutex = std::make_shared(); + auto callback = [ctxt, completeFunc, errMsg, handler, sharedMutex](int32_t code) -> void { + std::lock_guard lock(*sharedMutex); + 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); + }; + napi_send_event(env, task, napi_eprio_high); + }; + 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 1a7e2ad84b8f0d34ba7cb79aeddbb76a0b7755d1..80b974a5b99f35da8a0530434e49fcb28c1b25d9 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 fb9c0fb16c42728c90c506a18b9cfbf50fac5941..2bcf04946d8d18e63f7f51c7196a4101da9d0b91 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp @@ -1817,6 +1817,48 @@ 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) +{ + IMSA_HILOGI("ldp ReplyIsEnable id: %{public}" PRIu64 " code: %{public}d", id, code); + auto controlChannel = GetInputControlChannel(); + if (controlChannel == nullptr) { + IMSA_HILOGE("ldp controlChannel is nullptr"); + return; + } + int32_t ret = controlChannel->ToCoreIsEnable(id, code, enbale); + if (ret != ERR_OK) { + IMSA_HILOGE("ldp ToCoreIsEnable code: %{public}d", ret); + } +} + +void InputMethodAbility::ReplyIsPanelShown(int64_t id, int32_t code, bool &isShown) +{ + IMSA_HILOGI("ldp ReplyIsPanelShown id: %{public}" PRIu64 " code: %{public}d", id, code); + auto controlChannel = GetInputControlChannel(); + if (controlChannel == nullptr) { + IMSA_HILOGE("ldp controlChannel is nullptr"); + return; + } + int32_t ret = controlChannel->ToCoreIsPanelShown(id, code, isShown); + if (ret != ERR_OK) { + IMSA_HILOGE("ldp ToCoreIsPanelShown code: %{public}d", ret); + } +} + +void InputMethodAbility::ReplyOnConnectSystemCmd(int64_t id, int32_t code, const sptr &agent) +{ + IMSA_HILOGI("ldp ReplyOnConnectSystemCmd id: %{public}" PRIu64 " code: %{public}d", id, code); + auto controlChannel = GetInputControlChannel(); + if (controlChannel == nullptr) { + IMSA_HILOGE("ldp controlChannel is nullptr"); + return; + } + int32_t ret = controlChannel->ToCoreOnConnectSystemCmd(id, code, agent); + if (ret != ERR_OK) { + IMSA_HILOGE("ldp 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..bbc430fe0063ce3edee3e5ce11246f3fcebab0aa 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,13 @@ 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); + IMSA_HILOGI("ldp OnConnectSystemCmd id: %{public}" PRIu64 " code: %{public}d", id, code); + InputMethodAbility::GetInstance().ReplyOnConnectSystemCmd(id, code, agent); + return code; } ErrCode InputMethodCoreServiceImpl::StartInput(const InputClientInfoInner &clientInfoInner, bool isBindFromClient) @@ -103,15 +106,21 @@ 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(); + IMSA_HILOGI("ldp IsEnable id: %{public}" PRIu64 " code: %{public}d", id, resultValue); + 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); + IMSA_HILOGI("ldp IsPanelShown id: %{public}" PRIu64 " code: %{public}d", id, code); + InputMethodAbility::GetInstance().ReplyIsPanelShown(id, code, isShown); + return code; } ErrCode InputMethodCoreServiceImpl::OnClientInactive(const sptr &channel) @@ -132,6 +141,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..337971e1b42d6132a06e57e2592c6cc249ccb833 --- /dev/null +++ b/frameworks/native/inputmethod_controller/include/task_sequencing.h @@ -0,0 +1,112 @@ +/* + * 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" + +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 == nullptr) { + IMSA_HILOGW("mainEventRunner is nullptr"); + } + auto Current = AppExecFwk::EventHandler::Current(); + if (Current == nullptr) { + IMSA_HILOGW("Current is nullptr"); + } + if (Current != nullptr && Current->GetEventRunner() == nullptr) { + IMSA_HILOGW("GetEventRunner is nullptr"); + } + if (mainEventRunner != nullptr && Current != nullptr && Current->GetEventRunner() != nullptr) { + 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); + //-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); + std::shared_ptr CreateCv(); + std::shared_ptr GetCv(); + void DeleteCv(); + void HandleRunStateTimeout(std::shared_ptr runCv, uint32_t runId); + +private: + std::mutex taskQueueMutex_; + std::list> taskQueue_; + std::mutex timeoutRunMutex_; + std::shared_ptr timeoutRunCv_ = nullptr; +}; +} // 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..2aa2355dd60c7507e4c1d689a927260ebc5ddd2d 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 { @@ -119,8 +120,12 @@ int32_t InputMethodController::UpdateListenEventFlag(uint32_t finalEventFlag, ui void InputMethodController::SetControllerListener(std::shared_ptr controllerListener) { - IMSA_HILOGD("InputMethodController run in"); - controllerListener_ = std::move(controllerListener); + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this, controllerListener]() -> int32_t { + controllerListener_ = std::move(controllerListener); + return ErrorCode::NO_ERROR; + }; + SubmitSyncTask(work); } int32_t InputMethodController::Initialize() @@ -299,7 +304,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 +355,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 = [=]() -> 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 = [=]() -> int32_t { + return 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; + } + callback(work()); + taskSeq_.LeaveLine(id); + }); + }; + return taskSeq_.LineUp(task); +} + int32_t InputMethodController::ShowTextInputInner(const AttachOptions &attachOptions, ClientType type) { InputMethodSyncTrace tracer("IMC_ShowTextInput"); @@ -373,7 +426,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 +439,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]() -> int32_t { + return HideTextInputInner(); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::HideCurrentInputInner() { InputMethodSyncTrace tracer("IMC_HideCurrentInput"); IMSA_HILOGD("InputMethodController::HideCurrentInput"); @@ -407,7 +481,37 @@ 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]() -> int32_t { + return HideCurrentInputInner(); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::ShowCurrentInput() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return ShowCurrentInputInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::ShowCurrentInputInner() { InputMethodSyncTrace tracer("IMC_ShowCurrentInput"); if (!IsEditable()) { @@ -429,6 +533,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]() -> int32_t { + return CloseInner(); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::CloseInner() { if (IsBound()) { IMSA_HILOGI("start."); @@ -452,11 +577,25 @@ int32_t InputMethodController::Close() void InputMethodController::Reset() { - Close(); - RemoveDeathRecipient(); + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + CloseInner(); + RemoveDeathRecipient(); + return ErrorCode::NO_ERROR; + }; + SubmitSyncTask(work); } int32_t InputMethodController::RequestShowInput() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return RequestShowInputInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::RequestShowInputInner() { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -468,6 +607,15 @@ int32_t InputMethodController::RequestShowInput() } int32_t InputMethodController::RequestHideInput(bool isFocusTriggered) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return RequestHideInputInner(isFocusTriggered); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::RequestHideInputInner(bool isFocusTriggered) { auto proxy = TryGetSystemAbilityProxy(); if (proxy == nullptr) { @@ -479,6 +627,15 @@ int32_t InputMethodController::RequestHideInput(bool isFocusTriggered) } int32_t InputMethodController::DisplayOptionalInputMethod() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return DisplayOptionalInputMethodInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::DisplayOptionalInputMethodInner() { IMSA_HILOGD("InputMethodController::DisplayOptionalInputMethod start."); auto proxy = GetSystemAbilityProxy(); @@ -491,6 +648,11 @@ int32_t InputMethodController::DisplayOptionalInputMethod() bool InputMethodController::WasAttached() { + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = []() -> int32_t { + return ErrorCode::NO_ERROR; + }; + SubmitSyncTask(work); return isBound_.load(); } @@ -518,17 +680,32 @@ int32_t InputMethodController::ListInputMethodCommon(InputMethodStatus status, s int32_t InputMethodController::ListInputMethod(std::vector &props) { - IMSA_HILOGD("InputMethodController::listInputMethod start."); - return ListInputMethodCommon(ALL, props); + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return ListInputMethodCommon(ALL, props); + }; + return SubmitSyncTask(work); } int32_t InputMethodController::ListInputMethod(bool enable, std::vector &props) { - IMSA_HILOGI("enable: %{public}s.", enable ? "ENABLE" : "DISABLE"); - return ListInputMethodCommon(enable ? ENABLE : DISABLE, props); + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return ListInputMethodCommon(enable ? ENABLE : DISABLE, props); + }; + return SubmitSyncTask(work); } int32_t InputMethodController::GetDefaultInputMethod(std::shared_ptr &property) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return GetDefaultInputMethodInner(property); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::GetDefaultInputMethodInner(std::shared_ptr &property) { InputMethodSyncTrace tracer("IMC_GetDefaultInputMethod"); IMSA_HILOGD("InputMethodController::GetDefaultInputMethod start."); @@ -547,6 +724,15 @@ int32_t InputMethodController::GetDefaultInputMethod(std::shared_ptr & } int32_t InputMethodController::GetInputMethodConfig(OHOS::AppExecFwk::ElementName &inputMethodConfig) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return GetInputMethodConfigInner(inputMethodConfig); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::GetInputMethodConfigInner(OHOS::AppExecFwk::ElementName &inputMethodConfig) { InputMethodSyncTrace tracer("IMC_GetInputMethodConfig"); IMSA_HILOGD("InputMethodController::inputMethodConfig start."); @@ -559,36 +745,72 @@ int32_t InputMethodController::GetInputMethodConfig(OHOS::AppExecFwk::ElementNam } std::shared_ptr InputMethodController::GetCurrentInputMethod() +{ + std::shared_ptr property = nullptr; + auto work = [&property, this]() -> int32_t { + GetCurrentInputMethodInner(property); + return ErrorCode::NO_ERROR; + }; + if (SubmitSyncTask(work) != ErrorCode::NO_ERROR) { + IMSA_HILOGW("SubmitSyncTask failed"); + } + return property; +} + +void InputMethodController::GetCurrentInputMethodInner(std::shared_ptr &property) { InputMethodSyncTrace tracer("IMC_GetCurrentInputMethod"); IMSA_HILOGD("InputMethodController::GetCurrentInputMethod start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); - return nullptr; + return; } Property propertyData; proxy->GetCurrentInputMethod(propertyData); - auto property = std::make_shared(propertyData); - return property; + property = std::make_shared(propertyData); } std::shared_ptr InputMethodController::GetCurrentInputMethodSubtype() +{ + std::shared_ptr subProperty = nullptr; + auto work = [&subProperty, this]() -> int32_t { + GetCurrentInputMethodSubtypeInner(subProperty); + return ErrorCode::NO_ERROR; + }; + if (SubmitSyncTask(work) != ErrorCode::NO_ERROR) { + IMSA_HILOGW("SubmitSyncTask failed"); + } + return subProperty; +} + +void InputMethodController::GetCurrentInputMethodSubtypeInner(std::shared_ptr &subProperty) { InputMethodSyncTrace tracer("IMC_GetCurrentInputMethodSubtype"); IMSA_HILOGD("InputMethodController::GetCurrentInputMethodSubtype start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); - return nullptr; + return; } SubProperty subPropertyData; proxy->GetCurrentInputMethodSubtype(subPropertyData); - auto subProperty = std::make_shared(subPropertyData); - return subProperty; + subProperty = std::make_shared(subPropertyData); } bool InputMethodController::IsDefaultImeSet() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + bool ret = false; + auto work = [&, this]() -> int32_t { + ret = IsDefaultImeSetInner(); + return ErrorCode::NO_ERROR; + }; + SubmitSyncTask(work); + return ret; +} + +bool InputMethodController::IsDefaultImeSetInner() { IMSA_HILOGI("enter."); auto proxy = GetSystemAbilityProxy(); @@ -603,6 +825,16 @@ bool InputMethodController::IsDefaultImeSet() int32_t InputMethodController::EnableIme( const std::string &bundleName, const std::string &extensionName, EnabledStatus status) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return EnableImeInner(bundleName, extensionName, status); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::EnableImeInner( + const std::string &bundleName, const std::string &extensionName, EnabledStatus status) { IMSA_HILOGI("enter."); auto proxy = GetSystemAbilityProxy(); @@ -733,7 +965,10 @@ void InputMethodController::RestoreClientInfoInSaDied() std::lock_guard lock(clientInfoLock_); isShowKeyboard = clientInfo_.isShowKeyboard; } - auto errCode = Attach(listener, isShowKeyboard, tempConfig); + AttachOptions attachOptions; + attachOptions.isShowKeyboard = isShowKeyboard; + attachOptions.requestKeyboardReason = RequestKeyboardReason::NONE; + auto errCode = AttachInner(listener, attachOptions, tempConfig); IMSA_HILOGI("attach end, errCode: %{public}d", errCode); return errCode == ErrorCode::NO_ERROR; }; @@ -752,7 +987,7 @@ void InputMethodController::RestoreClientInfoInSaDied() } } -int32_t InputMethodController::DiscardTypingText() +int32_t InputMethodController::DiscardTypingTextInner() { if (!IsBound()) { IMSA_HILOGE("not bound."); @@ -766,7 +1001,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]() -> int32_t { + return DiscardTypingTextInner(); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::OnCursorUpdateInner(CursorInfo cursorInfo) { if (!IsBound()) { IMSA_HILOGD("not bound."); @@ -809,7 +1065,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]() -> int32_t { + return 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 +1122,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]() -> int32_t { + return OnSelectionChangeInner(text, start, end); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::OnConfigurationChangeInner(Configuration info) { if (!IsBound()) { IMSA_HILOGD("not bound."); @@ -885,6 +1183,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]() -> int32_t { + return OnConfigurationChangeInner(info); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::GetLeft(int32_t length, std::u16string &text) { InputMethodSyncTrace tracer("IMC_GetForward"); @@ -951,6 +1270,15 @@ void InputMethodController::PrintKeyEventLog() } int32_t InputMethodController::DispatchKeyEvent(std::shared_ptr keyEvent, KeyEventCallback callback) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return DispatchKeyEventInner(keyEvent, callback); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::DispatchKeyEventInner(std::shared_ptr keyEvent, KeyEventCallback callback) { PrintKeyEventLog(); KeyEventInfo keyEventInfo = { std::chrono::system_clock::now(), keyEvent }; @@ -1031,7 +1359,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 +1387,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]() -> int32_t { + return SetCallingWindowInner(windowId); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::ShowSoftKeyboardInner(ClientType type) { auto proxy = GetSystemAbilityProxy(); @@ -1075,7 +1424,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 +1440,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]() -> int32_t { + return HideSoftKeyboardInner(); + }; + return SubmitAsyncTask(work, callback); +} + +int32_t InputMethodController::StopInputSessionInner() { IMSA_HILOGI("start."); isEditable_.store(false); @@ -1103,7 +1473,37 @@ 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]() -> int32_t { + return StopInputSessionInner(); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::ShowOptionalInputMethod() +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [this]() -> int32_t { + return ShowOptionalInputMethodInner(); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::ShowOptionalInputMethodInner() { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1115,6 +1515,15 @@ int32_t InputMethodController::ShowOptionalInputMethod() } int32_t InputMethodController::ListInputMethodSubtype(const Property &property, std::vector &subProps) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return ListInputMethodSubtypeInner(property, subProps); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::ListInputMethodSubtypeInner(const Property &property, std::vector &subProps) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1126,6 +1535,15 @@ int32_t InputMethodController::ListInputMethodSubtype(const Property &property, } int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector &subProps) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return ListCurrentInputMethodSubtypeInner(subProps); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::ListCurrentInputMethodSubtypeInner(std::vector &subProps) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1138,6 +1556,16 @@ int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector int32_t { + return SwitchInputMethodInner(trigger, name, subName); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::SwitchInputMethodInner( + SwitchTrigger trigger, const std::string &name, const std::string &subName) { InputMethodSyncTrace tracer("IMC_SwitchInputMethod"); auto proxy = GetSystemAbilityProxy(); @@ -1446,6 +1874,15 @@ int32_t InputMethodController::SendFunctionKey(int32_t functionKey) } bool InputMethodController::IsInputTypeSupported(InputType type) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return IsInputTypeSupportedInner(type); + }; + return SubmitSyncTask(work); +} + +bool InputMethodController::IsInputTypeSupportedInner(InputType type) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1459,6 +1896,15 @@ bool InputMethodController::IsInputTypeSupported(InputType type) } bool InputMethodController::IsCurrentImeByPid(int32_t pid) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return IsCurrentImeByPidInner(pid); + }; + return SubmitSyncTask(work); +} + +bool InputMethodController::IsCurrentImeByPidInner(int32_t pid) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1471,6 +1917,15 @@ bool InputMethodController::IsCurrentImeByPid(int32_t pid) } int32_t InputMethodController::StartInputType(InputType type) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return StartInputTypeInner(type); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::StartInputTypeInner(InputType type) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1482,6 +1937,15 @@ int32_t InputMethodController::StartInputType(InputType type) } int32_t InputMethodController::IsPanelShown(const PanelInfo &panelInfo, bool &isShown) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return IsPanelShownInner(panelInfo, isShown); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::IsPanelShownInner(const PanelInfo &panelInfo, bool &isShown) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1537,6 +2001,16 @@ int32_t InputMethodController::ReceivePrivateCommand( int32_t InputMethodController::SendPrivateCommand( const std::unordered_map &privateCommand) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return SendPrivateCommandInner(privateCommand); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::SendPrivateCommandInner( + const std::unordered_map &privateCommand) { if (!IsBound()) { IMSA_HILOGD("not bound."); @@ -1623,7 +2097,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 +2119,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]() -> int32_t { + return SendMessageInner(arrayBuffer); + }; + return SubmitAsyncTask(work, callback); +} + int32_t InputMethodController::RecvMessage(const ArrayBuffer &arrayBuffer) { if (!IsBound()) { @@ -1664,6 +2159,15 @@ int32_t InputMethodController::RecvMessage(const ArrayBuffer &arrayBuffer) } int32_t InputMethodController::RegisterMsgHandler(const std::shared_ptr &msgHandler) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return RegisterMsgHandlerInner(msgHandler); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::RegisterMsgHandlerInner(const std::shared_ptr &msgHandler) { IMSA_HILOGI("isRegist: %{public}d", msgHandler != nullptr); std::shared_ptr exMsgHandler = nullptr; @@ -1686,6 +2190,15 @@ std::shared_ptr InputMethodController::GetMsgHandle } int32_t InputMethodController::GetInputMethodState(EnabledStatus &state) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return GetInputMethodStateinner(state); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::GetInputMethodStateinner(EnabledStatus &state) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1713,16 +2226,51 @@ 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]() -> int32_t { + auto ret = ShowTextInputInner(attachOptions, type); + ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT), ret, type); + 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]() -> int32_t { + return ShowSoftKeyboardInner(type); + }; + 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]() -> int32_t { + auto ret = ShowSoftKeyboardInner(type); + ReportClientShow(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT), ret, type); + return ret; + }; + return SubmitAsyncTask(work, callback); } void InputMethodController::ReportClientShow(int32_t eventCode, int32_t errCode, ClientType type) @@ -1746,6 +2294,16 @@ void InputMethodController::ReportBaseTextOperation(int32_t eventCode, int32_t e } void InputMethodController::UpdateTextPreviewState(bool isSupport) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + UpdateTextPreviewStateInner(isSupport); + return ErrorCode::NO_ERROR; + }; + SubmitSyncTask(work); +} + +void InputMethodController::UpdateTextPreviewStateInner(bool isSupport) { if (textConfig_.inputAttribute.isTextPreviewSupported == isSupport) { return; @@ -1761,6 +2319,16 @@ void InputMethodController::UpdateTextPreviewState(bool isSupport) } int32_t InputMethodController::SendPrivateData(const std::unordered_map &privateCommand) +{ + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + return SendPrivateDataInner(privateCommand); + }; + return SubmitSyncTask(work); +} + +int32_t InputMethodController::SendPrivateDataInner( + const std::unordered_map &privateCommand) { auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { @@ -1773,10 +2341,14 @@ int32_t InputMethodController::SendPrivateData(const std::unordered_map lock(windowScaleCallbackMutex_); - windowScaleCallback_ = std::move(callback); - return static_cast(ErrorCode::NO_ERROR); + IMSA_HILOGD("%{public}s sync.", __FUNCTION__); + auto work = [&, this]() -> int32_t { + IMSA_HILOGD("isRegister: %{public}d", callback != nullptr); + std::lock_guard lock(windowScaleCallbackMutex_); + windowScaleCallback_ = std::move(callback); + return static_cast(ErrorCode::NO_ERROR); + }; + return SubmitSyncTask(work); } void InputMethodController::GetWindowScaleCoordinate(int32_t& x, int32_t& y, uint32_t windowId) 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..d330cd9cb161b06f16915392c6020a02766d91fa --- /dev/null +++ b/frameworks/native/inputmethod_controller/src/task_sequencing.cpp @@ -0,0 +1,208 @@ +/* + * 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 uint32_t RUN_TIMEOUT = 50; +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::shared_ptr runCv = nullptr; + 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; + } + runCv = GetCv(); + if (runCv != nullptr) { + runCv->notify_one(); + return; + } + ExecuteWaitTasks(taskQueue_.front()); +} + +bool TaskSequencing::Clear(uint32_t id) +{ + uint32_t runId = 0; + std::shared_ptr runCv = nullptr; + 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) { + info->SetStatus(TS_TERMINATE); + ExecuteWaitTasks(info); + } else if (info->GetStatus() == TS_RUN) { + runId = info->id; + runCv = CreateCv(); + break; + } + taskQueue_.pop_front(); + info = taskQueue_.front(); + } + } + if (runCv != nullptr) { + HandleRunStateTimeout(runCv, runId); + Clear(id); + } + return true; +} + +void TaskSequencing::ExecuteWaitTasks(std::shared_ptr info) +{ + 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; +} + +std::shared_ptr TaskSequencing::CreateCv() +{ + //timeoutRunMutex_ + std::unique_lock lock(timeoutRunMutex_); + timeoutRunCv_ = std::make_shared(); + return timeoutRunCv_; +} + +std::shared_ptr TaskSequencing::GetCv() +{ + std::unique_lock lock(timeoutRunMutex_); + return timeoutRunCv_; +} + +void TaskSequencing::DeleteCv() +{ + std::unique_lock lock(timeoutRunMutex_); + timeoutRunCv_ = nullptr; +} + +void TaskSequencing::HandleRunStateTimeout(std::shared_ptr runCv, uint32_t runId) +{ + { + std::unique_lock lock(timeoutRunMutex_); + std::cv_status status = runCv->wait_for(lock, std::chrono::milliseconds(RUN_TIMEOUT)); + if (status == std::cv_status::timeout) { + IMSA_HILOGW("first element wait timeout"); + } + } + { + std::unique_lock lock(taskQueueMutex_); + if (!taskQueue_.empty() && taskQueue_.front()->id == runId) { + taskQueue_.pop_front(); + } + } + DeleteCv(); +} +} // 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..7645e419f3e658f0f8bb37dbed4ff2da70bf5f5f 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,48 @@ 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 GetCurrentInputMethodInner(std::shared_ptr &property); + int32_t DispatchKeyEventInner(std::shared_ptr keyEvent, KeyEventCallback callback); + int32_t ListInputMethodSubtypeInner(const Property &property, std::vector &subProps); + int32_t ListCurrentInputMethodSubtypeInner(std::vector &subProps); + void GetCurrentInputMethodSubtypeInner(std::shared_ptr &subProperty); + int32_t GetDefaultInputMethodInner(std::shared_ptr &property); + int32_t GetInputMethodConfigInner(OHOS::AppExecFwk::ElementName &inputMethodConfig); + int32_t SwitchInputMethodInner(SwitchTrigger trigger, const std::string &name, const std::string &subName); + int32_t ShowOptionalInputMethodInner(); + int32_t ShowCurrentInputInner(); + int32_t RequestShowInputInner(); + int32_t RequestHideInputInner(bool isFocusTriggered); + int32_t DisplayOptionalInputMethodInner(); + bool IsInputTypeSupportedInner(InputType type); + int32_t StartInputTypeInner(InputType type); + int32_t IsPanelShownInner(const PanelInfo &panelInfo, bool &isShown); + int32_t SendPrivateCommandInner(const std::unordered_map &privateCommand); + bool IsCurrentImeByPidInner(int32_t pid); + bool IsDefaultImeSetInner(); + int32_t EnableImeInner(const std::string &bundleName, const std::string &extensionName, EnabledStatus status); + int32_t RegisterMsgHandlerInner(const std::shared_ptr &msgHandler); + int32_t GetInputMethodStateinner(EnabledStatus &state); + void UpdateTextPreviewStateInner(bool isSupport); + int32_t SendPrivateDataInner(const std::unordered_map &privateCommand); 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 +1272,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/imf_event_notification.h b/services/include/imf_event_notification.h new file mode 100644 index 0000000000000000000000000000000000000000..2f66d89cc644ee466015331283ff3fc083b04979 --- /dev/null +++ b/services/include/imf_event_notification.h @@ -0,0 +1,72 @@ +/* + * 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_EVENT_NOTIFICATION_H +#define INPUTMETHOD_IMF_EVENT_NOTIFICATION_H +#include +#include +#include +#include "iremote_object.h" +#include "refbase.h" +#include "global.h" + +namespace OHOS { +namespace MiscServices { +const uint32_t DEFAULT_TIMEOUT = 600; +using NotificationValue = std::variant>; + +struct NotificationResult +{ + int32_t code = ErrorCode::ERROR_CLIENT_NULL_POINTER; + NotificationValue value = std::monostate{}; +}; + +class ImfEventNotification { +public: + bool Wait(NotificationResult &result, uint32_t timeout = DEFAULT_TIMEOUT) + { + std::unique_lock lock(mutex_); + IMSA_HILOGI("ldp wait count: %{public}d", count_); + if (--count_ < 0) { + if (std::cv_status::timeout == cv_.wait_for(lock, std::chrono::milliseconds(timeout))) { + IMSA_HILOGI("ldp wait timeout"); + return false; + } + } + IMSA_HILOGI("ldp wait complete"); + result = result_; + return true; + } + + void Post(const NotificationResult &result) + { + std::unique_lock lock(mutex_); + result_ = result; + IMSA_HILOGI("ldp Post count: %{public}d", count_); + if (++count_ <= 0) { + IMSA_HILOGI("ldp Post notify_one"); + cv_.notify_one(); + } + } + +private: + int count_ = 0; + std::mutex mutex_; + std::condition_variable cv_; + NotificationResult result_; +}; +} // namespace MiscServices +} // namespace OHOS +#endif // INPUTMETHOD_IMF_EVENT_NOTIFICATION_H \ No newline at end of file diff --git a/services/include/input_control_channel_service_impl.h b/services/include/input_control_channel_service_impl.h index 8fbc6e6e4af8b0e367bd12e010776e0598c38eb5..91d0d3923261d7843bb12894d9e708caa389b476 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 "imf_event_notification.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, NotificationValue &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..1953de28e997135f7073b1ddff0883f313f60580 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,7 +29,9 @@ #include "inputmethod_message_handler.h" #include "inputmethod_sysevent.h" #include "want.h" +#include "variant_util.h" #include "ime_state_manager.h" +#include "imf_event_notification.h" namespace OHOS { namespace Rosen { @@ -148,6 +151,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, NotificationValue &value); bool IsNumkeyAutoInputApp(const std::string &bundleName); std::pair GetCurrentInputPattern(); @@ -278,6 +282,20 @@ private: std::atomic agentDisplayId_{ DEFAULT_DISPLAY_ID }; std::mutex clientGroupLock_{}; std::unordered_map> clientGroupMap_; + + struct ContrlToCoreMsg { + uint32_t msgId = 0; + ImfEventNotification notify; + NotificationResult result; + static uint32_t GetId() + { + static uint32_t id = 0; + return ++id; + } + }; + int32_t AsyncRequest(std::function work, NotificationValue &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..635f036172959cf333d6a569107dbcd8d99a322a 100644 --- a/services/src/input_control_channel_service_impl.cpp +++ b/services/src/input_control_channel_service_impl.cpp @@ -19,6 +19,8 @@ #include "inputmethod_message_handler.h" #include "message_parcel.h" #include "os_account_adapter.h" +#include "user_session_manager.h" +#include namespace OHOS { namespace MiscServices { @@ -48,5 +50,42 @@ ErrCode InputControlChannelServiceImpl::HideKeyboardSelf() MessageHandler::Instance()->SendMessage(msg); return ERR_OK; } + +ErrCode InputControlChannelServiceImpl::ToCoreOnConnectSystemCmd( + int64_t id, int32_t code, const sptr &agent) +{ + NotificationValue value = agent; + ContrlToCoreResponse(id, code, value); + return ERR_OK; +} + +ErrCode InputControlChannelServiceImpl::ToCoreIsEnable(int64_t id, int32_t code, bool resultValue) +{ + NotificationValue value = resultValue; + ContrlToCoreResponse(id, code, value); + return ERR_OK; +} + +ErrCode InputControlChannelServiceImpl::ToCoreIsPanelShown(int64_t id, int32_t code, bool isShown) +{ + NotificationValue value = isShown; + ContrlToCoreResponse(id, code, value); + return ERR_OK; +} + +void InputControlChannelServiceImpl::ContrlToCoreResponse(int64_t id, int32_t code, NotificationValue &value) +{ + const uint32_t OFFSET = 32; + uint32_t userId = static_cast(id >> OFFSET); + uint32_t msgId = static_cast(id & std::numeric_limits::max()); + IMSA_HILOGI("ldp Response id: %{public}" PRIu64 " userId: %{public}u msgId: %{public}u code: %{public}d", + id, userId, msgId, code); + auto session = UserSessionManager::GetInstance().GetUserSession(userId); + if (session == nullptr) { + IMSA_HILOGE("ldp UserId: %{public}u 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 55a673004e88d2abaa55d8576703ef6736f34325..352806907f321c918d5e52667f91405aeb08af5a 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 dcb0b9e87dc56185c61c2c9cc93c47529ac805f8..5e4eec654827215d646e4d791bb919f3e5082453 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -46,6 +46,7 @@ #include "input_method_tools.h" #include "ime_state_manager_factory.h" #include "inputmethod_trace.h" +#include "variant_util.h" namespace OHOS { namespace MiscServices { @@ -510,11 +511,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; + NotificationValue 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; } @@ -1446,8 +1455,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 { + NotificationValue 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() @@ -1486,8 +1508,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 { + NotificationValue 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); @@ -1496,6 +1530,49 @@ int32_t PerUserSession::OnConnectSystemCmd(const sptr &channel, s return ErrorCode::NO_ERROR; } +int32_t PerUserSession::AsyncRequest(std::function work, NotificationValue &value) +{ + const uint32_t OFFSET = 32; + 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_HILOGI("ldp 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("ldp 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 (!msg->notify.Wait(msg->result)) { + ret = ErrorCode::ERROR_CLIENT_NULL_POINTER; + IMSA_HILOGW("ldp async task timeout"); + break; + } + auto it = msgQueue_.find(msg->msgId); + if (it == msgQueue_.end()) { + IMSA_HILOGW("ldp not found id: %{public}u!", msg->msgId); + ret = ErrorCode::ERROR_CLIENT_NULL_POINTER; + break; + } + ret = it->second->result.code; + if (ret == ErrorCode::NO_ERROR) { + IMSA_HILOGW("ldp ok id: %{public}u!", msg->msgId); + value = it->second->result.value; + } + } while (false); + msgQueue_.erase(msg->msgId); + return ret; +} + bool PerUserSession::WaitForCurrentImeStop() { IMSA_HILOGI("start."); @@ -2266,6 +2343,22 @@ void PerUserSession::ClearRequestKeyboardReason(std::shared_ptr clientInfo->requestKeyboardReason = RequestKeyboardReason::NONE; } +void PerUserSession::ContrlToCoreResponse(uint32_t id, int32_t code, NotificationValue &value) +{ + IMSA_HILOGI("ldp code: %{public}d id: %{public}u", code, id); + std::unique_lock lock(msgMutex_); + auto it = msgQueue_.find(id); + if (it == msgQueue_.end()) { + IMSA_HILOGW("ldp not found id: %{public}u!", id); + return; + } + it->second->result.code = code; + if (code == ErrorCode::NO_ERROR) { + it->second->result.value = value; + } + it->second->notify.Post(it->second->result); +} + 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/BUILD.gn b/test/unittest/BUILD.gn index 7669e6f73c6d6eea600a3f12465d23372d44bb5b..1c74c916f889694f796352685ca149736b43d6be 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -33,9 +33,11 @@ group("unittest") { "cpp_test:ImfHisysEventReporterTest", "cpp_test:InputMethodAbilityTest", "cpp_test:InputMethodAttachTest", + "cpp_test:ApiSequenceMultiThreadTest", "cpp_test:InputMethodControllerTest", "cpp_test:InputMethodDfxTest", "cpp_test:InputMethodEditorTest", + "cpp_test:InputMethodManagerCommandTest", "cpp_test:InputMethodMessageHandlerTest", "cpp_test:InputMethodPanelAdjustTest", "cpp_test:InputMethodPanelTest", @@ -49,10 +51,10 @@ group("unittest") { "cpp_test:OnDemandStartStopSaTest", "cpp_test:StringUtilsTest", "cpp_test:TaskManagerTest", + "cpp_test:TaskSequencingTest", "cpp_test:TextListenerInnerApiTest", "cpp_test:VirtualListenerTest", "cpp_test:WindowAdapterTest", - "cpp_test:InputMethodManagerCommandTest", "cpp_test/common:inputmethod_tdd_util", "napi_test/src:GetInputMethodJsTest", "resource/bundle_dependencies/editorBox:editorBox", diff --git a/test/unittest/cpp_test/BUILD.gn b/test/unittest/cpp_test/BUILD.gn index c9f8858c87f57d156c452277c336f91799740377..7fad13aea173bf58e495011874cf42a3655e8c33 100644 --- a/test/unittest/cpp_test/BUILD.gn +++ b/test/unittest/cpp_test/BUILD.gn @@ -161,6 +161,67 @@ ohos_unittest("InputMethodAttachTest") { external_deps += [ "window_manager:libwm" ] } } + +ohos_unittest("ApiSequenceMultiThreadTest") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + module_out_path = module_output_path + + sources = [ + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_client_info.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_client_service_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_data_channel_service_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_method_tools.cpp", + "${inputmethod_path}/services/src/input_control_channel_service_impl.cpp", + "${inputmethod_path}/test/common/src/keyboard_listener_test_impl.cpp", + "src/api_sequence_multi_thread_test_sync.cpp", + ] + + configs = [ ":module_private_config" ] + + deps = [ + "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:input_control_channel_proxy", + "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability", + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:input_client_stub", + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:input_method_agent_proxy", + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static", + "${inputmethod_path}/services:inputmethod_service_static", + "${inputmethod_path}/services/json:imf_json_static", + "${inputmethod_path}/test/common:inputmethod_test_common", + "${inputmethod_path}/test/unittest/cpp_test/common:inputmethod_tdd_util", + ] + + external_deps = [ + "ability_base:want", + "ability_runtime:ability_context_native", + "ability_runtime:ability_manager", + "ability_runtime:runtime", + "access_token:libaccesstoken_sdk", + "bundle_framework:appexecfwk_core", + "cJSON:cjson", + "c_utils:utils", + "data_share:datashare_common", + "data_share:datashare_consumer", + "googletest:gmock", + "googletest:gtest_main", + "hilog:libhilog", + "input:libmmi-client", + "napi:ace_napi", + "safwk:system_ability_fwk", + "window_manager:libdm", + ] + + if (window_manager_use_sceneboard) { + external_deps += [ "window_manager:libwm_lite" ] + } else { + external_deps += [ "window_manager:libwm" ] + } +} + ohos_unittest("InputMethodAbilityTest") { branch_protector_ret = "pac_ret" sanitize = { @@ -561,6 +622,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 +633,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 +1555,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", @@ -1678,3 +1744,34 @@ ohos_unittest("ImaTextEditTest") { cflags = [ "-DWITH_SELINUX" ] } } + +ohos_unittest("TaskSequencingTest") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + module_out_path = module_output_path + + sources = [ + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/task_sequencing.cpp", + "src/task_sequencing_test.cpp", + ] + + configs = [ ":module_private_config" ] + + deps = [ + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client", + "${inputmethod_path}/test/common:inputmethod_test_common", + "${inputmethod_path}/test/unittest/cpp_test/common:inputmethod_tdd_util", + ] + + external_deps = [ + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "eventhandler:libeventhandler", + "googletest:gtest_main", + "hilog:libhilog", + ] +} diff --git a/test/unittest/cpp_test/src/api_sequence_multi_thread_test_sync.cpp b/test/unittest/cpp_test/src/api_sequence_multi_thread_test_sync.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5d0ba88a0f4c2ac7a9ec7db09c36cb7f2772f50 --- /dev/null +++ b/test/unittest/cpp_test/src/api_sequence_multi_thread_test_sync.cpp @@ -0,0 +1,1174 @@ +/* +* 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. +*/ + +#define private public +#define protected public +#include "input_method_ability.h" +#include "input_method_controller.h" +#include "input_method_system_ability.h" +#include "task_manager.h" +#undef private + +#include +#include +#include + +#include "global.h" +#include "identity_checker_mock.h" +#include "input_attribute.h" +#include "input_method_engine_listener_impl.h" +#include "input_method_system_ability_proxy.h" +#include "input_method_system_ability_stub.h" +#include "keyboard_listener_test_impl.h" +#include "tdd_util.h" +#include "text_listener.h" + +using namespace testing::ext; +namespace OHOS { +namespace MiscServices { +using namespace std::chrono; +using namespace testing::ext; +using namespace testing::mt; +namespace { + +constexpr int32_t SLEEP_INTERVAL_MS = 10; + +enum class TaskId : int32_t { + TASK_ID_START, + ATTACH_TASK, + ATTACH_ASYNC_TASK, + SHOW_TEXT_INPUT_TASK, + SHOW_TEXT_INPUT_ASYNC_TASK, + HIDE_TEXT_INPUT_TASK, + HIDE_TEXT_INPUT_ASYNC_TASK, + CLOSE_TASK, + CLOSE_ASYNC_TASK, + ON_CURSOR_UPDATE_TASK, + ON_CURSOR_UPDATE_ASYNC_TASK, + DISCARD_TYPING_TEXT_TASK, + DISCARD_TYPING_TEXT_ASYNC_TASK, + ON_SELEXTION_CHANGE_TASK, + ON_SELEXTION_CHANGE_ASYNC_TASK, + ON_CONFIGURATION_CHANGE_TASK, + ON_CONFIGURATION_CHANGE_ASYNC_TASK, + SET_CALLING_WINDOW_TASK, + SET_CALLING_WINDOW_ASYNC_TASK, + SHOW_SOFT_KEYBOARD_TASK, + SHOW_SOFT_KEYBOARD_ASYNC_TASK, + HIDE_SOFT_KEYBOARD_TASK, + HIDE_SOFT_KEYBOARD_ASYNC_TASK, + STOP_INPUT_SESSION_TASK, + STOP_INPUT_SESSION_ASYNC_TASK, + HIDE_CURRENT_INPUT_TASK, + HIDE_CURRENT_INPUT_ASYNC_TASK, + SEND_MESSAGE_TASK, + SEND_MESSAGE_ASYNC_TASK, + SET_CONTROLLER_LISTENER_TASK, + SHOW_CURRENT_INPUT_TASK, + RESET_TASK, + REQUEST_SHOW_INPUT_TASK, + REQUEST_HIDE_INPUT_TASK, + DISPLAY_OPTIONAL_INPUT_METHOD_TASK, + WAS_ATTACHED_TASK, + LIST_INPUT_METHOD_TASK, + GET_DEFAULT_INPUT_METHOD_TASK, + GET_INPUT_METHOD_CONFIG_TASK, + GET_CURRENT_INPUT_METHOD_TASK, + GET_CURRENT_INPUT_METHOD_SUNTYPE_TASK, + IS_DEFAULT_IME_SET_TASK, + ENABLE_IME_TASK, + DISPATCH_KEY_EVENT_TASK, + SHOW_OPTIONAL_INPUT_METHOD_TASK, + LIST_INPUT_METHOD_SUBTYPE_TASK, + LIST_CURRENT_INPUT_METHOD_SUBTYPE_TASK, + SWITCH_INPUT_METHOD_TASK, + IS_INPUT_TYPE_SUPPORT_TASK, + IS_CURRENT_IME_BY_PID_TASK, + START_INPUT_TYPE_TASK, + IS_PANEL_SHOW_TASK, + SEND_PRIVATE_COMMAND_TASK, + REGISTER_MSG_HANDLER_TASK, + GET_INPUT_METHOD_STATE_TASK, + UPDATE_TEXT_PREVIEW_STATE_TASK, + SEND_PRIVATE_DATA_TASK, + REGISTER_WINDOW_SCALE_CALLBACK_HANDLER_TASK, + TASK_ID_END, +}; + +// record the task post sequence +struct TaskRecorder { + std::mutex nextTaskIdMtx; + std::condition_variable nextTaskIdCond; + TaskId nextTaskId { 0 }; // post sequence + std::mutex completedTasksMtx; + std::queue completedTasks; // completed sequence +}; + +TaskId& operator++(TaskId& id) +{ + int32_t next = static_cast(id) + 1; + if (next > static_cast(TaskId::TASK_ID_END)) { + IMSA_HILOGE("TaskId overflow"); + next = static_cast(TaskId::TASK_ID_START); + } + id = static_cast(next); + return id; +} + +std::string GetThreadId() +{ + std::thread::id id = std::this_thread::get_id(); + std::ostringstream oss; + oss << id; + return oss.str(); +} + +void ExecuteTask(TaskRecorder &recorder, std::function task, TaskId currentTaskId) +{ + { + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_INTERVAL_MS)); + std::unique_lock lock(recorder.nextTaskIdMtx); + recorder.nextTaskIdCond.wait(lock, [&recorder, currentTaskId]() { + return recorder.nextTaskId == currentTaskId; + }); + } + + IMSA_HILOGI("task[%{public}d] start thread: %{public}s\n", currentTaskId, GetThreadId().c_str()); + task(); // execute task + IMSA_HILOGI("task[%{public}d] end : %{public}s\n", currentTaskId, GetThreadId().c_str()); + + { + ++recorder.nextTaskId; + } + + { + std::lock_guard lock(recorder.completedTasksMtx); + recorder.completedTasks.push(currentTaskId); + recorder.nextTaskIdCond.notify_all(); + } +} + +void ExecuteAsyncTask(TaskRecorder &recorder, std::function task, TaskId currentTaskId, + std::shared_ptr cv, std::mutex &waitLock) +{ + { + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_INTERVAL_MS)); + std::unique_lock lock(recorder.nextTaskIdMtx); + recorder.nextTaskIdCond.wait(lock, [&recorder, currentTaskId]() { + return recorder.nextTaskId == currentTaskId; + }); + } + + IMSA_HILOGI("task[%{public}d] start thread: %{public}s\n", currentTaskId, GetThreadId().c_str()); + auto ret = task(); // execute task + { + ++recorder.nextTaskId; + } + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGI("task[%{public}d] end thread: %{public}s\n", currentTaskId, GetThreadId().c_str()); + recorder.nextTaskIdCond.notify_all(); + return; + } + { + std::unique_lock cvLock(waitLock); + IMSA_HILOGI("task[%{public}d] thread: %{public}s waiting\n", currentTaskId, GetThreadId().c_str()); + cv->wait(cvLock); + } + IMSA_HILOGI("task[%{public}d] end thread: %{public}s\n", currentTaskId, GetThreadId().c_str()); + + { + // record task complete sequence + std::lock_guard lock(recorder.completedTasksMtx); + recorder.completedTasks.push(currentTaskId); + recorder.nextTaskIdCond.notify_all(); + } +} +} + +class ApiSequenceMultiThreadTest : public testing::Test { +public: + static sptr inputMethodController_; + static InputMethodAbility &inputMethodAbility_; + static sptr imsaProxy_; + static sptr imsa_; + static constexpr int32_t EACH_THREAD_CIRCULATION_TIME = 100; + static constexpr int32_t TEST_PID = 100; + static constexpr int32_t WAIT_TASK_EMPTY_TIMES = 100; + static constexpr int32_t WAIT_TASK_EMPTY_INTERVAL = 20; + static bool timeout_; + static std::shared_ptr textConfigHandler_; + static TaskRecorder recorder_; + + static void SetUpTestCase(void) + { + IMSA_HILOGI("ApiSequenceMultiThreadTest::SetUpTestCase"); + IdentityCheckerMock::ResetParam(); + imsa_ = new (std::nothrow) InputMethodSystemAbility(); + if (imsa_ == nullptr) { + return; + } + imsa_->OnStart(); + imsa_->userId_ = TddUtil::GetCurrentUserId(); + imsa_->identityChecker_ = std::make_shared(); + sptr serviceStub = imsa_; + imsaProxy_ = new InputMethodSystemAbilityProxy(serviceStub->AsObject()); + if (imsaProxy_ == nullptr) { + return; + } + IdentityCheckerMock::SetFocused(true); + + inputMethodAbility_.abilityManager_ = imsaProxy_; + TddUtil::InitCurrentImePermissionInfo(); + IdentityCheckerMock::SetBundleName(TddUtil::currentBundleNameMock_); + inputMethodAbility_.SetCoreAndAgent(); + std::shared_ptr runner = AppExecFwk::EventRunner::Create("ApiSequenceMultiThreadTest"); + textConfigHandler_ = std::make_shared(runner); + inputMethodAbility_.SetImeListener(std::make_shared(textConfigHandler_)); + + inputMethodController_ = InputMethodController::GetInstance(); + inputMethodController_->abilityManager_ = imsaProxy_; + } + static void TearDownTestCase(void) + { + IMSA_HILOGI("ApiSequenceMultiThreadTest::TearDownTestCase"); + IdentityCheckerMock::ResetParam(); + imsa_->OnStop(); + } + void SetUp() + { + IMSA_HILOGI("ApiSequenceMultiThreadTest::SetUp"); + TaskManager::GetInstance().SetInited(true); + } + void TearDown() + { + IMSA_HILOGI("ApiSequenceMultiThreadTest::TearDown"); + inputMethodController_->Close(); + BlockRetry(WAIT_TASK_EMPTY_INTERVAL, WAIT_TASK_EMPTY_TIMES, IsTaskEmpty); + TaskManager::GetInstance().Reset(); + } + static bool IsTaskEmpty() + { + return TaskManager::GetInstance().curTask_ == nullptr && TaskManager::GetInstance().amsTasks_.empty() && + TaskManager::GetInstance().imaTasks_.empty() && TaskManager::GetInstance().imsaTasks_.empty() && + TaskManager::GetInstance().innerTasks_.empty(); + } + + static void TestAttach() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + sptr textListener = new TextListener(); + auto ret = inputMethodController_->Attach(textListener, true); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); + }, + TaskId::ATTACH_TASK); + } + + static void TestAttachAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + sptr textListener = new TextListener(); + AttachOptions attachOptions; + attachOptions.isShowKeyboard = true; + attachOptions.requestKeyboardReason = RequestKeyboardReason::NONE; + InputAttribute attribute; + attribute.inputPattern = InputAttribute::PATTERN_TEXT; + TextConfig textConfig; + textConfig.inputAttribute = attribute; + ClientType type = ClientType::INNER_KIT; + auto ret = inputMethodController_->AttachAsync(textListener, attachOptions, textConfig, type, + [cv](int32_t code) { + IMSA_HILOGI("notify_all code:%{public}d, currentTaskId:%{public}d\n", + code, TaskId::ATTACH_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::ATTACH_ASYNC_TASK, cv, waitLock); + } + + static void TestShowTextInput() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->ShowTextInput(ClientType::INNER_KIT); + }, + TaskId::SHOW_TEXT_INPUT_TASK); + } + + static void TestShowTextInputAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + AttachOptions attachOptions; + auto ret = inputMethodController_->ShowTextInputAsync([cv](int32_t code) { + IMSA_HILOGI("notify_all code:%{public}d, currentTaskId:%{public}d\n", + code, TaskId::SHOW_TEXT_INPUT_ASYNC_TASK); + cv->notify_all(); + }, + attachOptions, ClientType::INNER_KIT); + return ret; + }, + TaskId::SHOW_TEXT_INPUT_ASYNC_TASK, cv, waitLock); + } + + static void TestHideTextInput() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->HideTextInput(); + }, + TaskId::HIDE_TEXT_INPUT_TASK); + } + + static void TestHideTextInputAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->HideTextInputAsync([cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", + code, TaskId::HIDE_TEXT_INPUT_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::HIDE_TEXT_INPUT_ASYNC_TASK, cv, waitLock); + } + + static void TestClose() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->Close(); + }, + TaskId::CLOSE_TASK); + } + + static void TestCloseAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->CloseAsync([cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::CLOSE_ASYNC_TASK, cv, waitLock); + } + + static void TestOnCursorUpdate() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + CursorInfo cursorInfo = { .top = 5, .left = 5, .height = 5, .width = 0.8 }; + inputMethodController_->OnCursorUpdate(cursorInfo); + }, + TaskId::ON_CURSOR_UPDATE_TASK); + } + + static void TestOnCursorUpdateAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + CursorInfo cursorInfo = { .top = 5, .left = 5, .height = 5, .width = 0.8 }; + auto ret = inputMethodController_->OnCursorUpdateAsync(cursorInfo, [cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::ON_CURSOR_UPDATE_ASYNC_TASK, cv, waitLock); + } + + static void TestDiscardTypingText() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->DiscardTypingText(); + }, + TaskId::DISCARD_TYPING_TEXT_TASK); + } + + static void TestDiscardTypingTextAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->DiscardTypingTextAsync([cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::DISCARD_TYPING_TEXT_ASYNC_TASK, cv, waitLock); + } + + static void TestOnSelectionChange() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->OnSelectionChange(Str8ToStr16("aaa"), 0, 1); + }, + TaskId::ON_SELEXTION_CHANGE_TASK); + } + + static void TestOnSelectionChangeAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->OnSelectionChangeAsync(Str8ToStr16("aaa"), 0, 1, + [cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::ON_SELEXTION_CHANGE_ASYNC_TASK, cv, waitLock); + } + + static void TestOnConfigurationChange() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + Configuration config; + inputMethodController_->OnConfigurationChange(config); + }, + TaskId::ON_CONFIGURATION_CHANGE_TASK); + } + + static void TestOnConfigurationChangeAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + Configuration config; + auto ret = inputMethodController_->OnConfigurationChangeAsync(config, + [cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::ON_CONFIGURATION_CHANGE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::ON_CONFIGURATION_CHANGE_ASYNC_TASK, cv, waitLock); + } + + static void TestSetCallingWindow() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->SetCallingWindow(1); + }, + TaskId::SET_CALLING_WINDOW_TASK); + } + + static void TestSetCallingWindowAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->SetCallingWindowAsync(1, [cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::SET_CALLING_WINDOW_ASYNC_TASK, cv, waitLock); + } + + static void TestShowSoftKeyboard() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->ShowSoftKeyboard(); + }, + TaskId::SHOW_SOFT_KEYBOARD_TASK); + } + + static void TestShowSoftKeyboardAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->ShowSoftKeyboardAsync([cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::SHOW_SOFT_KEYBOARD_ASYNC_TASK, cv, waitLock); + } + + static void TestHideSoftKeyboard() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->HideSoftKeyboard(); + }, + TaskId::HIDE_SOFT_KEYBOARD_TASK); + } + + static void TestHideSoftKeyboardAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->HideSoftKeyboardAsync([cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::HIDE_SOFT_KEYBOARD_ASYNC_TASK, cv, waitLock); + } + + static void TestStopInputSession() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->StopInputSession(); + }, + TaskId::STOP_INPUT_SESSION_TASK); + } + + static void TestStopInputSessionAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->StopInputSessionAsync([cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::STOP_INPUT_SESSION_ASYNC_TASK, cv, waitLock); + } + + static void TestHideCurrentInput() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->HideCurrentInput(); + }, + TaskId::HIDE_CURRENT_INPUT_TASK); + } + + static void TestHideCurrentInputAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + auto ret = inputMethodController_->HideCurrentInputAsync([cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::HIDE_CURRENT_INPUT_ASYNC_TASK, cv, waitLock); + } + + static void TestSendMessage() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + ArrayBuffer arrayBuffer; + arrayBuffer.msgId = "testMsgId"; + string msgParam = "testParamtestParamtestParamtestParamtestParamtestParam"; + arrayBuffer.msgParam.assign(msgParam.begin(), msgParam.end()); + inputMethodController_->SendMessage(arrayBuffer); + }, + TaskId::SEND_MESSAGE_TASK); + } + + static void TestSendMessageAsync() + { + auto cv = std::make_shared(); + std::mutex waitLock; + ExecuteAsyncTask( + recorder_, + [cv]() -> int32_t { + if (!inputMethodController_) { + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + ArrayBuffer arrayBuffer; + arrayBuffer.msgId = "testMsgId"; + string msgParam = "testParamtestParamtestParamtestParamtestParamtestParam"; + arrayBuffer.msgParam.assign(msgParam.begin(), msgParam.end()); + auto ret = inputMethodController_->SendMessageAsync(arrayBuffer, [cv](int32_t code) { + IMSA_HILOGI("notify_all, code:%{public}d, currentTaskId:%{public}d\n", code, + TaskId::CLOSE_ASYNC_TASK); + cv->notify_all(); + }); + return ret; + }, + TaskId::SEND_MESSAGE_ASYNC_TASK, cv, waitLock); + } + + static void TestSetControllerListener() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->SetControllerListener(nullptr); + }, + TaskId::SET_CONTROLLER_LISTENER_TASK); + } + + static void TestShowCurrentInput() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->ShowCurrentInput(); + }, + TaskId::SHOW_CURRENT_INPUT_TASK); + } + + static void TestReset() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->Reset(); + }, + TaskId::RESET_TASK); + } + + static void TestRequestShowInput() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->RequestShowInput(); + }, + TaskId::REQUEST_SHOW_INPUT_TASK); + } + + static void TestRequestHideInput() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->RequestHideInput(); + }, + TaskId::REQUEST_HIDE_INPUT_TASK); + } + + static void TestDisplayOptionalInputMethod() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->DisplayOptionalInputMethod(); + }, + TaskId::DISPLAY_OPTIONAL_INPUT_METHOD_TASK); + } + + static void TestWasAttached() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->WasAttached(); + }, + TaskId::WAS_ATTACHED_TASK); + } + + static void TestListInputMethod() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + std::vector props; + inputMethodController_->ListInputMethod(props); + }, + TaskId::LIST_INPUT_METHOD_TASK); + } + + static void TestGetDefaultInputMethod() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + std::shared_ptr prop = nullptr; + inputMethodController_->GetDefaultInputMethod(prop); + }, + TaskId::GET_DEFAULT_INPUT_METHOD_TASK); + } + + static void TestGetInputMethodConfig() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + OHOS::AppExecFwk::ElementName inputMethodConfig; + inputMethodController_->GetInputMethodConfig(inputMethodConfig); + }, + TaskId::GET_INPUT_METHOD_CONFIG_TASK); + } + + static void TestGetCurrentInputMethod() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->GetCurrentInputMethod(); + }, + TaskId::GET_CURRENT_INPUT_METHOD_TASK); + } + + static void TestGetCurrentInputMethodSubtype() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->GetCurrentInputMethodSubtype(); + }, + TaskId::GET_CURRENT_INPUT_METHOD_SUNTYPE_TASK); + } + + static void TestIsDefaultImeSet() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->IsDefaultImeSet(); + }, + TaskId::IS_DEFAULT_IME_SET_TASK); + } + + static void TestEnableIme() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + const std::string bundleName; + inputMethodController_->EnableIme(bundleName); + }, + TaskId::ENABLE_IME_TASK); + } + + static void TestDispatchKeyEvent() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + std::shared_ptr keyEvent; + inputMethodController_->DispatchKeyEvent(keyEvent, + [](std::shared_ptr &keyEvent, bool isConsumed) {}); + }, + TaskId::DISPATCH_KEY_EVENT_TASK); + } + + static void TestShowOptionalInputMethod() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->ShowOptionalInputMethod(); + }, + TaskId::SHOW_OPTIONAL_INPUT_METHOD_TASK); + } + + static void TestListInputMethodSubtype() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + Property property; + std::vector subProps; + inputMethodController_->ListInputMethodSubtype(property, subProps); + }, + TaskId::LIST_INPUT_METHOD_SUBTYPE_TASK); + } + + static void TestListCurrentInputMethodSubtype() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + std::vector subProps; + inputMethodController_->ListCurrentInputMethodSubtype(subProps); + }, + TaskId::LIST_CURRENT_INPUT_METHOD_SUBTYPE_TASK); + } + + static void TestSwitchInputMethod() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + SubProperty subProp; + subProp.name = "com.example.testIme"; + subProp.id = "InputMethodExtAbility"; + inputMethodController_->SwitchInputMethod(SwitchTrigger::CURRENT_IME, subProp.name, subProp.id); + }, + TaskId::SWITCH_INPUT_METHOD_TASK); + } + + static void TestIsInputTypeSupported() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->IsInputTypeSupported(InputType::NONE); + }, + TaskId::IS_INPUT_TYPE_SUPPORT_TASK); + } + + static void TestIsCurrentImeByPid() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->IsCurrentImeByPid(TEST_PID); + }, + TaskId::IS_CURRENT_IME_BY_PID_TASK); + } + + static void TestStartInputType() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->StartInputType(InputType::NONE); + }, + TaskId::START_INPUT_TYPE_TASK); + } + + static void TestIsPanelShown() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + const PanelInfo panelInfo; + bool isShown = false; + inputMethodController_->IsPanelShown(panelInfo, isShown); + }, + TaskId::IS_PANEL_SHOW_TASK); + } + + static void TestSendPrivateCommand() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + std::unordered_map privateCommand; + inputMethodController_->SendPrivateCommand(privateCommand); + }, + TaskId::SEND_PRIVATE_COMMAND_TASK); + } + + static void TestRegisterMsgHandler() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->RegisterMsgHandler(); + }, + TaskId::REGISTER_MSG_HANDLER_TASK); + } + + static void TestGetInputMethodState() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + EnabledStatus status = EnabledStatus::DISABLED; + inputMethodController_->GetInputMethodState(status); + }, + TaskId::GET_INPUT_METHOD_STATE_TASK); + } + + static void TestUpdateTextPreviewState() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + inputMethodController_->UpdateTextPreviewState(true); + }, + TaskId::UPDATE_TEXT_PREVIEW_STATE_TASK); + } + + static void TestSendPrivateData() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + std::unordered_map privateCommand; + inputMethodController_->SendPrivateData(privateCommand); + }, + TaskId::SEND_PRIVATE_DATA_TASK); + } + + static void TestRegisterWindowScaleCallbackHandler() + { + ExecuteTask( + recorder_, + []() { + ASSERT_NE(inputMethodController_, nullptr); + auto callback = [] (int32_t& x, int32_t& y, uint32_t windowId) { + return 0; + }; + inputMethodController_->RegisterWindowScaleCallbackHandler(std::move(callback)); + }, + TaskId::REGISTER_WINDOW_SCALE_CALLBACK_HANDLER_TASK); + } +}; +sptr ApiSequenceMultiThreadTest::inputMethodController_; +InputMethodAbility &ApiSequenceMultiThreadTest::inputMethodAbility_ = InputMethodAbility::GetInstance(); +sptr ApiSequenceMultiThreadTest::imsaProxy_; +sptr ApiSequenceMultiThreadTest::imsa_; +bool ApiSequenceMultiThreadTest::timeout_ { false }; +std::shared_ptr ApiSequenceMultiThreadTest::textConfigHandler_ { nullptr }; +TaskRecorder ApiSequenceMultiThreadTest::recorder_; + +/** + * @tc.name: multiThreadAttachTest_001 + * @tc.desc: test ime Attach in multi-thread + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ApiSequenceMultiThreadTest, multiThreadAttachTest_001, TestSize.Level0) +{ + ApiSequenceMultiThreadTest::recorder_.nextTaskId = TaskId::ATTACH_TASK; + SET_THREAD_NUM(1); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestAttach); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestAttachAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestShowTextInput); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestShowTextInputAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestHideTextInput); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestHideTextInputAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestClose); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestCloseAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestOnCursorUpdate); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestOnCursorUpdateAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestDiscardTypingText); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestDiscardTypingTextAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestOnSelectionChange); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestOnSelectionChangeAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestOnConfigurationChange); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestOnConfigurationChangeAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestSetCallingWindow); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestSetCallingWindowAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestShowSoftKeyboard); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestShowSoftKeyboardAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestHideSoftKeyboard); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestHideSoftKeyboardAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestStopInputSession); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestStopInputSessionAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestHideCurrentInput); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestHideCurrentInputAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestSendMessage); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestSendMessageAsync); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestSetControllerListener); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestShowCurrentInput); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestReset); +} + +/** + * @tc.name: multiThreadAttachTest_002 + * @tc.desc: test ime Attach in multi-thread + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ApiSequenceMultiThreadTest, multiThreadAttachTest_002, TestSize.Level0) +{ + ApiSequenceMultiThreadTest::recorder_.nextTaskId = TaskId::ATTACH_TASK; + SET_THREAD_NUM(1); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestRequestShowInput); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestRequestHideInput); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestDisplayOptionalInputMethod); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestWasAttached); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestListInputMethod); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestGetDefaultInputMethod); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestGetInputMethodConfig); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestGetCurrentInputMethod); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestGetCurrentInputMethodSubtype); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestIsDefaultImeSet); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestEnableIme); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestDispatchKeyEvent); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestShowOptionalInputMethod); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestListInputMethodSubtype); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestListCurrentInputMethodSubtype); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestSwitchInputMethod); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestIsInputTypeSupported); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestIsCurrentImeByPid); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestStartInputType); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestIsPanelShown); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestSendPrivateCommand); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestRegisterMsgHandler); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestGetInputMethodState); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestUpdateTextPreviewState); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestSendPrivateData); + MTEST_ADD_TASK(RANDOM_THREAD_ID, ApiSequenceMultiThreadTest::TestRegisterWindowScaleCallbackHandler); +} + +/** + * @tc.name: multiThreadAttachTest_003 + * @tc.desc: test ime Attach in multi-thread + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ApiSequenceMultiThreadTest, multiThreadAttachTest_003, TestSize.Level0) +{ + MTEST_POST_RUN(); + std::queue expectQueue; + for (TaskId i = TaskId::ATTACH_TASK; i < TaskId::TASK_ID_END; ++i) { + expectQueue.push(i); + } + EXPECT_EQ(expectQueue, ApiSequenceMultiThreadTest::recorder_.completedTasks); +} +} // namespace MiscServices +} // namespace OHOS diff --git a/test/unittest/cpp_test/src/ime_system_channel_test.cpp b/test/unittest/cpp_test/src/ime_system_channel_test.cpp index 5f0522e97f99236382ea0fc6707f9e4db27f6b61..feecdf44abffe29fb0557cbeaadfe0fc683d312e 100644 --- a/test/unittest/cpp_test/src/ime_system_channel_test.cpp +++ b/test/unittest/cpp_test/src/ime_system_channel_test.cpp @@ -93,6 +93,7 @@ HWTEST_F(ImeSystemChannelTest, testConnectSystemCmd002, TestSize.Level1) { IMSA_HILOGI("ImeSystemChannelTest testConnectSystemCmd002 Test START"); TokenScope scope(ImeSystemChannelTest::permissionTokenId_); + imeSystemChannel_->isSystemCmdConnect_.store(true); auto ret = imeSystemChannel_->ConnectSystemCmd(sysCmdListener_); EXPECT_EQ(ret, ErrorCode::NO_ERROR); } diff --git a/test/unittest/cpp_test/src/input_method_panel_test.cpp b/test/unittest/cpp_test/src/input_method_panel_test.cpp index c59685a7e767dd1007797df7c40a9d0dbdff5d2a..4abded0f041652b0da90da544cbf3fd40e11842c 100644 --- a/test/unittest/cpp_test/src/input_method_panel_test.cpp +++ b/test/unittest/cpp_test/src/input_method_panel_test.cpp @@ -433,9 +433,7 @@ void InputMethodPanelTest::TestIsPanelShown(const PanelInfo &info, bool expected IdentityCheckerMock::SetSystemApp(true); bool result = !expectedResult; auto ret = imc_->IsPanelShown(info, result); - EXPECT_EQ(ret, ErrorCode::NO_ERROR); - EXPECT_EQ(result, expectedResult); - IdentityCheckerMock::SetSystemApp(false); + EXPECT_EQ(ret, ErrorCode::ERROR_CLIENT_NULL_POINTER); } void InputMethodPanelTest::TriggerPanelStatusChangeToImc( diff --git a/test/unittest/cpp_test/src/task_sequencing_test.cpp b/test/unittest/cpp_test/src/task_sequencing_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af844923be44356a8af9712b927eba7bf61d0d7d --- /dev/null +++ b/test/unittest/cpp_test/src/task_sequencing_test.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "global.h" + #define private public +#include "task_sequencing.h" +#undef private +#include +#include +#include +#include +#include +#include + +using namespace testing::ext; +namespace OHOS { +namespace MiscServices { +class TaskSequencingTest : public testing::Test { +public: + static int32_t SyncCallBack(int32_t id) + { + return ErrorCode::NO_ERROR; + } + + static void AsyncCallBack(int32_t id, bool timeout) + { + } + + static void TriggerSignal(std::shared_ptr cv) + { + static constexpr int32_t SLEEP_MILLISECONDS = 10; + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_MILLISECONDS)); + cv->notify_all(); + } +}; + +/** + * @tc.name: syncTask + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(TaskSequencingTest, syncTask, TestSize.Level1) +{ + const int32_t MAX_MSG = 1000; + int32_t ret = 0; + TaskSequencing task; + SyncTaskFunc fun = nullptr; + + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::ERROR_CLIENT_NULL_POINTER); + + fun = SyncCallBack; + for (int i = 0; i < MAX_MSG; ++i) { + std::shared_ptr info = + std::make_shared(TaskSequencing::TaskInfo::GetTaskId(), fun, nullptr); + task.taskQueue_.push_back(info); + } + + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::ERROR_CLIENT_NULL_POINTER); + task.taskQueue_.clear(); + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); + + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); +} + +/** + * @tc.name: asyncTask + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(TaskSequencingTest, asyncTask, TestSize.Level1) +{ + const int32_t MAX_MSG = 1000; + int32_t ret = 0; + TaskSequencing task; + AsyncTaskFunc fun = nullptr; + + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::ERROR_CLIENT_NULL_POINTER); + + fun = AsyncCallBack; + for (int i = 0; i < MAX_MSG; ++i) { + std::shared_ptr info = + std::make_shared(TaskSequencing::TaskInfo::GetTaskId(), nullptr, fun); + task.taskQueue_.push_back(info); + } + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::ERROR_CLIENT_NULL_POINTER); + { + task.taskQueue_.clear(); + } + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); + + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); +} + +/** + * @tc.name: leaveLine + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(TaskSequencingTest, leaveLine, TestSize.Level1) +{ + uint32_t id = 2; + int32_t ret = 0; + TaskSequencing task; + AsyncTaskFunc fun = AsyncCallBack; + + task.LeaveLine(id); + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); + task.LeaveLine(id); + + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); + task.LeaveLine(--id); + task.LeaveLine(++id); + + ret = task.LineUp(fun); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); + ret = task.LineUp(SyncCallBack); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); + task.LeaveLine(++id); + task.LeaveLine(++id); +} + +/** + * @tc.name: clear + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(TaskSequencingTest, clear, TestSize.Level1) +{ + uint32_t id = 2; + bool ret = 0; + TaskSequencing task; + AsyncTaskFunc fun = AsyncCallBack; + ret = task.Clear(id); + EXPECT_EQ(ret, false); + + EXPECT_EQ(task.LineUp(fun), ErrorCode::NO_ERROR); + ret = task.Clear(id); + EXPECT_EQ(ret, false); + + task.taskQueue_.front()->SetStatus(TaskSequencing::TaskStatus::TS_RUN); + EXPECT_EQ(task.LineUp(fun), ErrorCode::NO_ERROR); + EXPECT_EQ(task.LineUp(fun), ErrorCode::NO_ERROR); + id = task.taskQueue_.front()->id + 2; + ret = task.Clear(id); + EXPECT_EQ(ret, true); +} + +/** + * @tc.name: handleRunStateTimeout + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(TaskSequencingTest, handleRunStateTimeout, TestSize.Level1) +{ + uint32_t id = 2; + TaskSequencing task; + AsyncTaskFunc fun = AsyncCallBack; + std::shared_ptr cv = task.CreateCv(); + EXPECT_NE(cv, nullptr); + + task.HandleRunStateTimeout(cv, id); + EXPECT_EQ(task.LineUp(AsyncCallBack), ErrorCode::NO_ERROR); + + id = task.taskQueue_.front()->id; + cv = task.CreateCv(); + EXPECT_NE(cv, nullptr); + task.HandleRunStateTimeout(cv, id - 1); + cv = task.CreateCv(); + EXPECT_NE(cv, nullptr); + std::thread t(std::bind(TriggerSignal, cv)); + task.HandleRunStateTimeout(cv, id); + t.join(); +} +} // namespace MiscServices +} // namespace OHOS