From 3b322fc94d169078738d0b431bdc3a976e4fd76c Mon Sep 17 00:00:00 2001 From: blueyouth Date: Wed, 25 Jun 2025 19:23:24 +0800 Subject: [PATCH] Load touch drawing dynamically (part 1) Signed-off-by: blueyouth Change-Id: I3cefc201ab58e8e9dc04c183e8b839ab7674b16e --- frameworks/proxy/BUILD.gn | 9 +- intention/prototype/include/i_context.h | 33 +- .../BUILD.gn | 43 +- .../include/component_manager.h | 190 ++++ .../plugin_manager/include/plugin_manager.h | 119 --- service/BUILD.gn | 1 + .../include/i_touch_drawing_handler.h | 60 +- .../include/touch_drawing_handler.h | 144 +++ .../src/touch_drawing_handler.cpp | 853 ++++++++++++++++++ 9 files changed, 1235 insertions(+), 217 deletions(-) rename intention/scheduler/{plugin_manager => component_manager}/BUILD.gn (42%) create mode 100644 intention/scheduler/component_manager/include/component_manager.h delete mode 100644 intention/scheduler/plugin_manager/include/plugin_manager.h rename intention/scheduler/plugin_manager/src/plugin_manager.cpp => service/window_manager/include/i_touch_drawing_handler.h (34%) create mode 100644 service/window_manager/include/touch_drawing_handler.h create mode 100644 service/window_manager/src/touch_drawing_handler.cpp diff --git a/frameworks/proxy/BUILD.gn b/frameworks/proxy/BUILD.gn index 2a552de12c..80084a1ee8 100644 --- a/frameworks/proxy/BUILD.gn +++ b/frameworks/proxy/BUILD.gn @@ -24,9 +24,8 @@ config("libmmi_client_config") { include_dirs = [ "${mmi_path}/interfaces/kits/c/input", - "${mmi_path}/interfaces/native/innerkits/common/include", - "${mmi_path}/util/common/include", "${mmi_path}/interfaces/native/innerkits/event/include", + "${mmi_path}/interfaces/native/innerkits/proxy/include", "event_handler/include", "events/include", "module_loader/include", @@ -60,6 +59,12 @@ config("libmmi_test_util") { } ohos_source_set("libmmi-common") { + include_dirs = [ + "${mmi_path}/interfaces/native/innerkits/event/include", + "${mmi_path}/interfaces/native/innerkits/proxy/include", + "${mmi_path}/util/common/include", + ] + sources = libmmi_common_sources public_configs = [ ":libmmi_client_config" ] visibility = [ "${mmi_path}/*" ] diff --git a/intention/prototype/include/i_context.h b/intention/prototype/include/i_context.h index ff962fb7d2..cf7f6e5b39 100644 --- a/intention/prototype/include/i_context.h +++ b/intention/prototype/include/i_context.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Copyright (c) 2022-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 @@ -15,40 +15,13 @@ #ifndef I_CONTEXT_H #define I_CONTEXT_H - -#include "i_delegate_tasks.h" -#include "i_device_manager.h" -#include "i_drag_manager.h" -#include "i_dsoftbus_adapter.h" -#include "i_input_adapter.h" -#include "i_socket_session_manager.h" -#include "i_plugin_manager.h" -#include "i_timer_manager.h" - namespace OHOS { -namespace Msdp { -namespace DeviceStatus { -struct MouseLocation { - int32_t physicalX { 0 }; - int32_t physicalY { 0 }; -}; - +namespace MMI { class IContext { public: IContext() = default; virtual ~IContext() = default; - - virtual IDelegateTasks& GetDelegateTasks() = 0; - virtual IDeviceManager& GetDeviceManager() = 0; - virtual ITimerManager& GetTimerManager() = 0; - virtual IDragManager& GetDragManager() = 0; - - virtual ISocketSessionManager& GetSocketSessionManager() = 0; - virtual IPluginManager& GetPluginManager() = 0; - virtual IInputAdapter& GetInput() = 0; - virtual IDSoftbusAdapter& GetDSoftbus() = 0; }; -} // namespace DeviceStatus -} // namespace Msdp +} // namespace MMI } // namespace OHOS #endif // I_CONTEXT_H \ No newline at end of file diff --git a/intention/scheduler/plugin_manager/BUILD.gn b/intention/scheduler/component_manager/BUILD.gn similarity index 42% rename from intention/scheduler/plugin_manager/BUILD.gn rename to intention/scheduler/component_manager/BUILD.gn index 2cc5dde250..1946fe1dd2 100644 --- a/intention/scheduler/plugin_manager/BUILD.gn +++ b/intention/scheduler/component_manager/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Huawei Device Co., Ltd. +# Copyright (c) 2023-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 @@ -11,53 +11,38 @@ # See the License for the specific language governing permissions and # limitations under the License. -import("../../../device_status.gni") +import("../../../multimodalinput_mini.gni") -config("plugin_manager_config") { +config("component_manager_config") { include_dirs = [ "include", - "${device_status_root_path}/interfaces/innerkits/interaction/include", + "${mmi_path}/intention/prototype/include", ] } -ohos_source_set("intention_plugin_manager") { +ohos_source_set("mmi_component_manager") { + branch_protector_ret = "pac_ret" sanitize = { - integer_overflow = true - ubsan = true - boundary_sanitize = true cfi = true cfi_cross_dso = true debug = false } - branch_protector_ret = "pac_ret" - include_dirs = [ "include", - "${device_status_root_path}/interfaces/innerkits/interaction/include", + "${mmi_path}/intention/prototype/include", ] - sources = [ "src/plugin_manager.cpp" ] + sources = [] - public_configs = [ ":plugin_manager_config" ] + public_configs = [ ":component_manager_config" ] - defines = device_status_default_defines - defines += [ "__aarch64__" ] + defines = input_default_defines - deps = [ - "${device_status_root_path}/intention/prototype:intention_prototype", - "${device_status_root_path}/utils/ipc:devicestatus_ipc", - "${device_status_utils_path}:devicestatus_util", - ] + deps = [] - external_deps = [ - "c_utils:utils", - "graphic_2d:librender_service_client", - "hilog:libhilog", - "image_framework:image_native", - "input:libmmi-client", - ] + external_deps = [ "hilog:libhilog" ] - subsystem_name = "${device_status_subsystem_name}" - part_name = "${device_status_part_name}" + subsystem_name = "${mmi_subsystem_name}" + part_name = "${mmi_part_name}" } diff --git a/intention/scheduler/component_manager/include/component_manager.h b/intention/scheduler/component_manager/include/component_manager.h new file mode 100644 index 0000000000..1b2c0d84b9 --- /dev/null +++ b/intention/scheduler/component_manager/include/component_manager.h @@ -0,0 +1,190 @@ +/* + * 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 COMPONENT_MANAGER_H +#define COMPONENT_MANAGER_H + +#include +#include +#include + +#include "define_multimodal.h" +#include "i_context.h" + +#undef MMI_LOG_DOMAIN +#define MMI_LOG_DOMAIN MMI_LOG_SERVER +#undef MMI_LOG_TAG +#define MMI_LOG_TAG "ComponentManager" + +namespace OHOS { +namespace MMI { + +// Loading、unloading and bookkeeping of modules. +class ComponentManager final { +private: + template + using CreateComponent = IComponent* (*)(IContext *context); + + template + using DestroyComponent = void (*)(IComponent *); + +public: + template + class Component final { + public: + Component(IContext *context, void *handle); + Component(Component &&other); + ~Component(); + DISALLOW_COPY(Component); + + Component& operator=(Component &&other); + void operator()(IComponent *instance); + IComponent* GetInstance(); + + private: + void DeleteInstance(IComponent *instance); + void Unload(); + + IContext *context_ { nullptr }; + void *handle_ { nullptr }; + IComponent *instance_ { nullptr }; + }; + + ComponentManager() = default; + ~ComponentManager() = default; + DISALLOW_COPY_AND_MOVE(ComponentManager); + + template + static std::unique_ptr> LoadLibrary(IContext *context, const char *libPath); +}; + +template +ComponentManager::Component::Component(IContext *context, void *handle) + : context_(context), handle_(handle) +{} + +template +ComponentManager::Component::~Component() +{ + Unload(); +} + +template +ComponentManager::Component::Component(ComponentManager::Component &&other) + : context_(other.context_), handle_(other.handle_), instance_(other.instance_) +{ + other.context_ = nullptr; + other.handle_ = nullptr; + other.instance_ = nullptr; +} + +template +ComponentManager::Component& ComponentManager::Component::operator=( + Component &&other) +{ + if (&other == this) { + return *this; + } + Unload(); + context_ = other.context_; + handle_ = other.handle_; + instance_ = other.instance_; + other.context_ = nullptr; + other.handle_ = nullptr; + other.instance_ = nullptr; + return *this; +} + +template +void ComponentManager::Component::operator()(IComponent *instance) +{ + DeleteInstance(instance); +} + +template +IComponent* ComponentManager::Component::GetInstance() +{ + if (instance_ != nullptr) { + return instance_; + } + ::dlerror(); + CreateComponent create = + reinterpret_cast>(::dlsym(handle_, "CreateInstance")); + if (auto err = ::dlerror(); err != nullptr) { + MMI_HILOGE("dlsym('DestroyInstance') fail: %{public}s", err); + return; + } + instance_ = create(context_); + return instance_; +} + +template +void ComponentManager::Component::DeleteInstance(IComponent *instance) +{ + if ((handle_ == nullptr) || (instance_ == nullptr) || (instance_ != instance)) { + return; + } + ::dlerror(); + DestroyComponent destroy = + reinterpret_cast>(::dlsym(handle_, "DestroyInstance")); + if (auto err = ::dlerror(); err != nullptr) { + MMI_HILOGE("dlsym('DestroyInstance') fail: %{public}s", err); + return; + } + destroy(instance_); + instance_ = nullptr; +} + +template +void ComponentManager::Component::Unload() +{ + if (handle_ != nullptr) { + DeleteInstance(instance_); + if (::dlclose(handle_) != RET_OK) { + MMI_HILOGE("dlclose fail: %{public}s", ::dlerror()); + } + handle_ = nullptr; + } +} + +template +std::unique_ptr> ComponentManager::LoadLibrary( + IContext *context, const char *libPath) +{ + if (libPath == nullptr) { + MMI_HILOGE("libPath is null"); + return { nullptr, ComponentManager::Component(nullptr, nullptr) }; + } + auto realPath = ::realpath(libPath, nullptr); + if (realPath == nullptr) { + MMI_HILOGE("Not real path: %{public}s", libPath); + return { nullptr, ComponentManager::Component(nullptr, nullptr) }; + } + void *handle = ::dlopen(realPath, RTLD_NOW); + ::free(realPath); + if (handle == nullptr) { + if (auto err = ::dlerror(); err != nullptr) { + MMI_HILOGE("dlopen fail for %{public}s: %{public}s", libPath, err); + } else { + MMI_HILOGE("dlopen fail for %{public}s", libPath); + } + return { nullptr, ComponentManager::Component(nullptr, nullptr) }; + } + Component plugin(context, handle); + return { plugin.GetInstance(), std::move(plugin) }; +} +} // namespace MMI +} // namespace OHOS +#endif // COMPONENT_MANAGER_H diff --git a/intention/scheduler/plugin_manager/include/plugin_manager.h b/intention/scheduler/plugin_manager/include/plugin_manager.h deleted file mode 100644 index 972a82bf41..0000000000 --- a/intention/scheduler/plugin_manager/include/plugin_manager.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef PLUGIN_MANAGER_H -#define PLUGIN_MANAGER_H - -#include -#include - -#include - -#include "nocopyable.h" - -#include "i_context.h" -#include "i_plugin_manager.h" - -namespace OHOS { -namespace Msdp { -namespace DeviceStatus { - -// Loading、unloading and bookkeeping of modules. -class PluginManager final : public IPluginManager { - template - class Plugin final { - public: - Plugin(IContext *context, void *handle); - ~Plugin(); - DISALLOW_COPY_AND_MOVE(Plugin); - - IPlugin* GetInstance(); - - private: - IContext *context_ { nullptr }; - void *handle_ { nullptr }; - IPlugin *instance_ { nullptr }; - }; - - template - using CreatePlugin = IPlugin* (*)(IContext *context); - - template - using DestroyPlugin = void (*)(IPlugin *); - -public: - PluginManager(IContext *context) : context_(context) {} - ~PluginManager() = default; - DISALLOW_COPY_AND_MOVE(PluginManager); - - ICooperate* LoadCooperate() override; - void UnloadCooperate() override; - -private: - template - std::unique_ptr> LoadLibrary(IContext *context, const char *libPath); - -private: - std::mutex lock_; - IContext *context_ { nullptr }; - std::unique_ptr> cooperate_ { nullptr }; -}; - -template -PluginManager::Plugin::Plugin(IContext *context, void *handle) - : context_(context), handle_(handle) -{} - -template -PluginManager::Plugin::~Plugin() -{ - if (instance_ != nullptr) { - DestroyPlugin destroy = - reinterpret_cast>(::dlsym(handle_, "DestroyInstance")); - if (destroy != nullptr) { - destroy(instance_); - } - } - ::dlclose(handle_); -} - -template -IPlugin* PluginManager::Plugin::GetInstance() -{ - if (instance_ != nullptr) { - return instance_; - } - CreatePlugin create = reinterpret_cast>(::dlsym(handle_, "CreateInstance")); - if (create != nullptr) { - instance_ = create(context_); - } - return instance_; -} - -template -std::unique_ptr> PluginManager::LoadLibrary(IContext *context, const char *libPath) -{ - char realPath[PATH_MAX] = { 0 }; - if (realpath(libPath, realPath) == nullptr) { - FI_HILOGE("Path is error, path is %{public}s", libPath); - return nullptr; - } - void *handle = ::dlopen(libPath, RTLD_NOW); - return (handle != nullptr ? std::make_unique>(context, handle) : nullptr); -} -} // namespace DeviceStatus -} // namespace Msdp -} // namespace OHOS -#endif // PLUGIN_MANAGER_H \ No newline at end of file diff --git a/service/BUILD.gn b/service/BUILD.gn index b1aa8dad4a..1e077e2033 100644 --- a/service/BUILD.gn +++ b/service/BUILD.gn @@ -290,6 +290,7 @@ ohos_shared_library("libmmi-server") { "${mmi_path}/frameworks/proxy:libmmi-common", "${mmi_path}/service/connect_manager:mmi_connect_manager_service", "${mmi_path}/service/filter:mmi_event_filter_proxy", + "${mmi_path}/intention/scheduler/component_manager:mmi_component_manager", "${mmi_path}/util:libmmi-util", ] diff --git a/intention/scheduler/plugin_manager/src/plugin_manager.cpp b/service/window_manager/include/i_touch_drawing_handler.h similarity index 34% rename from intention/scheduler/plugin_manager/src/plugin_manager.cpp rename to service/window_manager/include/i_touch_drawing_handler.h index 9a31236328..d5d43130f3 100644 --- a/intention/scheduler/plugin_manager/src/plugin_manager.cpp +++ b/service/window_manager/include/i_touch_drawing_handler.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-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 + * 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, @@ -13,42 +13,28 @@ * limitations under the License. */ -#include "plugin_manager.h" +#ifndef I_TOUCH_DRAWING_HANDLER_H +#define I_TOUCH_DRAWING_HANDLER_H -#include - -#include "devicestatus_define.h" - -#undef LOG_TAG -#define LOG_TAG "PluginManager" +#include "pointer_event.h" +#include "window_info.h" namespace OHOS { -namespace Msdp { -namespace DeviceStatus { - -#if (defined(__aarch64__) || defined(__x86_64__)) -constexpr std::string_view LIB_COOPERATE_PATH { "/system/lib64/libintention_cooperate.z.so" }; -#else -constexpr std::string_view LIB_COOPERATE_PATH { "/system/lib/libintention_cooperate.z.so" }; -#endif // defined(__x86_64__) - -ICooperate* PluginManager::LoadCooperate() -{ - CALL_DEBUG_ENTER; - std::lock_guard guard(lock_); - CHKPP(context_); - if (cooperate_ == nullptr) { - cooperate_ = LoadLibrary(context_, LIB_COOPERATE_PATH.data()); - } - return (cooperate_ != nullptr ? cooperate_->GetInstance() : nullptr); -} - -void PluginManager::UnloadCooperate() -{ - CALL_DEBUG_ENTER; - std::lock_guard guard(lock_); - cooperate_.reset(); -} -} // namespace DeviceStatus -} // namespace Msdp +namespace MMI { +class ITouchDrawingHandler { +public: + ITouchDrawingHandler() = default; + virtual ~ITouchDrawingHandler() = default; + + virtual void UpdateDisplayInfo(const DisplayInfo &displayInfo) = 0; + virtual void TouchDrawHandler(std::shared_ptr pointerEvent) = 0; + virtual void RotationScreen() = 0; + virtual void UpdateLabels(bool isOn) = 0; + virtual void UpdateBubbleData(bool isOn) = 0; + virtual void SetMultiWindowScreenId(uint64_t screenId, uint64_t displayNodeScreenId) = 0; + virtual void Dump(int32_t fd, const std::vector &args) = 0; + virtual bool IsWindowRotation() const = 0; +}; +} // namespace MMI } // namespace OHOS +#endif // I_TOUCH_DRAWING_HANDLER_H diff --git a/service/window_manager/include/touch_drawing_handler.h b/service/window_manager/include/touch_drawing_handler.h new file mode 100644 index 0000000000..82ea0f63f4 --- /dev/null +++ b/service/window_manager/include/touch_drawing_handler.h @@ -0,0 +1,144 @@ +/* + * 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 TOUCH_DRAWING_HANDLER_H +#define TOUCH_DRAWING_HANDLER_H + +#include +#include +#include +#include +#include +#include + +#ifndef USE_ROSEN_DRAWING +#include +#else +#include +#include +#endif // USE_ROSEN_DRAWING + +#include "i_touch_drawing_handler.h" + +namespace OHOS { +namespace MMI { +class TouchDrawingHandler final : public ITouchDrawingHandler { + struct Bubble { + int32_t innerCircleRadius { 0 }; + int32_t outerCircleRadius { 0 }; + float outerCircleWidth { 0 }; + }; + + struct DevMode { + std::string SwitchName; + bool isShow { false }; + }; + +#ifndef USE_ROSEN_DRAWING + using RosenCanvas = Rosen::RSRecordingCanvas; +#else + using RosenCanvas = Rosen::Drawing::RecordingCanvas; +#endif // USE_ROSEN_DRAWING + +public: + TouchDrawingHandler() = default; + ~TouchDrawingHandler() = default; + DISALLOW_COPY_AND_MOVE(TouchDrawingHandler); + + void UpdateDisplayInfo(const DisplayInfo &displayInfo) override; + void TouchDrawHandler(std::shared_ptr pointerEvent) override; + void RotationScreen() override; + void UpdateLabels(bool isOn) override; + void UpdateBubbleData(bool isOn) override; + void SetMultiWindowScreenId(uint64_t screenId, uint64_t displayNodeScreenId) override; + void Dump(int32_t fd, const std::vector &args) override; + bool IsWindowRotation() const override; + +private: + void AddCanvasNode(std::shared_ptr& canvasNode, bool isTrackerNode, + bool isNeedRotate = true); + void RotationCanvasNode(std::shared_ptr canvasNode); + void ResetCanvasNode(std::shared_ptr canvasNode); + void RotationCanvas(RosenCanvas *canvas, Direction direction); + void CreateTouchWindow(); + void DestoryTouchWindow(); + void DrawBubbleHandler(); + void DrawBubble(); + void DrawPointerPositionHandler(); + void DrawTracker(int32_t x, int32_t y, int32_t pointerId); + void DrawCrosshairs(RosenCanvas *canvas, int32_t x, int32_t y); + void DrawLabels(); + void DrawRectItem(RosenCanvas* canvas, const std::string &text, + Rosen::Drawing::Rect &rect, const Rosen::Drawing::Color &color); + void UpdatePointerPosition(); + void RecordLabelsInfo(); + void UpdateLastPointerItem(PointerEvent::PointerItem &pointerItem); + void RemovePointerPosition(); + void ClearTracker(); + void InitLabels(); + + template + std::string FormatNumber(T number, int32_t precision); + + bool IsValidAction(const int32_t action); + void Snapshot(); + std::pair CalcDrawCoordinate( + const DisplayInfo& displayInfo, const PointerEvent::PointerItem &pointerItem); + std::pair TransformDisplayXY(const DisplayInfo &info, double logicX, double logicY) const; + void StartTrace(int32_t pointerId); + void StopTrace(); + +private: + std::shared_ptr surfaceNode_ { nullptr }; + std::shared_ptr bubbleCanvasNode_ { nullptr }; + std::shared_ptr trackerCanvasNode_ { nullptr }; + std::shared_ptr crosshairCanvasNode_ { nullptr }; + std::shared_ptr labelsCanvasNode_ { nullptr }; + DisplayInfo displayInfo_ {}; + Bubble bubble_; + Rosen::Drawing::Point firstPt_; + Rosen::Drawing::Point currentPt_; + Rosen::Drawing::Point lastPt_; + DevMode bubbleMode_; + DevMode pointerMode_; + int32_t currentPointerId_ { 0 }; + int32_t maxPointerCount_ { 0 }; + int32_t currentPointerCount_ { 0 }; + int32_t rectTopPosition_ { 0 }; + int32_t scaleW_ { 0 }; + int32_t scaleH_ { 0 }; + int64_t lastActionTime_ { 0 }; + uint64_t screenId_ { -1 }; + double xVelocity_ { 0.0 }; + double yVelocity_ { 0.0 }; + double pressure_ { 0.0 }; + double itemRectW_ { 0.0 }; + bool hasBubbleObserver_{ false }; + bool hasPointerObserver_{ false }; + bool isFirstDownAction_ { false }; + bool isDownAction_ { false }; + bool isFirstDraw_ { true }; + bool isChangedRotation_ { false }; + bool isChangedMode_ { false }; + bool stopRecord_ { false }; + std::shared_ptr pointerEvent_ { nullptr }; + std::list lastPointerItem_ { }; + std::mutex mutex_; + uint64_t windowScreenId_ { 0 }; + uint64_t displayNodeScreenId_ { 0 }; +}; +} // namespace MMI +} // namespace OHOS +#endif // TOUCH_DRAWING_HANDLER_H diff --git a/service/window_manager/src/touch_drawing_handler.cpp b/service/window_manager/src/touch_drawing_handler.cpp new file mode 100644 index 0000000000..56d6126f56 --- /dev/null +++ b/service/window_manager/src/touch_drawing_handler.cpp @@ -0,0 +1,853 @@ +/* + * 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 "touch_drawing_handler.h" + +#include +#ifdef HITRACE_ENABLED +#include "hitrace_meter.h" +#endif // HITRACE_ENABLED +#include "parameters.h" + +#include "define_multimodal.h" +#include "error_multimodal.h" +#include "i_context.h" +#include "mmi_matrix3.h" +#include "table_dump.h" + +#undef MMI_LOG_DOMAIN +#define MMI_LOG_DOMAIN MMI_LOG_CURSOR +#undef MMI_LOG_TAG +#define MMI_LOG_TAG "TouchDrawingHandler" + +namespace OHOS { +namespace MMI { +namespace { +const static Rosen::Drawing::Color LABELS_DEFAULT_COLOR = Rosen::Drawing::Color::ColorQuadSetARGB(192, 255, 255, 255); +const static Rosen::Drawing::Color LABELS_RED_COLOR = Rosen::Drawing::Color::ColorQuadSetARGB(192, 255, 0, 0); +const static Rosen::Drawing::Color TRACKER_COLOR = Rosen::Drawing::Color::ColorQuadSetARGB(255, 0, 96, 255); +const static Rosen::Drawing::Color POINTER_RED_COLOR = Rosen::Drawing::Color::ColorQuadSetARGB(255, 255, 0, 0); +const static Rosen::Drawing::Color CROSS_HAIR_COLOR = Rosen::Drawing::Color::ColorQuadSetARGB(255, 0, 0, 192); +constexpr int32_t DENSITY_BASELINE { 160 }; +constexpr int32_t INDEPENDENT_INNER_PIXELS { 20 }; +constexpr int32_t INDEPENDENT_OUTER_PIXELS { 21 }; +constexpr int32_t INDEPENDENT_WIDTH_PIXELS { 2 }; +constexpr int32_t MULTIPLE_FACTOR { 10 }; +constexpr int32_t CALCULATE_MIDDLE { 2 }; +constexpr int32_t DEFAULT_VALUE { -1 }; +constexpr int32_t RECT_COUNT { 6 }; +constexpr int32_t PHONE_RECT_TOP { 118 }; +constexpr int32_t PAD_RECT_TOP { 0 }; +constexpr int32_t RECT_HEIGHT { 40 }; +constexpr int32_t TEXT_TOP { 30 }; +constexpr int32_t PEN_WIDTH { 1 }; +constexpr int32_t TOUCH_SLOP { 30 }; +constexpr int32_t RECT_SPACEING { 1 }; +constexpr int32_t THREE_PRECISION { 3 }; +constexpr int32_t TWO_PRECISION { 2 }; +constexpr int32_t ONE_PRECISION { 1 }; +constexpr int32_t ROTATION_ANGLE_0 { 0 }; +constexpr int32_t ROTATION_ANGLE_90 { 90 }; +constexpr int32_t ROTATION_ANGLE_180 { 180 }; +constexpr int32_t ROTATION_ANGLE_270 { 270 }; +constexpr float TEXT_SIZE { 28.0f }; +constexpr float TEXT_SCALE { 1.0f }; +constexpr float TEXT_SKEW { 0.0f }; +constexpr float INNER_CIRCLE_TRANSPARENCY { 0.6f }; +constexpr float OUT_CIRCLE_TRANSPARENCY { 0.1f }; +const std::string SHOW_CURSOR_SWITCH_NAME { "settings.input.show_touch_hint" }; +const std::string POINTER_POSITION_SWITCH_NAME { "settings.developer.show_touch_track" }; +const std::string PRODUCT_TYPE = system::GetParameter("const.product.devicetype", "unknown"); +const int32_t ROTATE_POLICY = system::GetIntParameter("const.window.device.rotate_policy", 0); +const std::string FOLDABLE_DEVICE_POLICY = system::GetParameter("const.window.foldabledevice.rotate_policy", ""); +constexpr int32_t WINDOW_ROTATE { 0 }; +constexpr char ROTATE_WINDOW_ROTATE { '0' }; +constexpr int32_t FOLDABLE_DEVICE { 2 }; +constexpr int32_t ANGLE_90 { 90 }; +constexpr int32_t ANGLE_360 { 360 }; +constexpr char PRODUCT_PHONE[] { "phone" }; +constexpr char PRODUCT_TYPE_PC[] { "2in1" }; +} // namespace + +void TouchDrawingHandler::RecordLabelsInfo() +{ + CHKPV(pointerEvent_); + PointerEvent::PointerItem pointerItem; + if (!pointerEvent_->GetPointerItem(currentPointerId_, pointerItem)) { + MMI_HILOGE("Can't find pointer item, pointer:%{public}d", currentPointerId_); + return; + } + auto displayXY = CalcDrawCoordinate(displayInfo_, pointerItem); + if (pointerItem.IsPressed()) { + currentPt_.SetX(displayXY.first); + currentPt_.SetY(displayXY.second); + pressure_ = pointerItem.GetPressure(); + } + if (isFirstDownAction_) { + firstPt_.SetX(displayXY.first); + firstPt_.SetY(displayXY.second); + isFirstDownAction_ = false; + } + int64_t actionTime = pointerEvent_->GetActionTime(); + if (pointerEvent_->GetPointerId() == currentPointerId_ && !lastPointerItem_.empty()) { + double diffTime = static_cast(actionTime - lastActionTime_) / 1000; + if (MMI_EQ(diffTime, 0.0)) { + xVelocity_ = 0.0; + yVelocity_ = 0.0; + } else { + auto diffX = currentPt_.GetX() - lastPt_.GetX(); + auto diffY = currentPt_.GetY() - lastPt_.GetY(); + xVelocity_ = diffX / diffTime; + yVelocity_ = diffY / diffTime; + } + lastActionTime_ = actionTime; + } +} + +void TouchDrawingHandler::TouchDrawHandler(std::shared_ptr pointerEvent) +{ + CALL_DEBUG_ENTER; + CHKPV(pointerEvent); + pointerEvent_ = pointerEvent; + + if (bubbleMode_.isShow) { + CreateTouchWindow(); + AddCanvasNode(bubbleCanvasNode_, false); + DrawBubbleHandler(); + } + if (pointerEvent->GetPointerAction() == PointerEvent::POINTER_ACTION_UP + && pointerEvent->GetAllPointerItems().size() == 1) { + lastPointerItem_.clear(); + } + if (pointerEvent->GetPointerAction() == PointerEvent::POINTER_ACTION_DOWN + && pointerEvent->GetAllPointerItems().size() == 1) { + stopRecord_ = false; + } + if (pointerMode_.isShow && !stopRecord_) { + CreateTouchWindow(); + AddCanvasNode(trackerCanvasNode_, true); + AddCanvasNode(crosshairCanvasNode_, false); + AddCanvasNode(labelsCanvasNode_, false, false); + DrawPointerPositionHandler(); + lastPt_ = currentPt_; + } +} + +void TouchDrawingHandler::UpdateDisplayInfo(const DisplayInfo& displayInfo) +{ + CALL_DEBUG_ENTER; + isChangedRotation_ = displayInfo.direction == displayInfo_.direction ? false : true; + isChangedMode_ = displayInfo.displayMode == displayInfo_.displayMode ? false : true; + scaleW_ = displayInfo.validWidth > displayInfo.validHeight ? displayInfo.validWidth : displayInfo.validHeight; + scaleH_ = displayInfo.validWidth > displayInfo.validHeight ? displayInfo.validWidth : displayInfo.validHeight; + if (displayInfo.screenCombination != displayInfo_.screenCombination || + displayInfo.uniqueId != displayInfo_.uniqueId) { + if (surfaceNode_ != nullptr) { + surfaceNode_->ClearChildren(); + surfaceNode_.reset(); + isChangedMode_ = true; + } + } + displayInfo_ = displayInfo; + bubble_.innerCircleRadius = displayInfo.dpi * INDEPENDENT_INNER_PIXELS / DENSITY_BASELINE / CALCULATE_MIDDLE; + bubble_.outerCircleRadius = displayInfo.dpi * INDEPENDENT_OUTER_PIXELS / DENSITY_BASELINE / CALCULATE_MIDDLE; + bubble_.outerCircleWidth = static_cast(displayInfo.dpi * INDEPENDENT_WIDTH_PIXELS) / DENSITY_BASELINE; + itemRectW_ = static_cast(displayInfo_.validWidth) / RECT_COUNT; + rectTopPosition_ = 0; + if (IsWindowRotation()) { + if (displayInfo_.direction == DIRECTION0 || displayInfo_.direction == DIRECTION180) { + rectTopPosition_ = PRODUCT_TYPE == PRODUCT_PHONE ? PHONE_RECT_TOP : PAD_RECT_TOP; + } + } else { + if (displayInfo_.direction == DIRECTION90 && PRODUCT_TYPE != PRODUCT_TYPE_PC) { + rectTopPosition_ = PHONE_RECT_TOP; + } + } + if (isChangedMode_) { + if (trackerCanvasNode_ != nullptr) { + trackerCanvasNode_.reset(); + } + if (bubbleCanvasNode_ != nullptr) { + bubbleCanvasNode_.reset(); + } + if (crosshairCanvasNode_ != nullptr) { + crosshairCanvasNode_.reset(); + } + if (labelsCanvasNode_ != nullptr) { + labelsCanvasNode_.reset(); + } + Rosen::RSTransaction::FlushImplicitTransaction(); + } +} + +void TouchDrawingHandler::UpdateLabels(bool isOn) +{ + CALL_DEBUG_ENTER; + pointerMode_.isShow = isOn; + if (pointerMode_.isShow) { + CreateTouchWindow(); + AddCanvasNode(labelsCanvasNode_, false, false); + DrawLabels(); + } else { + RemovePointerPosition(); + DestoryTouchWindow(); + } + Rosen::RSTransaction::FlushImplicitTransaction(); +} + +void TouchDrawingHandler::UpdateBubbleData(bool isOn) +{ + CALL_DEBUG_ENTER; + bubbleMode_.isShow = isOn; + if (bubbleMode_.isShow) { + return; + } + CHKPV(surfaceNode_); + surfaceNode_->RemoveChild(bubbleCanvasNode_); + bubbleCanvasNode_.reset(); + DestoryTouchWindow(); + Rosen::RSTransaction::FlushImplicitTransaction(); +} + +void TouchDrawingHandler::RotationScreen() +{ + CALL_DEBUG_ENTER; + if (!isChangedRotation_ && !isChangedMode_) { + return; + } + if (pointerMode_.isShow) { + RotationCanvasNode(trackerCanvasNode_); + RotationCanvasNode(crosshairCanvasNode_); + } + if (bubbleMode_.isShow) { + RotationCanvasNode(bubbleCanvasNode_); + } + + if (pointerMode_.isShow && !isChangedMode_) { + if (!lastPointerItem_.empty() || stopRecord_) { + Snapshot(); + } else if (!stopRecord_) { + UpdateLabels(pointerMode_.isShow); + } + } + Rosen::RSTransaction::FlushImplicitTransaction(); +} + +template +std::string TouchDrawingHandler::FormatNumber(T number, int32_t precision) +{ + std::string temp(".000"); + auto str = std::to_string(number); + if (str.find(".") == std::string::npos) { + str += temp; + } + return str.substr(0, str.find(".") + precision + 1); +} + +void TouchDrawingHandler::AddCanvasNode(std::shared_ptr& canvasNode, bool isTrackerNode, + bool isNeedRotate) +{ + CALL_DEBUG_ENTER; + std::lock_guard lock(mutex_); + CHKPV(surfaceNode_); + if (canvasNode != nullptr && screenId_ == static_cast(displayInfo_.uniqueId)) { + return; + } + MMI_HILOGI("Screen from:%{public}" PRIu64 " to :%{public}d", screenId_, displayInfo_.uniqueId); + screenId_ = static_cast(displayInfo_.uniqueId); + canvasNode = isTrackerNode ? Rosen::RSCanvasDrawingNode::Create() : Rosen::RSCanvasNode::Create(); + canvasNode->SetBounds(0, 0, scaleW_, scaleH_); + canvasNode->SetFrame(0, 0, scaleW_, scaleH_); + surfaceNode_->SetBounds(0, 0, scaleW_, scaleH_); + surfaceNode_->SetFrame(0, 0, scaleW_, scaleH_); + if (isNeedRotate) { + RotationCanvasNode(canvasNode); + } +#ifndef USE_ROSEN_DRAWING + canvasNode->SetBackgroundColor(SK_ColorTRANSPARENT); +#else + canvasNode->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT); +#endif + canvasNode->SetCornerRadius(1); + canvasNode->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z); + surfaceNode_->AddChild(canvasNode, DEFAULT_VALUE); +} + +void TouchDrawingHandler::RotationCanvasNode(std::shared_ptr canvasNode) +{ + CALL_DEBUG_ENTER; + CHKPV(canvasNode); + Direction displayDirection = static_cast(( + ((displayInfo_.direction - displayInfo_.displayDirection) * ANGLE_90 + ANGLE_360) % ANGLE_360) / ANGLE_90); + if (displayDirection == Direction::DIRECTION90) { + canvasNode->SetRotation(ROTATION_ANGLE_270); + canvasNode->SetTranslateX(0); + } else if (displayDirection == Direction::DIRECTION270) { + canvasNode->SetRotation(ROTATION_ANGLE_90); + canvasNode->SetTranslateX(-std::fabs(displayInfo_.validWidth - displayInfo_.validHeight)); + } else if (displayDirection == Direction::DIRECTION180) { + canvasNode->SetRotation(ROTATION_ANGLE_180); + canvasNode->SetTranslateX(-std::fabs(displayInfo_.validWidth - displayInfo_.validHeight)); + } else { + canvasNode->SetRotation(ROTATION_ANGLE_0); + canvasNode->SetTranslateX(0); + } + canvasNode->SetTranslateY(0); +} + +void TouchDrawingHandler::ResetCanvasNode(std::shared_ptr canvasNode) +{ + CALL_DEBUG_ENTER; + CHKPV(canvasNode); + canvasNode->SetRotation(ROTATION_ANGLE_0); + canvasNode->SetTranslateX(0); + canvasNode->SetTranslateY(0); +} + +void TouchDrawingHandler::RotationCanvas(RosenCanvas *canvas, Direction direction) +{ + CHKPV(canvas); + if (direction == Direction::DIRECTION90) { + canvas->Translate(0, displayInfo_.validWidth); + canvas->Rotate(ROTATION_ANGLE_270, 0, 0); + } else if (direction == Direction::DIRECTION180) { + canvas->Rotate(ROTATION_ANGLE_180, static_cast(displayInfo_.validWidth) / CALCULATE_MIDDLE, + static_cast(displayInfo_.validHeight) / CALCULATE_MIDDLE); + } else if (direction == Direction::DIRECTION270) { + canvas->Translate(displayInfo_.validHeight, 0); + canvas->Rotate(ROTATION_ANGLE_90, 0, 0); + } +} + +void TouchDrawingHandler::CreateTouchWindow() +{ + CALL_DEBUG_ENTER; + std::lock_guard lock(mutex_); + if (surfaceNode_ != nullptr || scaleW_ == 0 || scaleH_ == 0) { + return; + } + Rosen::RSSurfaceNodeConfig surfaceNodeConfig; + surfaceNodeConfig.SurfaceNodeName = "touch window"; + Rosen::RSSurfaceNodeType surfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE; + surfaceNode_ = Rosen::RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType); + CHKPV(surfaceNode_); + surfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT_FILL); + surfaceNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z); + surfaceNode_->SetBounds(0, 0, scaleW_, scaleH_); + surfaceNode_->SetFrame(0, 0, scaleW_, scaleH_); +#ifndef USE_ROSEN_DRAWING + surfaceNode_->SetBackgroundColor(SK_ColorTRANSPARENT); +#else + surfaceNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT); +#endif + surfaceNode_->SetRotation(0); + screenId_ = static_cast(displayInfo_.uniqueId); + if (windowScreenId_ == screenId_) { + screenId_ = displayNodeScreenId_; + } + surfaceNode_->AttachToDisplay(screenId_); + MMI_HILOGI("Setting screen:%{public}" PRIu64 ", displayNode:%{public}" PRIu64, screenId_, surfaceNode_->GetId()); +} + +void TouchDrawingHandler::DrawBubbleHandler() +{ + CALL_DEBUG_ENTER; + CHKPV(pointerEvent_); + auto pointerAction = pointerEvent_->GetPointerAction(); + if (IsValidAction(pointerAction)) { + DrawBubble(); + } + Rosen::RSTransaction::FlushImplicitTransaction(); +} + +void TouchDrawingHandler::DrawBubble() +{ + CHKPV(pointerEvent_); + CHKPV(bubbleCanvasNode_); + auto canvas = static_cast(bubbleCanvasNode_->BeginRecording(scaleW_, scaleH_)); + CHKPV(canvas); + auto pointerIdList = pointerEvent_->GetPointerIds(); + for (auto pointerId : pointerIdList) { + if ((pointerEvent_->GetPointerAction() == PointerEvent::POINTER_ACTION_UP || + pointerEvent_->GetPointerAction() == PointerEvent::POINTER_ACTION_PULL_UP || + pointerEvent_->GetPointerAction() == PointerEvent::POINTER_ACTION_CANCEL) && + pointerEvent_->GetPointerId() == pointerId) { + MMI_HILOGI("Continue bubble draw, pointerAction:%{public}d, pointerId:%{public}d", + pointerEvent_->GetPointerAction(), pointerEvent_->GetPointerId()); + continue; + } + PointerEvent::PointerItem pointerItem; + if (!pointerEvent_->GetPointerItem(pointerId, pointerItem)) { + MMI_HILOGE("Can't find pointer item, pointer:%{public}d", pointerId); + return; + } + auto displayXY = CalcDrawCoordinate(displayInfo_, pointerItem); + Rosen::Drawing::Point centerPt(displayXY.first, displayXY.second); + Rosen::Drawing::Pen pen; + pen.SetColor(Rosen::Drawing::Color::COLOR_BLACK); + pen.SetAntiAlias(true); + pen.SetAlphaF(OUT_CIRCLE_TRANSPARENCY); + pen.SetWidth(bubble_.outerCircleWidth); + canvas->AttachPen(pen); + canvas->DrawCircle(centerPt, bubble_.outerCircleRadius); + canvas->DetachPen(); + + Rosen::Drawing::Brush brush; + brush.SetColor(Rosen::Drawing::Color::COLOR_WHITE); + brush.SetAntiAlias(true); + brush.SetAlphaF(INNER_CIRCLE_TRANSPARENCY); + canvas->AttachBrush(brush); + canvas->DrawCircle(centerPt, bubble_.innerCircleRadius); + canvas->DetachBrush(); + if (pointerEvent_->GetPointerAction() == PointerEvent::POINTER_ACTION_DOWN && + pointerEvent_->GetPointerId() == pointerId) { + MMI_HILOGI("Bubble is draw success, pointerAction:%{public}d, pointerId:%{public}d, physicalX:%{private}d," + " physicalY:%{private}d, width:%{public}d, height:%{public}d", pointerEvent_->GetPointerAction(), + pointerEvent_->GetPointerId(), displayXY.first, displayXY.second, scaleW_, scaleH_); + } + } + bubbleCanvasNode_->FinishRecording(); +} + +void TouchDrawingHandler::DrawPointerPositionHandler() +{ + CALL_DEBUG_ENTER; + CHKPV(pointerEvent_); + UpdatePointerPosition(); + ClearTracker(); + RecordLabelsInfo(); + CHKPV(crosshairCanvasNode_); + auto canvas = static_cast(crosshairCanvasNode_->BeginRecording(scaleW_, scaleH_)); + CHKPV(canvas); + auto pointerIdList = pointerEvent_->GetPointerIds(); + for (auto pointerId : pointerIdList) { + PointerEvent::PointerItem pointerItem; + if (!pointerEvent_->GetPointerItem(pointerId, pointerItem)) { + MMI_HILOGE("Can't find pointer item, pointer:%{public}d", pointerId); + return; + } + auto displayXY = CalcDrawCoordinate(displayInfo_, pointerItem); + DrawTracker(displayXY.first, displayXY.second, pointerId); + if (pointerEvent_->GetPointerAction() != PointerEvent::POINTER_ACTION_UP) { + DrawCrosshairs(canvas, displayXY.first, displayXY.second); + UpdateLastPointerItem(pointerItem); + } + } + DrawLabels(); + crosshairCanvasNode_->FinishRecording(); + Rosen::RSTransaction::FlushImplicitTransaction(); +} + +void TouchDrawingHandler::Snapshot() +{ + CHKPV(labelsCanvasNode_); + std::string viewP = "P: 0 / " + std::to_string(maxPointerCount_); + auto dx = currentPt_.GetX() - firstPt_.GetX(); + auto dy = currentPt_.GetY() - firstPt_.GetY(); + std::string viewDx = "dX: " + FormatNumber(dx, ONE_PRECISION); + std::string viewDy = "dY: " + FormatNumber(dy, ONE_PRECISION); + std::string viewXv = "Xv: " + FormatNumber(xVelocity_, THREE_PRECISION); + std::string viewYv = "Yv: " + FormatNumber(yVelocity_, THREE_PRECISION); + std::string viewPrs = "Prs: " + FormatNumber(pressure_, TWO_PRECISION); + Rosen::Drawing::Color color = LABELS_DEFAULT_COLOR; + auto canvas = static_cast(labelsCanvasNode_->BeginRecording(scaleW_, scaleH_)); + Rosen::Drawing::Rect rect; + rect.top_ = rectTopPosition_; + rect.bottom_ = rectTopPosition_ + RECT_HEIGHT; + rect.left_ = 0; + rect.right_ = itemRectW_ + rect.left_; + Direction displayDirection = static_cast(( + ((displayInfo_.direction - displayInfo_.displayDirection) * ANGLE_90 + ANGLE_360) % ANGLE_360) / ANGLE_90); + RotationCanvas(canvas, displayDirection); + + DrawRectItem(canvas, viewP, rect, color); + color = std::abs(dx) < TOUCH_SLOP ? LABELS_DEFAULT_COLOR : LABELS_RED_COLOR; + DrawRectItem(canvas, viewDx, rect, color); + color = std::abs(dy) < TOUCH_SLOP ? LABELS_DEFAULT_COLOR : LABELS_RED_COLOR; + DrawRectItem(canvas, viewDy, rect, color); + DrawRectItem(canvas, viewXv, rect, LABELS_DEFAULT_COLOR); + DrawRectItem(canvas, viewYv, rect, LABELS_DEFAULT_COLOR); + color = isFirstDraw_ ? LABELS_DEFAULT_COLOR : LABELS_RED_COLOR; + DrawRectItem(canvas, viewPrs, rect, color); + labelsCanvasNode_->FinishRecording(); + CHKPV(crosshairCanvasNode_); + auto crosshairCanvas = static_cast(crosshairCanvasNode_->BeginRecording(scaleW_, scaleH_)); + crosshairCanvas->Clear(); + crosshairCanvasNode_->FinishRecording(); + stopRecord_ = true; +} + +bool TouchDrawingHandler::IsWindowRotation() const +{ + MMI_HILOGD("ROTATE_POLICY:%{public}d, FOLDABLE_DEVICE_POLICY:%{public}s", + ROTATE_POLICY, FOLDABLE_DEVICE_POLICY.c_str()); + return (ROTATE_POLICY == WINDOW_ROTATE || + (ROTATE_POLICY == FOLDABLE_DEVICE && + ((displayInfo_.displayMode == DisplayMode::MAIN && + FOLDABLE_DEVICE_POLICY[0] == ROTATE_WINDOW_ROTATE) || + (displayInfo_.displayMode == DisplayMode::FULL && + (FOLDABLE_DEVICE_POLICY.size() > FOLDABLE_DEVICE) && + FOLDABLE_DEVICE_POLICY[FOLDABLE_DEVICE] == ROTATE_WINDOW_ROTATE)))); +} + +void TouchDrawingHandler::DrawTracker(int32_t x, int32_t y, int32_t pointerId) +{ + CALL_DEBUG_ENTER; + Rosen::Drawing::Point currentPt(x, y); + Rosen::Drawing::Point lastPt; + bool find = false; + for (auto &item : lastPointerItem_) { + if (item.GetPointerId() == pointerId) { + auto displayXY = CalcDrawCoordinate(displayInfo_, item); + lastPt.SetX(displayXY.first); + lastPt.SetY(displayXY.second); + find = true; + break; + } + } + if (currentPt == lastPt) { + return; + } + CHKPV(trackerCanvasNode_); + StartTrace(pointerId); + auto canvas = static_cast(trackerCanvasNode_->BeginRecording(scaleW_, scaleH_)); + CHKPV(canvas); + Rosen::Drawing::Pen pen; + if (find) { + pen.SetColor(TRACKER_COLOR); + pen.SetWidth(PEN_WIDTH); + canvas->AttachPen(pen); + canvas->DrawLine(lastPt, currentPt); + canvas->DetachPen(); + pen.SetColor(POINTER_RED_COLOR); + pen.SetWidth(INDEPENDENT_WIDTH_PIXELS); + canvas->AttachPen(pen); + canvas->DrawPoint(currentPt); + canvas->DetachPen(); + } + if (!isDownAction_ && !find) { + int32_t futureX = x + xVelocity_ * MULTIPLE_FACTOR; + int32_t futureY = y + yVelocity_ * MULTIPLE_FACTOR; + Rosen::Drawing::Point futurePt(futureX, futureY); + pen.SetColor(POINTER_RED_COLOR); + pen.SetWidth(PEN_WIDTH); + canvas->AttachPen(pen); + canvas->DrawLine(currentPt, futurePt); + canvas->DetachPen(); + } + trackerCanvasNode_->FinishRecording(); + StopTrace(); +} + +void TouchDrawingHandler::DrawCrosshairs(RosenCanvas *canvas, int32_t x, int32_t y) +{ + CALL_DEBUG_ENTER; + CHKPV(canvas); + Rosen::Drawing::Pen pen; + pen.SetColor(CROSS_HAIR_COLOR); + pen.SetWidth(PEN_WIDTH); + canvas->AttachPen(pen); + Rosen::Drawing::Point left(0, y); + Rosen::Drawing::Point right(scaleH_, y); + canvas->DrawLine(left, right); + Rosen::Drawing::Point top(x, 0); + Rosen::Drawing::Point bottom(x, scaleH_); + canvas->DrawLine(top, bottom); + canvas->DetachPen(); +} + +void TouchDrawingHandler::DrawLabels() +{ + CALL_DEBUG_ENTER; + CHKPV(labelsCanvasNode_); + std::string viewP = "P: " + std::to_string(currentPointerCount_) + " / " + std::to_string(maxPointerCount_); + std::string viewX = "X: " + FormatNumber(currentPt_.GetX(), ONE_PRECISION); + std::string viewY = "Y: " + FormatNumber(currentPt_.GetY(), ONE_PRECISION); + auto dx = currentPt_.GetX() - firstPt_.GetX(); + auto dy = currentPt_.GetY() - firstPt_.GetY(); + std::string viewDx = "dX: " + FormatNumber(dx, ONE_PRECISION); + std::string viewDy = "dY: " + FormatNumber(dy, ONE_PRECISION); + std::string viewXv = "Xv: " + FormatNumber(xVelocity_, THREE_PRECISION); + std::string viewYv = "Yv: " + FormatNumber(yVelocity_, THREE_PRECISION); + std::string viewPrs = "Prs: " + FormatNumber(pressure_, TWO_PRECISION); + Rosen::Drawing::Color color = LABELS_DEFAULT_COLOR; + std::lock_guard lock(mutex_); + auto canvas = static_cast(labelsCanvasNode_->BeginRecording(scaleW_, scaleH_)); + CHKPV(canvas); + Rosen::Drawing::Rect rect; + rect.top_ = rectTopPosition_; + rect.bottom_ = rectTopPosition_ + RECT_HEIGHT; + rect.left_ = 0; + rect.right_ = itemRectW_ + rect.left_; + Direction displayDirection = static_cast(( + ((displayInfo_.direction - displayInfo_.displayDirection) * ANGLE_90 + ANGLE_360) % ANGLE_360) / ANGLE_90); + RotationCanvas(canvas, displayDirection); + DrawRectItem(canvas, viewP, rect, color); + if (isDownAction_ || !lastPointerItem_.empty()) { + DrawRectItem(canvas, viewX, rect, color); + DrawRectItem(canvas, viewY, rect, color); + } else { + color = std::abs(dx) < TOUCH_SLOP ? LABELS_DEFAULT_COLOR : LABELS_RED_COLOR; + DrawRectItem(canvas, viewDx, rect, color); + color = std::abs(dy) < TOUCH_SLOP ? LABELS_DEFAULT_COLOR : LABELS_RED_COLOR; + DrawRectItem(canvas, viewDy, rect, color); + } + DrawRectItem(canvas, viewXv, rect, LABELS_DEFAULT_COLOR); + DrawRectItem(canvas, viewYv, rect, LABELS_DEFAULT_COLOR); + color = isFirstDraw_ ? LABELS_DEFAULT_COLOR : LABELS_RED_COLOR; + DrawRectItem(canvas, viewPrs, rect, color); + labelsCanvasNode_->FinishRecording(); + isFirstDraw_ = false; +} + +void TouchDrawingHandler::DrawRectItem(RosenCanvas* canvas, const std::string &text, + Rosen::Drawing::Rect &rect, const Rosen::Drawing::Color &color) +{ + CHKPV(canvas); + Rosen::Drawing::Brush brush; + brush.SetColor(color); + canvas->AttachBrush(brush); + canvas->DrawRect(rect); + canvas->DetachBrush(); + + std::shared_ptr textBlob = Rosen::Drawing::TextBlob::MakeFromString(text.c_str(), + Rosen::Drawing::Font(nullptr, TEXT_SIZE, TEXT_SCALE, TEXT_SKEW), Rosen::Drawing::TextEncoding::UTF8); + CHKPV(textBlob); + brush.SetColor(Rosen::Drawing::Color::COLOR_BLACK); + canvas->AttachBrush(brush); + canvas->DrawTextBlob(textBlob.get(), rect.left_, rectTopPosition_ + TEXT_TOP); + canvas->DetachBrush(); + rect.left_ += itemRectW_ + RECT_SPACEING; + rect.right_ += itemRectW_ + RECT_SPACEING; +} + +void TouchDrawingHandler::UpdatePointerPosition() +{ + CALL_DEBUG_ENTER; + CHKPV(pointerEvent_); + int32_t pointerAction = pointerEvent_->GetPointerAction(); + int32_t pointerId = pointerEvent_->GetPointerId(); + if (pointerAction == PointerEvent::POINTER_ACTION_DOWN) { + if (lastPointerItem_.empty()) { + InitLabels(); + } + maxPointerCount_ = ++currentPointerCount_; + } else if (pointerAction == PointerEvent::POINTER_ACTION_UP) { + isDownAction_ = false; + isFirstDownAction_ = false; + for (auto it = lastPointerItem_.begin(); it != lastPointerItem_.end(); it++) { + if (it->GetPointerId() == pointerId) { + lastPointerItem_.erase(it); + --currentPointerCount_; + break; + } + } + if (!lastPointerItem_.empty() && (currentPointerId_ == pointerId)) { + currentPointerId_ = lastPointerItem_.front().GetPointerId(); + } + } +} + +void TouchDrawingHandler::UpdateLastPointerItem(PointerEvent::PointerItem &pointerItem) +{ + CALL_DEBUG_ENTER; + if (!pointerItem.IsPressed()) { + return; + } + for (auto &item : lastPointerItem_) { + if (item.GetPointerId() == pointerItem.GetPointerId()) { + item = pointerItem; + return; + } + } + lastPointerItem_.emplace_back(pointerItem); +} + +void TouchDrawingHandler::RemovePointerPosition() +{ + CALL_DEBUG_ENTER; + CHKPV(surfaceNode_); + surfaceNode_->RemoveChild(trackerCanvasNode_); + trackerCanvasNode_.reset(); + + surfaceNode_->RemoveChild(crosshairCanvasNode_); + crosshairCanvasNode_.reset(); + + surfaceNode_->RemoveChild(labelsCanvasNode_); + labelsCanvasNode_.reset(); + + pointerEvent_.reset(); + Rosen::RSTransaction::FlushImplicitTransaction(); + isFirstDraw_ = true; + pressure_ = 0.0; +} + +void TouchDrawingHandler::DestoryTouchWindow() +{ + if (bubbleMode_.isShow || pointerMode_.isShow) { + return; + } + MMI_HILOGI("Destory touch window success, bubbleMode:%{public}d, pointerMode:%{public}d", + bubbleMode_.isShow, pointerMode_.isShow); + CHKPV(surfaceNode_); + surfaceNode_->ClearChildren(); + surfaceNode_.reset(); +} + +void TouchDrawingHandler::ClearTracker() +{ + CALL_DEBUG_ENTER; + CHKPV(trackerCanvasNode_); + if (lastPointerItem_.empty() && isDownAction_) { + MMI_HILOGD("ClearTracker isDownAction_ and empty"); + auto canvasNode = static_cast(trackerCanvasNode_.get()); + canvasNode->ResetSurface(scaleW_, scaleH_); + } +} + +void TouchDrawingHandler::InitLabels() +{ + isFirstDownAction_ = true; + isDownAction_ = true; + maxPointerCount_ = 0; + currentPointerCount_ = 0; + currentPointerId_ = 0; + xVelocity_ = 0.0; + yVelocity_ = 0.0; +} + +bool TouchDrawingHandler::IsValidAction(const int32_t action) +{ + if (action == PointerEvent::POINTER_ACTION_DOWN || action == PointerEvent::POINTER_ACTION_PULL_DOWN || + action == PointerEvent::POINTER_ACTION_MOVE || action == PointerEvent::POINTER_ACTION_PULL_MOVE || + action == PointerEvent::POINTER_ACTION_UP || action == PointerEvent::POINTER_ACTION_PULL_UP || + action == PointerEvent::POINTER_ACTION_CANCEL) { + return true; + } + return false; +} + +void TouchDrawingHandler::SetMultiWindowScreenId(uint64_t screenId, uint64_t displayNodeScreenId) +{ + windowScreenId_ = screenId; + displayNodeScreenId_ = displayNodeScreenId; +} + +void TouchDrawingHandler::Dump(int32_t fd, const std::vector &args) +{ + CALL_DEBUG_ENTER; + std::ostringstream oss; + + std::vector titles1 = {"currentPointerId", "maxPointerCount", "currentPointerCount", + "lastActionTime", "xVelocity", "yVelocity"}; + + std::vector> data1 = { + {std::to_string(currentPointerId_), std::to_string(maxPointerCount_), std::to_string(currentPointerCount_), + std::to_string(lastActionTime_), std::to_string(xVelocity_), std::to_string(yVelocity_)} + }; + + DumpFullTable(oss, "Touch Location Info", titles1, data1); + oss << std::endl; + + std::vector titles2 = {"pressure", "itemRectW", "hasBubbleObserver", + "hasPointerObserver", "isFirstDownAction", "isDownAction", "isFirstDraw"}; + + std::vector> data2 = { + {std::to_string(pressure_), std::to_string(itemRectW_), std::to_string(hasBubbleObserver_), + std::to_string(hasPointerObserver_), std::to_string(isFirstDownAction_), std::to_string(isDownAction_), + std::to_string(isFirstDraw_)} + }; + + DumpFullTable(oss, "Touch Location Info", titles2, data2); + oss << std::endl; + + std::vector bubbleTitles = {"innerCircleRadius", "outerCircleRadius", "outerCircleWidth"}; + std::vector> bubbleData = { + { std::to_string(bubble_.innerCircleRadius), + std::to_string(bubble_.outerCircleRadius), + std::to_string(bubble_.outerCircleWidth) } + }; + + DumpFullTable(oss, "Bubble Info", bubbleTitles, bubbleData); + oss << std::endl; + + std::vector devModeTitles = {"Name", "SwitchName", "IsShow"}; + std::vector> devModeData = { + {"BubbleMode", bubbleMode_.SwitchName, std::to_string(bubbleMode_.isShow)}, + {"PointerMode", pointerMode_.SwitchName, std::to_string(pointerMode_.isShow)} + }; + + DumpFullTable(oss, "DevMode Info", devModeTitles, devModeData); + oss << std::endl; + + std::string dumpInfo = oss.str(); + dprintf(fd, dumpInfo.c_str()); +} + +std::pair TouchDrawingHandler::CalcDrawCoordinate( + const DisplayInfo& displayInfo, const PointerEvent::PointerItem &pointerItem) +{ + CALL_DEBUG_ENTER; + double physicalX = pointerItem.GetRawDisplayX(); + double physicalY = pointerItem.GetRawDisplayY(); + if (!displayInfo.transform.empty()) { + auto displayXY = TransformDisplayXY(displayInfo, physicalX, physicalY); + physicalX = displayXY.first; + physicalY = displayXY.second; + } + return {static_cast(physicalX), static_cast(physicalY)}; +} + +std::pair TouchDrawingHandler::TransformDisplayXY( + const DisplayInfo &info, double logicX, double logicY) const +{ + Matrix3f transform(info.transform); + if (info.transform.size() != MATRIX3_SIZE || transform.IsIdentity()) { + return { logicX, logicY }; + } + Vector3f logicXY(logicX, logicY, 1.0); + Vector3f displayXY = transform * logicXY; + return { std::round(displayXY[0]), std::round(displayXY[1]) }; +} + +void TouchDrawingHandler::StartTrace(int32_t pointerId) +{ +#ifdef HITRACE_ENABLED + std::ostringstream sTrace; + sTrace << "pointerId:" << pointerId; + ::StartTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_MULTIMODALINPUT, std::move(sTrace).str().c_str()); +#endif // HITRACE_ENABLED +} + +void TouchDrawingHandler::StopTrace() +{ +#ifdef HITRACE_ENABLED + ::FinishTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_MULTIMODALINPUT); +#endif // HITRACE_ENABLED +} + +extern "C" ITouchDrawingHandler* CreateInstance(IContext *env) +{ + return new TouchDrawingHandler(); +} + +extern "C" void DestroyInstance(ITouchDrawingHandler *instance) +{ + if (instance != nullptr) { + delete instance; + } +} +} // namespace MMI +} // namespace OHOS \ No newline at end of file -- Gitee