diff --git a/interfaces/native/innerkits/event/include/plugin_stage.h b/interfaces/native/innerkits/event/include/plugin_stage.h new file mode 100644 index 0000000000000000000000000000000000000000..5a43f65aa6786ff01f7da5537cea986c221be887 --- /dev/null +++ b/interfaces/native/innerkits/event/include/plugin_stage.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024-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 PLUGIN_STAGE_H +#define PLUGIN_STAGE_H + +#include "key_event.h" +#include "pointer_event.h" +#include "axis_event.h" +#include "input_device.h" +#include "libinput.h" + +namespace OHOS { +namespace MMI { + +enum class InputPluginStage { + INPUT_GLOBAL_INIT = 0, + INPUT_DEV_ADDED = 3, + INPUT_DEV_REMOVEED = 6, + INPUT_BEFORE_LIBINPUT_ADAPTER_ON_EVENT = 12, + INPUT_AFTER_LIBINPUT_ADAPTER_ON_EVENT = 13, + INPUT_BEFORE_NORMALIZED = 15, + INPUT_AFTER_NORMALIZED, + INPUT_DEVICE_CHANGE = 20, + INPUT_BEFORE_FILTER = 25, + INPUT_AFTER_FILTER, + INPUT_BEFORE_INTERCEPT = 30, + INPUT_AFTER_INTERCEPT, + INPUT_BEFORE_KEYCOMMAND = 35, + INPUT_AFTER_KEYCOMMAND, + INPUT_BEFORE_MONITOR = 40, + INPUT_AFTER_MONITOR, + INPUT_STAGE_BUTT, +}; + +enum class PluginResult { + Error = -1, + UseNeedReissue = 0, + NotUse, + UseNoNeedReissue, +}; + +enum class InputDispatchStage { + Filter = 0, + Intercept, + KeyCommand, + Monitor, +}; + +struct IPluginContext { + virtual int32_t AddTimer(std::function func, int32_t intervalMs, int32_t repeatCount) = 0; + virtual int32_t RemoveTimer(int32_t id) = 0; + void DispatchEvent(std::shared_ptr keyEvent, InputDispatchStage stage); + void DispatchEvent(std::shared_ptr pointerEvent, InputDispatchStage stage); + void DispatchEvent(std::shared_ptr AxisEvent, InputDispatchStage stage); + virtual void DispatchEvent(libinput_event *event, int64_t frameTime) = 0; +}; + +struct IInputPlugin { + virtual int32_t GetPriority() const = 0; + virtual const std::string GetVersion() const = 0; + virtual const std::string GetName() const = 0; + virtual InputPluginStage GetStage() const = 0; + virtual void DeviceWillAdded(std::shared_ptr inputDevice){}; + virtual void DeviceDidAdded(std::shared_ptr inputDevice){}; + virtual void DeviceWillRemoved(std::shared_ptr inputDevice){}; + virtual void DeviceDidRemoved(std::shared_ptr inputDevice){}; + virtual PluginResult HandleEvent(libinput_event *event, int64_t frameTime) const = 0; + virtual PluginResult HandleEvent(std::shared_ptr keyEvent, InputPluginStage stage) const = 0; + virtual PluginResult HandleEvent(std::shared_ptr pointerEvent, InputPluginStage stage) const = 0; + virtual PluginResult HandleEvent(std::shared_ptr axisEvent, InputPluginStage stage) const = 0; +}; +} // namespace MMI +} // namespace OHOS +#endif // PLUGIN_STAGE_H \ No newline at end of file diff --git a/multimodalinput_mini.gni b/multimodalinput_mini.gni index 0a7e3a92eca63b54802e83fa78b41ed91c2d2f9c..9d901cfcc2724bb0e8dc2bbe4c76e1e6968f039f 100644 --- a/multimodalinput_mini.gni +++ b/multimodalinput_mini.gni @@ -156,6 +156,7 @@ declare_args() { "module_loader/src/app_debug_listener.cpp", "module_loader/src/mmi_service.cpp", "module_loader/src/multimodal_input_preferences_manager.cpp", + "module_loader/src/multimodal_input_plugin_manager.cpp", "module_loader/src/uds_server.cpp", "module_loader/src/watchdog_task.cpp", "nap_process/src/nap_process.cpp", diff --git a/service/BUILD.gn b/service/BUILD.gn index 5a1cb538402ba20d8115e43f8a3c88cb3695d3e7..594b6523d7875e02587b8ed6db5b64e0b3a0c7d0 100644 --- a/service/BUILD.gn +++ b/service/BUILD.gn @@ -2006,15 +2006,18 @@ ohos_unittest("ModuleLoaderTest") { "module_loader/src/input_screen_capture_agent.cpp", "module_loader/test/input_screen_capture_agent_test.cpp", "module_loader/test/mmi_service_test.cpp", - "module_loader/test/multimodal_input_preferences_manager_test.cpp", "module_loader/test/uds_server_test.cpp", "module_loader/test/watchdog_task_test.cpp", + "module_loader/test/multimodal_input_preferences_manager_test.cpp", + "module_loader/test/multimodal_input_plugin_manager_test.cpp", ] deps = [ "${mmi_path}/frameworks/proxy:libmmi-common", "${mmi_path}/service:libmmi-server", "${mmi_path}/util:libmmi-util", + "${mmi_path}/test/facility/libinput_wrapper:libinput_wrapper_sources", + "${mmi_path}/test/facility/virtual_device:virtual_device_sources", ] external_deps = [ diff --git a/service/libinput_adapter/src/libinput_adapter.cpp b/service/libinput_adapter/src/libinput_adapter.cpp index 6480cdbe63856885bd8bb1d01ad1ede361e85988..4d9899115ccf1d906e6a86110d9a4844fd0d77e4 100644 --- a/service/libinput_adapter/src/libinput_adapter.cpp +++ b/service/libinput_adapter/src/libinput_adapter.cpp @@ -32,6 +32,7 @@ #include "common_event_manager.h" #include "common_event_support.h" #endif // OHOS_BUILD_ENABLE_VKEYBOARD +#include "multimodal_input_plugin_manager.h" #undef MMI_LOG_DOMAIN #define MMI_LOG_DOMAIN MMI_LOG_SERVER @@ -217,7 +218,26 @@ bool LibinputAdapter::Init(FunInputEvent funInputEvent) { CALL_DEBUG_ENTER; CHKPF(funInputEvent); - funInputEvent_ = funInputEvent; + + auto callback = [funInputEvent](libinput_event *event, int64_t frameTime) { + funInputEvent(static_cast(event), frameTime); + }; + auto manager = InputPluginManager::GetInstance(); + if (manager != nullptr) { + manager->PluginAssignmentCallBack(callback, InputPluginStage::INPUT_BEFORE_LIBINPUT_ADAPTER_ON_EVENT); + } + funInputEvent_ = [manager, callback](void *event, int64_t frameTime) { + if (manager != nullptr) { + int32_t result = manager->HandleEvent(static_cast(event), + frameTime, + InputPluginStage::INPUT_BEFORE_LIBINPUT_ADAPTER_ON_EVENT); + if (result != RET_NOTDO) { + return; + } + } + callback(static_cast(event), frameTime); + }; + input_ = libinput_path_create_context(&LIBINPUT_INTERFACE, nullptr); CHKPF(input_); libinput_log_set_handler(input_, &HiLogFunc); diff --git a/service/module_loader/include/multimodal_input_plugin_manager.h b/service/module_loader/include/multimodal_input_plugin_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..c30ad29407704302261152712897c3e375cf25ce --- /dev/null +++ b/service/module_loader/include/multimodal_input_plugin_manager.h @@ -0,0 +1,94 @@ +/* + * 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 MULTIMODAL_INPUT_PLUGIN_MANAGER_H +#define MULTIMODAL_INPUT_PLUGIN_MANAGER_H + +#include +#include + +#include +#include +#include + +namespace OHOS { +namespace MMI { + +/* 框架获取plugin对象 + * ctx: 框架注册给plugin调用框架的对象实例 + * plugin:plugin实例 + * return:= 0: success + * !=0: error + */ +typedef int32_t (*InitPlugin)(std::shared_ptr ctx, std::shared_ptr& plugin); +/* 框架通知plugin删除plugin对象 + * ctx: 框架注册给plugin调用框架的对象实例 + * plugin:plugin实例 + * return:= 0: success + * !=0: error + */ +typedef int32_t (*UnintPlugin)(std::shared_ptr plugin); + +const int32_t RET_NOTDO = 0; +const int32_t RET_DO = 1; + +struct InputPlugin : public IPluginContext { +public: + InputPlugin() {}; + virtual ~InputPlugin(); + int32_t Init(std::shared_ptr pin); + void UnInit(); + PluginResult HandleEvent(libinput_event *event, int64_t frameTime); + + int32_t AddTimer(std::function func, int32_t intervalMs, int32_t repeatCount) override; + int32_t RemoveTimer(int32_t id) override; + void DispatchEvent(libinput_event *event, int64_t frameTime) override; + + int32_t timerCnt_ = 0; + int32_t prio_ = 200; + std::function callback_; + UnintPlugin unintPlugin_ = nullptr; + std::shared_ptr plugin_; + std::string name_; + void* handle_; + +private: + InputPluginStage stage_; +}; + +struct InputPluginManager { +public: + ~InputPluginManager(); + explicit InputPluginManager(const std::string& directory) : directory_(directory) {}; + static std::shared_ptr GetInstance(const std::string &directory = ""); + int32_t Init(); + void Dump(int fd); + int32_t HandleEvent(libinput_event* event, int64_t frameTime, InputPluginStage stage); + void PluginAssignmentCallBack(std::function callback, InputPluginStage stage); + void PrintPlugins(); + int32_t DoHandleEvent(libinput_event *event, int64_t frameTime, InputPlugin *iplugin, InputPluginStage stage); + +private: + bool IntermediateEndEvent(libinput_event *event); + bool LoadPlugin(const std::string &path); + + std::string directory_; + std::map>> plugins_; + static std::shared_ptr instance_; + static std::once_flag init_flag_; +}; +} // namespace MMI +} // namespace OHOS +#endif // MULTIMODAL_INPUT_PLUGIN_MANAGER_H diff --git a/service/module_loader/src/mmi_service.cpp b/service/module_loader/src/mmi_service.cpp index 5469384be5e9c7fb6fe8199136b24e10b8c05926..f54f2a9948436689aad79b4595ae5d9d0e2a2953 100644 --- a/service/module_loader/src/mmi_service.cpp +++ b/service/module_loader/src/mmi_service.cpp @@ -66,6 +66,7 @@ #include "touchpad_settings_handler.h" #include "account_manager.h" #endif // OHOS_BUILD_ENABLE_POINTER +#include "multimodal_input_plugin_manager.h" #ifdef OHOS_RSS_CLIENT #include "res_sched_client.h" @@ -404,6 +405,7 @@ int32_t MMIService::Init() NapProcess::GetInstance()->Init(*this); MMI_HILOGD("ANRManager Init"); ANRMgr->Init(*this); + InputPluginManager::GetInstance()->Init(); MMI_HILOGI("PointerDrawingManager Init"); #if defined(OHOS_BUILD_ENABLE_POINTER) && defined(OHOS_BUILD_ENABLE_POINTER_DRAWING) if (!CursorDrawingComponent::GetInstance().Init()) { diff --git a/service/module_loader/src/multimodal_input_plugin_manager.cpp b/service/module_loader/src/multimodal_input_plugin_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae13d69ca6cc70cf65cb26cc39de936d8fd14be0 --- /dev/null +++ b/service/module_loader/src/multimodal_input_plugin_manager.cpp @@ -0,0 +1,342 @@ +/* + * 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 "multimodal_input_plugin_manager.h" + +#include "mmi_log.h" +#include + +#undef MMI_LOG_DOMAIN +#define MMI_LOG_DOMAIN MMI_LOG_SERVER +#undef MMI_LOG_TAG +#define MMI_LOG_TAG "MultiModalInputPluginManager" + +namespace OHOS { +namespace MMI { +std::shared_ptr InputPluginManager::instance_; +std::once_flag InputPluginManager::init_flag_; + +const char *FILE_EXTENSION = ".so"; +const char *FOLDER_PATH = "/system/lib64/multimodalinput/autorun"; +const int32_t TIMEOUT_US = 300; +const int32_t MAX_TIMER = 3; + +InputPluginManager::~InputPluginManager() +{ + plugins_.clear(); + if (instance_ != nullptr) { + instance_ = nullptr; + } + MMI_HILOGI("~InputPluginManager"); +} + +std::shared_ptr InputPluginManager::GetInstance(const std::string &directory) +{ + std::call_once(init_flag_, [&directory] { + if (instance_ == nullptr) { + MMI_HILOGI("New InputPluginManager"); + std::string dir = directory.empty() ? FOLDER_PATH : directory; + instance_ = std::make_shared(dir); + } + }); + return instance_; +} + +int32_t InputPluginManager::Init() +{ + CALL_DEBUG_ENTER; + DIR *dir = opendir(directory_.c_str()); + if (!dir) { + MMI_HILOGE("Failed to open error:%{private}s", strerror(errno)); + return RET_OK; + } + struct dirent *entry; + while ((entry = readdir(dir)) != nullptr) { + if (entry->d_type == DT_REG && std::string(entry->d_name) != "." && std::string(entry->d_name) != "..") { + std::string path = directory_ + "/" + entry->d_name; + if (path.length() >= strlen(FILE_EXTENSION) && + path.substr(path.size() - strlen(FILE_EXTENSION)) == FILE_EXTENSION) { + LoadPlugin(path); + } + } + } + closedir(dir); + PrintPlugins(); + return RET_OK; +} + +bool InputPluginManager::LoadPlugin(const std::string &path) +{ + CALL_DEBUG_ENTER; + void *handle = dlopen(path.c_str(), RTLD_LAZY); + if (!handle) { + MMI_HILOGE("Failed to load directory: %{private}s", dlerror()); + return false; + } + + InitPlugin func = reinterpret_cast(dlsym(handle, "InitPlugin")); + if (!func) { + MMI_HILOGE("Failed to find symbol InitPlugin in: %{private}s", dlerror()); + dlclose(handle); + return false; + } + + std::shared_ptr cPin = std::make_shared(); + if (!cPin) { + dlclose(handle); + return false; + } + + cPin->unintPlugin_ = reinterpret_cast(dlsym(handle, "UnintPlugin")); + if (!cPin->unintPlugin_) { + MMI_HILOGE("Failed to find symbol UnintPlugin in: %{private}s", dlerror()); + dlclose(handle); + return false; + } + std::shared_ptr iPin; + int32_t ret = func(cPin, iPin); + if (ret != 0 || !iPin) { + MMI_HILOGE("Failed to InitPlugin plugin."); + dlclose(handle); + return false; + } + ret = cPin->Init(iPin); + if (ret != 0) { + MMI_HILOGE("Failed to Init plugin."); + dlclose(handle); + return false; + } + cPin->handle_ = handle; + InputPluginStage stage = iPin->GetStage(); + + auto result = plugins_.insert({stage, {cPin}}); + if (!result.second) { + auto it = std::lower_bound(result.first->second.begin(), result.first->second.end(), cPin, + [](const std::shared_ptr &a, const std::shared_ptr &b) { + return a->prio_ < b->prio_; + }); + result.first->second.insert(it, cPin); + } + return true; +} + +void InputPluginManager::PrintPlugins() +{ + for (const auto &stagePlugins : plugins_) { + MMI_HILOGI("InputPluginManager InputPluginStage : %{public}d", stagePlugins.first); + for (const auto &plugin : stagePlugins.second) { + MMI_HILOGI("InputPluginManager : name:%{public}s prio_:%{public}d", + plugin->name_.c_str(), plugin->prio_); + } + } +} + +void InputPluginManager::PluginAssignmentCallBack( + std::function callback, InputPluginStage stage) +{ + CALL_DEBUG_ENTER; + auto it = plugins_.find(stage); + if (it == plugins_.end()) { + MMI_HILOGI("plugins_ not stage:%{public}d.", stage); + return; + } + for (auto &plugin : it->second) { + plugin->callback_ = callback; + } +} + +int32_t InputPluginManager::HandleEvent(libinput_event *event, int64_t frameTime, InputPluginStage stage) +{ + return DoHandleEvent(event, frameTime, nullptr, stage); +} + +int32_t InputPluginManager::DoHandleEvent( + libinput_event *event, int64_t frameTime, InputPlugin *iplugin, InputPluginStage stage) +{ + if (event == nullptr) { + return RET_NOTDO; + } + auto it = plugins_.find(stage); + if (it == plugins_.end()) { + return RET_NOTDO; + } + CALL_DEBUG_ENTER; + auto &plugins = it->second; + auto start_plugin = plugins.begin(); + if (iplugin != nullptr) { + auto cur_plugin = std::find_if(plugins.begin(), plugins.end(), + [iplugin](const std::shared_ptr &plugin) { return plugin.get() == iplugin; }); + if (cur_plugin == plugins.end()) { + return RET_NOTDO; + } + start_plugin = std::next(cur_plugin); + } + int64_t beginTime = 0; + PluginResult result; + int64_t endTime = 0; + int64_t lostTime = 0; + for (auto pluginIt = start_plugin; pluginIt != plugins.end(); ++pluginIt) { + if ((*pluginIt) == nullptr) { + continue; + } + beginTime = GetSysClockTime(); + result = (*pluginIt)->HandleEvent(event, frameTime); + endTime = GetSysClockTime(); + lostTime = endTime - beginTime; + if (lostTime >= TIMEOUT_US) { + MMI_HILOGE("pluginIt timeout name:%{public}s ,endTime:%{public}" PRId64 ",lostTime:%{public}" PRId64, + (*pluginIt)->name_.c_str(), endTime, lostTime); + } + if (result == PluginResult::UseNeedReissue) { + if (IntermediateEndEvent(event)) { + MMI_HILOGE("pluginIt is intermediate or end event"); + continue; + } + return RET_DO; + } else if (result == PluginResult::UseNoNeedReissue) { + return RET_DO; + } else if (result == PluginResult::Error) { + MMI_HILOGE("pluginIt err name:%{public}s", (*pluginIt)->name_.c_str()); + } + } + return RET_NOTDO; +} + +// LIBINPUT_EVENT_TABLET_TOOL_BUTTON、LIBINPUT_EVENT_TABLET_PAD_BUTTON、LIBINPUT_EVENT_TABLET_PAD_KEY +// These few existence termination events are currently not used and will be supplemented after use +bool InputPluginManager::IntermediateEndEvent(libinput_event *event) +{ + const libinput_event_type type = libinput_event_get_type(event); + switch (type) { + case LIBINPUT_EVENT_POINTER_MOTION: + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: + case LIBINPUT_EVENT_POINTER_AXIS: + case LIBINPUT_EVENT_POINTER_SCROLL_FINGER: + case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS: + case LIBINPUT_EVENT_POINTER_MOTION_TOUCHPAD: + case LIBINPUT_EVENT_POINTER_SCROLL_FINGER_END: + case LIBINPUT_EVENT_JOYSTICK_AXIS: + case LIBINPUT_EVENT_TOUCH_UP: + case LIBINPUT_EVENT_TOUCH_MOTION: + case LIBINPUT_EVENT_TOUCH_CANCEL: + case LIBINPUT_EVENT_TOUCHPAD_UP: + case LIBINPUT_EVENT_TOUCHPAD_MOTION: + case LIBINPUT_EVENT_TABLET_TOOL_AXIS: + case LIBINPUT_EVENT_TABLET_PAD_RING: + case LIBINPUT_EVENT_TABLET_PAD_STRIP: + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: + case LIBINPUT_EVENT_GESTURE_SWIPE_END: + case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: + case LIBINPUT_EVENT_GESTURE_PINCH_END: + case LIBINPUT_EVENT_GESTURE_HOLD_END: + return true; + case LIBINPUT_EVENT_KEYBOARD_KEY: { + struct libinput_event_keyboard *keyboardEvent = libinput_event_get_keyboard_event(event); + CHKPR(keyboardEvent, false); + return libinput_event_keyboard_get_key_state(keyboardEvent) == LIBINPUT_KEY_STATE_RELEASED; + } + case LIBINPUT_EVENT_POINTER_BUTTON: + case LIBINPUT_EVENT_POINTER_TAP: + case LIBINPUT_EVENT_POINTER_BUTTON_TOUCHPAD: { + auto touchpadButtonEvent = libinput_event_get_pointer_event(event); + CHKPR(touchpadButtonEvent, false); + return libinput_event_pointer_get_button_state(touchpadButtonEvent) == LIBINPUT_BUTTON_STATE_RELEASED; + } + case LIBINPUT_EVENT_JOYSTICK_BUTTON: { + auto rawBtnEvent = libinput_event_get_joystick_button_event(event); + CHKPR(rawBtnEvent, false); + return libinput_event_joystick_button_get_key_state(rawBtnEvent) == LIBINPUT_BUTTON_STATE_RELEASED; + } + case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: { + auto tabletEvent = libinput_event_get_tablet_tool_event(event); + CHKPR(tabletEvent, false); + return libinput_event_tablet_tool_get_proximity_state(tabletEvent) == + LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT; + } + case LIBINPUT_EVENT_TABLET_TOOL_TIP: { + auto tabletEvent = libinput_event_get_tablet_tool_event(event); + CHKPR(tabletEvent, false); + return libinput_event_tablet_tool_get_tip_state(tabletEvent) == LIBINPUT_TABLET_TOOL_TIP_UP; + } + default: + break; + } + return false; +} + +int32_t InputPlugin::Init(std::shared_ptr pin) +{ + name_ = pin->GetName(); + prio_ = pin->GetPriority(); + stage_ = pin->GetStage(); + plugin_ = pin; + return RET_OK; +} + +void InputPlugin::UnInit() +{ + CHKPV(plugin_); + MMI_HILOGI("InputPlugin UnInit Start name:%{public}s.", name_.c_str()); + if (unintPlugin_) { + unintPlugin_(plugin_); + } +} + +void InputPlugin::DispatchEvent(libinput_event *event, int64_t frameTime) +{ + int32_t result = InputPluginManager::GetInstance()->DoHandleEvent(event, frameTime, this, stage_); + if (result == RET_NOTDO) { + CHKPV(callback_); + callback_(event, frameTime); + } +} + +PluginResult InputPlugin::HandleEvent(libinput_event *event, int64_t frameTime) +{ + CHKPR(plugin_, PluginResult::NotUse); + return plugin_->HandleEvent(event, frameTime); +} + +int32_t InputPlugin::AddTimer(std::function func, int32_t intervalMs, int32_t repeatCount) +{ + if (timerCnt_ >= MAX_TIMER) { + return RET_ERR; + } + int32_t timerId = TimerMgr->AddTimerInternal(intervalMs, repeatCount, func, name_); + if (timerId != -1) { + timerCnt_++; + } + return timerId; +} + +int32_t InputPlugin::RemoveTimer(int32_t id) +{ + int32_t result = TimerMgr->RemoveTimer(id, name_); + if (timerCnt_ > 0) { + timerCnt_--; + } + return result; +} + +InputPlugin::~InputPlugin() +{ + if (handle_) { + dlclose(handle_); + handle_ = nullptr; + } + MMI_HILOGI("~InputPlugin"); +} +} // namespace MMI +} // namespace OHOS diff --git a/service/module_loader/test/multimodal_input_plugin_manager_test.cpp b/service/module_loader/test/multimodal_input_plugin_manager_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa09c205b4fed1b380fd5f047b80d38893c4a384 --- /dev/null +++ b/service/module_loader/test/multimodal_input_plugin_manager_test.cpp @@ -0,0 +1,139 @@ +/* + * 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 +#include + +#include "general_mouse.h" +#include "libinput_wrapper.h" +#include "multimodal_input_plugin_manager.h" + +#undef MMI_LOG_TAG +#define MMI_LOG_TAG "MultimodalInputPluginManagerTest" +namespace OHOS { +namespace MMI { +namespace { +using namespace testing::ext; +} // namespace + +const std::string PATH { "/system/lib64/multimodalinput/autorun" }; + +class MultimodalInputPluginManagerTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + static void SetupMouse(); + static void CloseMouse(); + + void SetUp(); +private: + std::shared_ptr manager; + static LibinputWrapper libinput_; + static GeneralMouse vMouse_; +}; + +GeneralMouse MultimodalInputPluginManagerTest::vMouse_; +LibinputWrapper MultimodalInputPluginManagerTest::libinput_; + + +void MultimodalInputPluginManagerTest::SetUpTestCase(void) +{ + ASSERT_TRUE(libinput_.Init()); + SetupMouse(); +} + +void MultimodalInputPluginManagerTest::TearDownTestCase(void) +{ + CloseMouse(); +} + +void MultimodalInputPluginManagerTest::SetupMouse() +{ + ASSERT_TRUE(vMouse_.SetUp()); + std::cout << "device node name: " << vMouse_.GetDevPath() << std::endl; + ASSERT_TRUE(libinput_.AddPath(vMouse_.GetDevPath())); + + libinput_event *event = libinput_.Dispatch(); + ASSERT_TRUE(event != nullptr); + ASSERT_EQ(libinput_event_get_type(event), LIBINPUT_EVENT_DEVICE_ADDED); +} + +void MultimodalInputPluginManagerTest::CloseMouse() +{ + libinput_.RemovePath(vMouse_.GetDevPath()); + vMouse_.Close(); +} + +void MultimodalInputPluginManagerTest::SetUp() +{ + manager = std::make_shared(PATH); +} + +/** + * @tc.name : MultimodalInputPluginManagerTest_Init_001 + * @tc.number: Init_001 + * @tc.desc : 测试初始化是否成功 + */ +HWTEST_F(MultimodalInputPluginManagerTest, MultimodalInputPluginManagerTest_Init_001, TestSize.Level0) { + int32_t valV1 = manager->Init(); + EXPECT_EQ(valV1, RET_OK); +} + +/** + * @tc.name: MultimodalInputPluginManagerTest_HandleEvent_02 + * @tc.desc: Test_HandleEvent_02 + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(MultimodalInputPluginManagerTest, MultimodalInputPluginManagerTest_HandleEvent_02, TestSize.Level1) +{ + CALL_TEST_DEBUG; + vMouse_.SendEvent(EV_REL, REL_X, 5); + vMouse_.SendEvent(EV_REL, REL_Y, -10); + vMouse_.SendEvent(EV_SYN, SYN_REPORT, 0); + + libinput_event *event = libinput_.Dispatch(); + ASSERT_TRUE(event != nullptr); + struct libinput_device *dev = libinput_event_get_device(event); + ASSERT_TRUE(dev != nullptr); + std::cout << "pointer device: " << libinput_device_get_name(dev) << std::endl; + int32_t result = manager->HandleEvent(event, GetSysClockTime(), + InputPluginStage::INPUT_BEFORE_LIBINPUT_ADAPTER_ON_EVENT); + EXPECT_GE(result, RET_OK); +} + +/** + * @tc.name: MultimodalInputPluginManagerTest_IntermediateEndEvent_03 + * @tc.desc: Test_IntermediateEndEvent_03 + * @tc.require: + */ +HWTEST_F(MultimodalInputPluginManagerTest, MultimodalInputPluginManagerTest_IntermediateEndEvent_03, TestSize.Level1) +{ + CALL_TEST_DEBUG; + vMouse_.SendEvent(EV_REL, REL_X, 5); + vMouse_.SendEvent(EV_REL, REL_Y, -10); + vMouse_.SendEvent(EV_SYN, SYN_REPORT, 0); + + libinput_event *event = libinput_.Dispatch(); + ASSERT_TRUE(event != nullptr); + struct libinput_device *dev = libinput_event_get_device(event); + ASSERT_TRUE(dev != nullptr); + std::cout << "pointer device: " << libinput_device_get_name(dev) << std::endl; + + EXPECT_TRUE(manager->IntermediateEndEvent(event)); +} + +} // namespace MMI +} // namespace OHOS diff --git a/service/timer_manager/include/timer_manager.h b/service/timer_manager/include/timer_manager.h index d8395cf0cb727a423d2a05c892570fd20b844071..6ad0f616707cd1d344945d4a17048e18faea528f 100644 --- a/service/timer_manager/include/timer_manager.h +++ b/service/timer_manager/include/timer_manager.h @@ -54,11 +54,13 @@ public: const std::string &name = ""); int32_t AddLongTimer(int32_t intervalMs, int32_t repeatCount, std::function callback, const std::string &name = ""); - int32_t RemoveTimer(int32_t timerId); + int32_t RemoveTimer(int32_t timerId, const std::string &name = ""); int32_t ResetTimer(int32_t timerId); bool IsExist(int32_t timerId); int32_t CalcNextDelay(); void ProcessTimers(); + int32_t AddTimerInternal(int32_t intervalMs, int32_t repeatCount, std::function callback, + const std::string &name = ""); private: struct TimerItem { @@ -72,9 +74,7 @@ private: }; private: int32_t TakeNextTimerId(); - int32_t AddTimerInternal(int32_t intervalMs, int32_t repeatCount, std::function callback, - const std::string &name = ""); - int32_t RemoveTimerInternal(int32_t timerId); + int32_t RemoveTimerInternal(int32_t timerId, const std::string &name = ""); int32_t ResetTimerInternal(int32_t timerId); bool IsExistInternal(int32_t timerId); void InsertTimerInternal(std::unique_ptr& timer); diff --git a/service/timer_manager/src/timer_manager.cpp b/service/timer_manager/src/timer_manager.cpp index ccd8d6373ffb180dc2170101d17a2d9037de0c06..2fb519935445e83c4295b13999947a9bd93c74cc 100644 --- a/service/timer_manager/src/timer_manager.cpp +++ b/service/timer_manager/src/timer_manager.cpp @@ -56,9 +56,9 @@ int32_t TimerManager::AddLongTimer(int32_t intervalMs, int32_t repeatCount, std: return AddTimerInternal(intervalMs, repeatCount, callback, name); } -int32_t TimerManager::RemoveTimer(int32_t timerId) +int32_t TimerManager::RemoveTimer(int32_t timerId, const std::string &name) { - return RemoveTimerInternal(timerId); + return RemoveTimerInternal(timerId, name); } int32_t TimerManager::ResetTimer(int32_t timerId) @@ -125,11 +125,11 @@ int32_t TimerManager::AddTimerInternal(int32_t intervalMs, int32_t repeatCount, return timerId; } -int32_t TimerManager::RemoveTimerInternal(int32_t timerId) +int32_t TimerManager::RemoveTimerInternal(int32_t timerId, const std::string &name) { std::lock_guard lock(timerMutex_); for (auto it = timers_.begin(); it != timers_.end(); ++it) { - if ((*it)->id == timerId) { + if ((*it)->id == timerId && (name.empty() || (*it)->name == name)) { timers_.erase(it); return RET_OK; } diff --git a/service/timer_manager/test/timer_manager_test.cpp b/service/timer_manager/test/timer_manager_test.cpp index bbddc7fe5f50a067bfe0e04a7f10c7c0ba66e0f6..674919c30dcc5829e82cd27c48298745bf4a88d1 100644 --- a/service/timer_manager/test/timer_manager_test.cpp +++ b/service/timer_manager/test/timer_manager_test.cpp @@ -114,6 +114,21 @@ HWTEST_F(TimerManagerTest, TimerManagerTest_ManagerTimer_005, TestSize.Level1) EXPECT_EQ(timerld, -1); } +/** + * @tc.name: TimerManagerTest_ManagerTimer_006 + * @tc.desc: Test the function RemoveTimer + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(TimerManagerTest, TimerManagerTest_ManagerTimer_006, TestSize.Level1) +{ + CALL_TEST_DEBUG; + int32_t repeatCount = 3; + int32_t intervalMs = 1000; + int32_t timerld = TimerMgr->AddTimerInternal(intervalMs, repeatCount, AddTimerCallback, "test006"); + ASSERT_EQ(TimerMgr->RemoveTimer(timerld, "test006"), 0); +} + /** * @tc.name: TimerManagerTest_AddTimer_001 * @tc.desc: Test adding a timer to the TimerManager diff --git a/service/window_manager/test/mock.cpp b/service/window_manager/test/mock.cpp index 55cbd2e9ce6e7453268c555a784bc63ff27e61bd..29bd3a213421f6a53a89d2ed7cfc2f57f3280975 100644 --- a/service/window_manager/test/mock.cpp +++ b/service/window_manager/test/mock.cpp @@ -170,7 +170,7 @@ int32_t TimerManager::AddTimer(int32_t intervalMs, int32_t repeatCount, std::fun return 0; } -int32_t TimerManager::RemoveTimer(int32_t timerId) +int32_t TimerManager::RemoveTimer(int32_t timerId, const std::string &name) { return 0; }