From b60abc2f7cfdf20ed099aedc4139515f7724be2c Mon Sep 17 00:00:00 2001 From: zhouchaobo Date: Sat, 23 Dec 2023 09:31:26 +0800 Subject: [PATCH] Add postEvent ability Signed-off-by: zhouchaobo Change-Id: Icc4a8f9e2838075bf329bdbb500bf44a81fe4515 --- adapter/ohos/entrance/mmi_event_convertor.cpp | 4 +- .../engine/functions/js_touch_function.cpp | 1 + .../jsview/js_base_node.cpp | 106 +++++++++- .../jsview/js_base_node.h | 1 + frameworks/core/common/event_manager.cpp | 85 ++++++++ frameworks/core/common/event_manager.h | 12 +- .../core/components_ng/base/frame_node.cpp | 2 +- .../core/components_ng/event/touch_event.cpp | 1 + .../gestures/recognizers/click_recognizer.cpp | 4 +- .../recognizers/gesture_recognizer.cpp | 7 +- .../recognizers/long_press_recognizer.cpp | 20 +- .../gestures/recognizers/recognizer_group.h | 12 ++ .../core/components_ng/manager/BUILD.gn | 1 + .../manager/post_event/post_event_manager.cpp | 183 ++++++++++++++++++ .../manager/post_event/post_event_manager.h | 58 ++++++ frameworks/core/event/touch_event.h | 38 +++- .../core/pipeline_ng/pipeline_context.cpp | 8 + .../core/pipeline_ng/pipeline_context.h | 3 + test/unittest/BUILD.gn | 1 + 19 files changed, 526 insertions(+), 21 deletions(-) create mode 100644 frameworks/core/components_ng/manager/post_event/post_event_manager.cpp create mode 100644 frameworks/core/components_ng/manager/post_event/post_event_manager.h diff --git a/adapter/ohos/entrance/mmi_event_convertor.cpp b/adapter/ohos/entrance/mmi_event_convertor.cpp index 3274998f6ad..bf2f1c178e9 100644 --- a/adapter/ohos/entrance/mmi_event_convertor.cpp +++ b/adapter/ohos/entrance/mmi_event_convertor.cpp @@ -19,9 +19,10 @@ #include "pointer_event.h" +#include "adapter/ohos/entrance/ace_container.h" +#include "base/utils/time_util.h" #include "base/utils/utils.h" #include "core/pipeline/pipeline_base.h" -#include "adapter/ohos/entrance/ace_container.h" namespace OHOS::Ace::Platform { namespace { @@ -114,6 +115,7 @@ TouchEvent ConvertTouchEvent(const std::shared_ptr& pointerEv #ifdef SECURITY_COMPONENT_ENABLE event.enhanceData = pointerEvent->GetEnhanceData(); #endif + event.currentSysTime = GetSysTimestamp(); int32_t orgDevice = pointerEvent->GetSourceType(); GetEventDevice(orgDevice, event); int32_t orgAction = pointerEvent->GetPointerAction(); diff --git a/frameworks/bridge/declarative_frontend/engine/functions/js_touch_function.cpp b/frameworks/bridge/declarative_frontend/engine/functions/js_touch_function.cpp index 34bb265c240..0260728f489 100644 --- a/frameworks/bridge/declarative_frontend/engine/functions/js_touch_function.cpp +++ b/frameworks/bridge/declarative_frontend/engine/functions/js_touch_function.cpp @@ -51,6 +51,7 @@ JSRef JsTouchFunction::CreateJSEventInfo(TouchEventInfo& info) JSRef touchArr = JSRef::New(); JSRef changeTouchArr = JSRef::New(); eventObj->SetProperty("source", static_cast(info.GetSourceDevice())); + eventObj->SetProperty("currentSysTime", static_cast(info.GetCurrentSysTime())); eventObj->SetProperty("timestamp", static_cast(info.GetTimeStamp().time_since_epoch().count())); auto target = CreateEventTargetObject(info); eventObj->SetPropertyObject("target", target); diff --git a/frameworks/bridge/declarative_frontend/jsview/js_base_node.cpp b/frameworks/bridge/declarative_frontend/jsview/js_base_node.cpp index 1025009f1e9..045b55bb0f0 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_base_node.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_base_node.cpp @@ -16,12 +16,14 @@ #include "base/utils/utils.h" #include "core/components_ng/base/view_stack_processor.h" +#include "core/event/touch_event.h" +#include "core/pipeline_ng/pipeline_context.h" #include "frameworks/bridge/declarative_frontend/engine/functions/js_function.h" namespace OHOS::Ace::Framework { namespace { const char* DIRTY_FLAG[] = { "UPDATE_PROPERTY", "UPDATE_CONTENT" }; -} +} // namespace void JSBaseNode::BuildNode(const JSCallbackInfo& info) { @@ -75,6 +77,107 @@ void JSBaseNode::FinishUpdateFunc(const JSCallbackInfo& info) NG::ViewStackProcessor::GetInstance()->FlushRerenderTask(); } +void JSBaseNode::PostTouchEvent(const JSCallbackInfo& info) +{ + if (!viewNode_ || info.Length() < 1 || !info[0]->IsObject()) { + info.SetReturnValue(JSRef::Make(ToJSValue(false))); + return; + } + TouchEvent touchEvent; + auto obj = JSRef::Cast(info[0]); + auto typeJsVal = obj->GetProperty("type"); + if (typeJsVal->IsNumber()) { + touchEvent.type = static_cast(typeJsVal->ToNumber()); + } + auto sourceJsVal = obj->GetProperty("source"); + if (sourceJsVal->IsNumber()) { + touchEvent.sourceType = static_cast((sourceJsVal->ToNumber())); + } + auto sourceToolJsVal = obj->GetProperty("sourceTool"); + if (sourceToolJsVal->IsNumber()) { + touchEvent.sourceTool = static_cast((sourceToolJsVal->ToNumber())); + } + auto pressureJsVal = obj->GetProperty("pressure"); + if (pressureJsVal->IsNumber()) { + touchEvent.force = sourceToolJsVal->ToNumber(); + } + auto timestampJsVal = obj->GetProperty("timestamp"); + if (timestampJsVal->IsNumber()) { + std::chrono::nanoseconds nanoseconds(static_cast(timestampJsVal->ToNumber())); + TimeStamp time(nanoseconds); + touchEvent.time = time; + } + auto currentSysTimeJsVal = obj->GetProperty("currentSysTime"); + if (currentSysTimeJsVal->IsNumber()) { + touchEvent.currentSysTime = static_cast(currentSysTimeJsVal->ToNumber()); + } + auto deviceIdJsVal = obj->GetProperty("deviceId"); + if (deviceIdJsVal->IsNumber()) { + touchEvent.deviceId = deviceIdJsVal->ToNumber(); + } + auto targetDisplayIdJsVal = obj->GetProperty("targetDisplayId"); + if (targetDisplayIdJsVal->IsNumber()) { + touchEvent.targetDisplayId = targetDisplayIdJsVal->ToNumber(); + } + auto touchesJsVal = obj->GetProperty("touches"); + if (touchesJsVal->IsArray()) { + JSRef touchesArray = JSRef::Cast(touchesJsVal); + for (auto index = 0; index < static_cast(touchesArray->Length()); index++) { + JSRef item = touchesArray->GetValueAt(index); + if (!item->IsObject()) { + continue; + } + JSRef itemObj = JSRef::Cast(item); + TouchPoint point; + point.id = itemObj->GetPropertyValue("id", 0); + point.x = itemObj->GetPropertyValue("x", 0.0f); + point.y = itemObj->GetPropertyValue("y", 0.0f); + point.screenX = itemObj->GetPropertyValue("screenX", 0.0f); + point.screenY = itemObj->GetPropertyValue("screenY", 0.0f); + touchEvent.pointers.emplace_back(point); + } + } + auto titleXJsVal = obj->GetProperty("tiltX"); + if (titleXJsVal->IsNumber()) { + touchEvent.tiltX = titleXJsVal->ToNumber(); + } + auto titleYJsVal = obj->GetProperty("tiltY"); + if (titleYJsVal->IsNumber()) { + touchEvent.tiltY = titleYJsVal->ToNumber(); + } + auto changedTouchesJsVal = obj->GetProperty("changedTouches"); + if (changedTouchesJsVal->IsArray()) { + JSRef changedTouchesArray = JSRef::Cast(changedTouchesJsVal); + if (static_cast(changedTouchesArray->Length()) <= 0) { + info.SetReturnValue(JSRef::Make(ToJSValue(false))); + return; + } + JSRef item = changedTouchesArray->GetValueAt(0); + if (!item->IsObject()) { + info.SetReturnValue(JSRef::Make(ToJSValue(false))); + return; + } + JSRef itemObj = JSRef::Cast(item); + touchEvent.id = itemObj->GetPropertyValue("id", 0); + touchEvent.x = itemObj->GetPropertyValue("x", 0.0f); + touchEvent.y = itemObj->GetPropertyValue("y", 0.0f); + touchEvent.screenX = itemObj->GetPropertyValue("screenX", 0.0f); + touchEvent.screenY = itemObj->GetPropertyValue("screenY", 0.0f); + } + auto pipelineContext = NG::PipelineContext::GetCurrentContext(); + if (!pipelineContext) { + info.SetReturnValue(JSRef::Make(ToJSValue(false))); + return; + } + auto postEventManager = pipelineContext->GetPostEventManager(); + if (!postEventManager) { + info.SetReturnValue(JSRef::Make(ToJSValue(false))); + return; + } + auto result = postEventManager->PostEvent(viewNode_, touchEvent); + info.SetReturnValue(JSRef::Make(ToJSValue(result))); +} + void JSBaseNode::JSBind(BindingTarget globalObj) { JSClass::Declare("__JSBaseNode__"); @@ -82,6 +185,7 @@ void JSBaseNode::JSBind(BindingTarget globalObj) JSClass::CustomMethod("build", &JSBaseNode::BuildNode); JSClass::CustomMethod("markDirty", &JSBaseNode::MarkDirty); JSClass::CustomMethod("finishUpdateFunc", &JSBaseNode::FinishUpdateFunc); + JSClass::CustomMethod("postTouchEvent", &JSBaseNode::PostTouchEvent); JSClass::Bind(globalObj, JSBaseNode::ConstructorCallback, JSBaseNode::DestructorCallback); } diff --git a/frameworks/bridge/declarative_frontend/jsview/js_base_node.h b/frameworks/bridge/declarative_frontend/jsview/js_base_node.h index 1faa538f33e..ea4f02aed7c 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_base_node.h +++ b/frameworks/bridge/declarative_frontend/jsview/js_base_node.h @@ -32,6 +32,7 @@ public: void MarkDirty(const JSCallbackInfo& info); void FinishUpdateFunc(const JSCallbackInfo& info); void BuildNode(const JSCallbackInfo& info); + void PostTouchEvent(const JSCallbackInfo& info); RefPtr GetViewNode() const { diff --git a/frameworks/core/common/event_manager.cpp b/frameworks/core/common/event_manager.cpp index fefcca86e4e..c4b4efdfd25 100644 --- a/frameworks/core/common/event_manager.cpp +++ b/frameworks/core/common/event_manager.cpp @@ -164,6 +164,35 @@ void EventManager::TouchTest(const TouchEvent& touchPoint, const RefPtr& uiNode, const TouchRestrict& touchRestrict) +{ + ContainerScope scope(instanceId_); + ACE_FUNCTION_TRACE(); + CHECK_NULL_RETURN(uiNode, false); + // collect + TouchTestResult hitTestResult; + const NG::PointF point { touchPoint.x, touchPoint.y }; + postEventRefereeNG_->CheckSourceTypeChange(touchPoint.sourceType); + if (postEventRefereeNG_->QueryAllDone(touchPoint.id)) { + postEventRefereeNG_->CleanGestureScope(touchPoint.id); + if (postEventTouchTestResults_.empty() && postEventRefereeNG_->QueryAllDone()) { + postEventRefereeNG_->CleanAll(); + } + } + // For root node, the parent local point is the same as global point. + auto result = uiNode->TouchTest(point, point, point, touchRestrict, hitTestResult, touchPoint.id); + for (const auto& item : hitTestResult) { + item->SetIsPostEventResult(true); + auto group = AceType::DynamicCast(item); + if (group) { + group->SetIsPostEventResultRecursively(true); + } + } + postEventTouchTestResults_[touchPoint.id] = std::move(hitTestResult); + return !(static_cast(result) == 0); +} + void EventManager::TouchTest( const AxisEvent& event, const RefPtr& frameNode, const TouchRestrict& touchRestrict) { @@ -468,6 +497,60 @@ bool EventManager::DispatchTouchEvent(const TouchEvent& event) return true; } +bool EventManager::PostEventDispatchTouchEvent(const TouchEvent& event) +{ + ContainerScope scope(instanceId_); + TouchEvent point = event; + const auto iter = postEventTouchTestResults_.find(point.id); + ACE_SCOPED_TRACE( + "PostEventDispatchTouchEvent id:%d, pointX=%f pointY=%f type=%d", point.id, point.x, point.y, (int)point.type); + + if (point.type == TouchType::DOWN) { + // first collect gesture into gesture referee. + postEventRefereeNG_->AddGestureToScope(point.id, iter->second); + // add gesture snapshot to dump + for (const auto& target : iter->second) { + AddGestureSnapshot(point.id, 0, target); + } + } + + bool dispatchSuccess = true; + for (auto entry = iter->second.rbegin(); entry != iter->second.rend(); ++entry) { + if (!(*entry)->DispatchMultiContainerEvent(point)) { + dispatchSuccess = false; + break; + } + } + // If one gesture recognizer has already been won, other gesture recognizers will still be affected by + // the event, each recognizer needs to filter the extra events by itself. + if (dispatchSuccess) { + bool isStopTouchEvent = false; + for (const auto& entry : iter->second) { + auto recognizer = AceType::DynamicCast(entry); + if (recognizer) { + entry->HandleMultiContainerEvent(point); + eventTree_.AddGestureProcedure(reinterpret_cast(AceType::RawPtr(recognizer)), point, + NG::TransRefereeState(recognizer->GetRefereeState()), + NG::TransGestureDisposal(recognizer->GetGestureDisposal())); + } + if (!recognizer && !isStopTouchEvent) { + isStopTouchEvent = !entry->HandleMultiContainerEvent(point); + eventTree_.AddGestureProcedure(reinterpret_cast(AceType::RawPtr(entry)), + std::string("Handle").append(GestureSnapshot::TransTouchType(point.type)), "", ""); + } + } + } + + if (point.type == TouchType::UP || point.type == TouchType::CANCEL) { + postEventRefereeNG_->CleanGestureScope(point.id); + postEventTouchTestResults_.erase(point.id); + if (postEventTouchTestResults_.empty()) { + postEventRefereeNG_->CleanRedundanceScope(); + } + } + return true; +} + bool EventManager::DispatchTouchEvent(const AxisEvent& event) { ContainerScope scope(instanceId_); @@ -1326,6 +1409,7 @@ void EventManager::DelKeyboardShortcutNode(int32_t nodeId) void EventManager::ClearResults() { touchTestResults_.clear(); + postEventTouchTestResults_.clear(); mouseTestResults_.clear(); axisTouchTestResults_.clear(); keyboardShortcutNode_.clear(); @@ -1334,6 +1418,7 @@ void EventManager::ClearResults() EventManager::EventManager() { refereeNG_ = AceType::MakeRefPtr(); + postEventRefereeNG_ = AceType::MakeRefPtr(); referee_ = AceType::MakeRefPtr(); responseCtrl_ = AceType::MakeRefPtr(); diff --git a/frameworks/core/common/event_manager.h b/frameworks/core/common/event_manager.h index abb08cfa5fb..d7054ad0119 100644 --- a/frameworks/core/common/event_manager.h +++ b/frameworks/core/common/event_manager.h @@ -23,6 +23,7 @@ #include "core/components/common/layout/constants.h" #include "core/components_ng/event/response_ctrl.h" #include "core/components_ng/gestures/gesture_referee.h" +#include "core/components_ng/gestures/recognizers/gesture_recognizer.h" #include "core/event/axis_event.h" #include "core/event/key_event.h" #include "core/event/mouse_event.h" @@ -73,6 +74,9 @@ public: const TouchRestrict& touchRestrict, const Offset& offset = Offset(), float viewScale = 1.0f, bool needAppend = false); + bool PostEventTouchTest(const TouchEvent& touchPoint, const RefPtr& uiNode, + const TouchRestrict& touchRestrict); + void TouchTest(const AxisEvent& event, const RefPtr& renderNode, const TouchRestrict& touchRestrict); void TouchTest(const AxisEvent& event, const RefPtr& frameNode, const TouchRestrict& touchRestrict); @@ -81,6 +85,7 @@ public: bool DispatchTouchEvent(const TouchEvent& point); bool DispatchTouchEvent(const AxisEvent& event); + bool PostEventDispatchTouchEvent(const TouchEvent& point); void FlushTouchEventsBegin(const std::list& touchEvents); void FlushTouchEventsEnd(const std::list& touchEvents); @@ -146,8 +151,11 @@ public: return referee_; } - RefPtr GetGestureRefereeNG() + RefPtr GetGestureRefereeNG(const RefPtr& recognizer) { + if (recognizer->IsPostEventResult()) { + return postEventRefereeNG_; + } return refereeNG_; } @@ -215,6 +223,7 @@ public: void CheckTouchEvent(TouchEvent touchEvent); private: std::unordered_map touchTestResults_; + std::unordered_map postEventTouchTestResults_; std::unordered_map mouseTestResults_; MouseTestResult currMouseTestResults_; MouseTestResult pressMouseTestResults_; @@ -236,6 +245,7 @@ private: bool isLastMoveBeforeUp_ = false; RefPtr referee_; RefPtr refereeNG_; + RefPtr postEventRefereeNG_; std::list> keyboardShortcutNode_; std::vector pressedKeyCodes_; NG::EventTreeRecord eventTree_; diff --git a/frameworks/core/components_ng/base/frame_node.cpp b/frameworks/core/components_ng/base/frame_node.cpp index e590958f428..7f57073be97 100644 --- a/frameworks/core/components_ng/base/frame_node.cpp +++ b/frameworks/core/components_ng/base/frame_node.cpp @@ -1634,7 +1634,7 @@ HitTestResult FrameNode::TouchTest(const PointF& globalPoint, const PointF& pare param[8], GetId(), localMat }; } - if (GetInspectorId()->find("SCBScreen-Temp") != std::string::npos && + if (GetInspectorId().has_value() && GetInspectorId()->find("SCBScreen-Temp") != std::string::npos && static_cast(translateCfg[GetId()].degree) != 0) { translateCfg[GetId()].degree = 0.0; translateCfg[GetId()].localMat = Matrix4(); diff --git a/frameworks/core/components_ng/event/touch_event.cpp b/frameworks/core/components_ng/event/touch_event.cpp index 01aa665533e..99df5cc0c88 100644 --- a/frameworks/core/components_ng/event/touch_event.cpp +++ b/frameworks/core/components_ng/event/touch_event.cpp @@ -52,6 +52,7 @@ bool TouchEventActuator::TriggerTouchCallBack(const TouchEvent& point) } TouchEventInfo event("touchEvent"); event.SetTimeStamp(lastPoint.time); + event.SetCurrentSysTime(lastPoint.currentSysTime); event.SetPointerEvent(lastPoint.pointerEvent); TouchLocationInfo changedInfo("onTouch", lastPoint.id); PointF lastLocalPoint(lastPoint.x, lastPoint.y); diff --git a/frameworks/core/components_ng/gestures/recognizers/click_recognizer.cpp b/frameworks/core/components_ng/gestures/recognizers/click_recognizer.cpp index f28f7f87fb1..00c51d54e01 100644 --- a/frameworks/core/components_ng/gestures/recognizers/click_recognizer.cpp +++ b/frameworks/core/components_ng/gestures/recognizers/click_recognizer.cpp @@ -48,7 +48,9 @@ bool ClickRecognizer::IsPointInRegion(const TouchEvent& event) PointF localPoint(event.x, event.y); auto frameNode = GetAttachedNode(); if (!frameNode.Invalid()) { - NGGestureRecognizer::Transform(localPoint, frameNode); + if (!IsPostEventResult()) { + NGGestureRecognizer::Transform(localPoint, frameNode); + } auto host = frameNode.Upgrade(); CHECK_NULL_RETURN(host, false); auto renderContext = host->GetRenderContext(); diff --git a/frameworks/core/components_ng/gestures/recognizers/gesture_recognizer.cpp b/frameworks/core/components_ng/gestures/recognizers/gesture_recognizer.cpp index d059e1c6bdf..c111b61f3cd 100644 --- a/frameworks/core/components_ng/gestures/recognizers/gesture_recognizer.cpp +++ b/frameworks/core/components_ng/gestures/recognizers/gesture_recognizer.cpp @@ -17,6 +17,7 @@ #include "base/log/log.h" #include "base/memory/ace_type.h" +#include "base/memory/referenced.h" #include "base/utils/utils.h" #include "core/common/container.h" #include "core/components_ng/event/response_ctrl.h" @@ -35,11 +36,11 @@ RefPtr GetCurrentEventManager() return context->GetEventManager(); } -RefPtr GetCurrentGestureReferee() +RefPtr GetCurrentGestureReferee(const RefPtr& recognizer) { auto eventManager = GetCurrentEventManager(); CHECK_NULL_RETURN(eventManager, nullptr); - return eventManager->GetGestureRefereeNG(); + return eventManager->GetGestureRefereeNG(recognizer); } } // namespace @@ -164,7 +165,7 @@ void NGGestureRecognizer::BatchAdjudicate(const RefPtr& rec return; } - auto referee = GetCurrentGestureReferee(); + auto referee = GetCurrentGestureReferee(recognizer); if (!referee) { recognizer->OnRejected(); return; diff --git a/frameworks/core/components_ng/gestures/recognizers/long_press_recognizer.cpp b/frameworks/core/components_ng/gestures/recognizers/long_press_recognizer.cpp index 11240aca9a2..b9c7d9b4cda 100644 --- a/frameworks/core/components_ng/gestures/recognizers/long_press_recognizer.cpp +++ b/frameworks/core/components_ng/gestures/recognizers/long_press_recognizer.cpp @@ -118,15 +118,17 @@ void LongPressRecognizer::HandleTouchDownEvent(const TouchEvent& event) "Long press recognizer receives %{public}d touch down event, begin to detect long press event", event.id); int32_t curDuration = duration_; #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW) - int64_t currentTimeStamp = GetSysTimestamp(); - int64_t eventTimeStamp = static_cast(event.time.time_since_epoch().count()); - if (currentTimeStamp > eventTimeStamp) { - TAG_LOGI( - AceLogTag::ACE_GESTURE, "CurrentTimeStamp is larger than eventTimeStamp, need to minus time spent waiting"); - // nanoseconds to millisceond. - curDuration = curDuration - static_cast((currentTimeStamp - eventTimeStamp) / (1000 * 1000)); - if (curDuration < 0) { - curDuration = 0; + if (!IsPostEventResult()) { + int64_t currentTimeStamp = GetSysTimestamp(); + int64_t eventTimeStamp = static_cast(event.time.time_since_epoch().count()); + if (currentTimeStamp > eventTimeStamp) { + TAG_LOGI(AceLogTag::ACE_GESTURE, + "CurrentTimeStamp is larger than eventTimeStamp, need to minus time spent waiting"); + // nanoseconds to millisceond. + curDuration = curDuration - static_cast((currentTimeStamp - eventTimeStamp) / (1000 * 1000)); + if (curDuration < 0) { + curDuration = 0; + } } } #endif diff --git a/frameworks/core/components_ng/gestures/recognizers/recognizer_group.h b/frameworks/core/components_ng/gestures/recognizers/recognizer_group.h index d22a49343f3..76b37a361da 100644 --- a/frameworks/core/components_ng/gestures/recognizers/recognizer_group.h +++ b/frameworks/core/components_ng/gestures/recognizers/recognizer_group.h @@ -147,6 +147,18 @@ public: refereeState_ = RefereeState::READY; disposal_ = GestureDisposal::NONE; } + + void SetIsPostEventResultRecursively(bool isPostEventResult) + { + for (const auto& item : recognizers_) { + item->SetIsPostEventResult(isPostEventResult); + auto group = AceType::DynamicCast(item); + if (group) { + group->SetIsPostEventResultRecursively(isPostEventResult); + } + } + } + protected: void OnBeginGestureReferee(int32_t touchId, bool needUpdateChild = false) override; void OnFinishGestureReferee(int32_t touchId, bool isBlocked = false) override; diff --git a/frameworks/core/components_ng/manager/BUILD.gn b/frameworks/core/components_ng/manager/BUILD.gn index f30c1cbe145..8a64259979f 100644 --- a/frameworks/core/components_ng/manager/BUILD.gn +++ b/frameworks/core/components_ng/manager/BUILD.gn @@ -22,6 +22,7 @@ build_component_ng("manager_ng") { "drag_drop/drag_drop_proxy.cpp", "frame_rate/frame_rate_manager.cpp", "full_screen/full_screen_manager.cpp", + "post_event/post_event_manager.cpp", "safe_area/safe_area_manager.cpp", "select_overlay/select_overlay_client.cpp", "select_overlay/select_overlay_manager.cpp", diff --git a/frameworks/core/components_ng/manager/post_event/post_event_manager.cpp b/frameworks/core/components_ng/manager/post_event/post_event_manager.cpp new file mode 100644 index 00000000000..e6e873072c1 --- /dev/null +++ b/frameworks/core/components_ng/manager/post_event/post_event_manager.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core/components_ng/manager/post_event/post_event_manager.h" + +#include "base/log/log_wrapper.h" +#include "core/pipeline_ng/pipeline_context.h" + +namespace OHOS::Ace::NG { + +bool PostEventManager::PostEvent(const RefPtr& uiNode, const TouchEvent& touchEvent) +{ + if (!CheckPointValidity(touchEvent)) { + return false; + } + auto result = false; + switch (touchEvent.type) { + case TouchType::DOWN: + result = PostDownEvent(uiNode, touchEvent); + break; + case TouchType::MOVE: + result = PostMoveEvent(uiNode, touchEvent); + break; + case TouchType::UP: + case TouchType::CANCEL: + result = PostUpEvent(uiNode, touchEvent); + break; + default: + TAG_LOGE(AceLogTag::ACE_GESTURE, "dispatchEvent touchEvent type unkown"); + break; + } + return result; +} + +bool PostEventManager::PostDownEvent(const RefPtr& targetNode, const TouchEvent& touchEvent) +{ + CHECK_NULL_RETURN(targetNode, false); + + for (const auto& iter : postEventAction_) { + if (iter.targetNode == targetNode && iter.touchEvent.type == TouchType::DOWN && + iter.touchEvent.id == touchEvent.id) { + auto lastEventMap = lastEventMap_; + auto lastItem = lastEventMap.find(touchEvent.id); + if (lastItem != lastEventMap.end()) { + auto event = lastItem->second.touchEvent; + event.type = TouchType::CANCEL; + PostUpEvent(lastItem->second.targetNode, event); + break; + } + return false; + } + } + auto pipelineContext = PipelineContext::GetCurrentContext(); + CHECK_NULL_RETURN(pipelineContext, false); + auto eventManager = pipelineContext->GetEventManager(); + CHECK_NULL_RETURN(eventManager, false); + auto scalePoint = touchEvent.CreateScalePoint(pipelineContext->GetViewScale()); + TouchRestrict touchRestrict { TouchRestrict::NONE }; + touchRestrict.sourceType = touchEvent.sourceType; + touchRestrict.touchEvent = touchEvent; + auto result = eventManager->PostEventTouchTest(scalePoint, targetNode, touchRestrict); + if (!result) { + return false; + } + + HandlePostEvent(targetNode, touchEvent); + return true; +} + +bool PostEventManager::PostMoveEvent(const RefPtr& targetNode, const TouchEvent& touchEvent) +{ + CHECK_NULL_RETURN(targetNode, false); + + if (!HaveReceiveDownEvent(targetNode, touchEvent.id) || HaveReceiveUpOrCancelEvent(targetNode, touchEvent.id)) { + return false; + } + + HandlePostEvent(targetNode, touchEvent); + return true; +} + +bool PostEventManager::PostUpEvent(const RefPtr& targetNode, const TouchEvent& touchEvent) +{ + CHECK_NULL_RETURN(targetNode, false); + + if (!HaveReceiveDownEvent(targetNode, touchEvent.id) || HaveReceiveUpOrCancelEvent(targetNode, touchEvent.id)) { + return false; + } + + HandlePostEvent(targetNode, touchEvent); + return true; +} + +void PostEventManager::HandlePostEvent(const RefPtr& targetNode, const TouchEvent& touchEvent) +{ + // push dispatchAction and store + PostEventAction postEventAction; + postEventAction.targetNode = targetNode; + postEventAction.touchEvent = touchEvent; + lastEventMap_[touchEvent.id] = postEventAction; + postEventAction_.push_back(postEventAction); + auto pipelineContext = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipelineContext); + auto eventManager = pipelineContext->GetEventManager(); + eventManager->PostEventDispatchTouchEvent(touchEvent); + // when receive UP event, clear DispatchAction which is same targetNode and same id + CheckAndClearPostEventAction(targetNode, touchEvent.id); +} + +void PostEventManager::CheckAndClearPostEventAction(const RefPtr& targetNode, int32_t id) +{ + bool receiveDown = false; + bool receiveUp = false; + for (const auto& iter : postEventAction_) { + if (iter.targetNode == targetNode && iter.touchEvent.id == id) { + if (iter.touchEvent.type == TouchType::DOWN) { + receiveDown = true; + } else if ((iter.touchEvent.type == TouchType::UP || iter.touchEvent.type == TouchType::CANCEL) && + receiveDown) { + receiveUp = true; + } + } + } + if (receiveUp) { + for (auto iter = postEventAction_.begin(); iter != postEventAction_.end();) { + if (iter->targetNode == targetNode && iter->touchEvent.id == id) { + iter = postEventAction_.erase(iter); + } else { + ++iter; + } + } + lastEventMap_.erase(id); + } +} + +bool PostEventManager::HaveReceiveDownEvent(const RefPtr& targetNode, int32_t id) +{ + return std::any_of(postEventAction_.begin(), postEventAction_.end(), [targetNode, id](const auto& actionItem) { + return actionItem.targetNode == targetNode && actionItem.touchEvent.type == TouchType::DOWN && + actionItem.touchEvent.id == id; + }); +} + +bool PostEventManager::HaveReceiveUpOrCancelEvent(const RefPtr& targetNode, int32_t id) +{ + return std::any_of(postEventAction_.begin(), postEventAction_.end(), [targetNode, id](const auto& actionItem) { + return actionItem.targetNode == targetNode && + (actionItem.touchEvent.type == TouchType::UP || actionItem.touchEvent.type == TouchType::CANCEL) && + actionItem.touchEvent.id == id; + }); +} + +bool PostEventManager::CheckPointValidity(const TouchEvent& touchEvent) +{ + return !std::any_of(postEventAction_.begin(), postEventAction_.end(), [touchEvent](const auto& actionItem) { + return actionItem.touchEvent.id == touchEvent.id && actionItem.touchEvent.time == touchEvent.time; + }); +} + +void PostEventManager::CheckNeedReissueCancelEvent(int64_t currentSysTime) +{ + auto lastEventMap = lastEventMap_; + for (const auto& item : lastEventMap) { + if ((currentSysTime - item.second.touchEvent.currentSysTime) > (800 * 1000 * 1000)) { + auto event = item.second.touchEvent; + event.type = TouchType::CANCEL; + PostUpEvent(item.second.targetNode, event); + } + } +} +} // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/manager/post_event/post_event_manager.h b/frameworks/core/components_ng/manager/post_event/post_event_manager.h new file mode 100644 index 00000000000..01d5e1596b5 --- /dev/null +++ b/frameworks/core/components_ng/manager/post_event/post_event_manager.h @@ -0,0 +1,58 @@ +/* + * 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 FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_MANAGER_POST_EVENT_POST_EVENT_MANAGER_H +#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_MANAGER_POST_EVENT_POST_EVENT_MANAGER_H + +#include + +#include "base/memory/referenced.h" +#include "core/event/touch_event.h" + +namespace OHOS::Ace::NG { + +struct PostEventAction { + RefPtr targetNode = nullptr; + TouchEvent touchEvent; +}; + +class ACE_FORCE_EXPORT PostEventManager : public virtual AceType { + DECLARE_ACE_TYPE(PostEventManager, AceType); + +public: + PostEventManager() = default; + ~PostEventManager() override = default; + + bool PostEvent(const RefPtr& uiNode, const TouchEvent& touchEvent); + void CheckNeedReissueCancelEvent(int64_t currentSysTime); + +private: + bool CheckPointValidity(const TouchEvent& touchEvent); + bool PostDownEvent(const RefPtr& targetNode, const TouchEvent& touchEvent); + bool PostMoveEvent(const RefPtr& targetNode, const TouchEvent& touchEvent); + bool PostUpEvent(const RefPtr& targetNode, const TouchEvent& touchEvent); + + void HandlePostEvent(const RefPtr& targetNode, const TouchEvent& touchEvent); + + void CheckAndClearPostEventAction(const RefPtr& targetNode, int32_t id); + + bool HaveReceiveDownEvent(const RefPtr& targetNode, int32_t id); + bool HaveReceiveUpOrCancelEvent(const RefPtr& targetNode, int32_t id); + std::list postEventAction_; + std::map lastEventMap_; +}; +} // namespace OHOS::Ace::NG + +#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_MANAGER_POST_EVENT_POST_EVENT_MANAGER_H \ No newline at end of file diff --git a/frameworks/core/event/touch_event.h b/frameworks/core/event/touch_event.h index fe5d0c7c75b..6490b48e782 100755 --- a/frameworks/core/event/touch_event.h +++ b/frameworks/core/event/touch_event.h @@ -90,6 +90,7 @@ struct TouchEvent final { SourceType sourceType = SourceType::NONE; SourceTool sourceTool = SourceTool::UNKNOWN; bool isInterpolated = false; + int64_t currentSysTime = 0; // all points on the touch screen. std::vector pointers; @@ -167,11 +168,17 @@ struct TouchEvent final { } } + void SetCurrentTime(int64_t currentTime) + { + currentSysTime = currentTime; + } + TouchEvent CreateScalePoint(float scale) const { if (NearZero(scale)) { return { id, x, y, screenX, screenY, type, pullType, time, size, force, tiltX, tiltY, deviceId, - targetDisplayId, sourceType, sourceTool, isInterpolated, pointers, pointerEvent, enhanceData }; + targetDisplayId, sourceType, sourceTool, isInterpolated, currentSysTime, pointers, pointerEvent, + enhanceData }; } auto temp = pointers; std::for_each(temp.begin(), temp.end(), [scale](auto&& point) { @@ -181,7 +188,8 @@ struct TouchEvent final { point.screenY = point.screenY / scale; }); return { id, x / scale, y / scale, screenX / scale, screenY / scale, type, pullType, time, size, force, tiltX, - tiltY, deviceId, targetDisplayId, sourceType, sourceTool, isInterpolated, temp, pointerEvent, enhanceData }; + tiltY, deviceId, targetDisplayId, sourceType, sourceTool, isInterpolated, currentSysTime, temp, + pointerEvent, enhanceData }; } TouchEvent UpdateScalePoint(float scale, float offsetX, float offsetY, int32_t pointId) const @@ -196,7 +204,7 @@ struct TouchEvent final { }); return { pointId, x - offsetX, y - offsetY, screenX - offsetX, screenY - offsetY, type, pullType, time, size, force, tiltX, tiltY, deviceId, targetDisplayId, sourceType, sourceTool, isInterpolated, - temp, pointerEvent, enhanceData }; + currentSysTime, temp, pointerEvent, enhanceData }; } std::for_each(temp.begin(), temp.end(), [scale, offsetX, offsetY](auto&& point) { @@ -207,7 +215,7 @@ struct TouchEvent final { }); return { pointId, (x - offsetX) / scale, (y - offsetY) / scale, (screenX - offsetX) / scale, (screenY - offsetY) / scale, type, pullType, time, size, force, tiltX, tiltY, deviceId, targetDisplayId, - sourceType, sourceTool, isInterpolated, temp, pointerEvent, enhanceData }; + sourceType, sourceTool, isInterpolated, currentSysTime, temp, pointerEvent, enhanceData }; } TouchEvent UpdatePointers() const @@ -652,6 +660,17 @@ public: { return targetComponent_; } + + void SetIsPostEventResult(bool isPostEventResult) + { + isPostEventResult_ = isPostEventResult; + } + + bool IsPostEventResult() const + { + return isPostEventResult_; + } + private: virtual bool ShouldResponse() { return true; }; @@ -666,6 +685,7 @@ protected: WeakPtr node_ = nullptr; Axis direction_ = Axis::NONE; RefPtr targetComponent_; + bool isPostEventResult_ = false; }; using TouchTestResult = std::list>; @@ -712,11 +732,21 @@ public: return pointerEvent_; } + int64_t GetCurrentSysTime() + { + return currentSysTime_; + } + void SetCurrentSysTime(int64_t currentSysTime) + { + currentSysTime_ = currentSysTime; + } + private: std::shared_ptr pointerEvent_; std::list touches_; std::list changedTouches_; std::list history_; + int64_t currentSysTime_ = 0; }; using TouchEventFunc = std::function; diff --git a/frameworks/core/pipeline_ng/pipeline_context.cpp b/frameworks/core/pipeline_ng/pipeline_context.cpp index d1885cf0852..401151d8959 100755 --- a/frameworks/core/pipeline_ng/pipeline_context.cpp +++ b/frameworks/core/pipeline_ng/pipeline_context.cpp @@ -472,6 +472,7 @@ void PipelineContext::FlushVsync(uint64_t nanoTimestamp, uint32_t frameCount) CHECK_RUN_ON(UI); ACE_FUNCTION_TRACE(); auto recvTime = GetSysTimestamp(); + postEventManager_->CheckNeedReissueCancelEvent(recvTime); static const std::string abilityName = AceApplicationInfo::GetInstance().GetProcessName().empty() ? AceApplicationInfo::GetInstance().GetPackageName() : AceApplicationInfo::GetInstance().GetProcessName(); @@ -842,6 +843,7 @@ void PipelineContext::SetupRootElement() DynamicCast(installationFree_ ? stageNode->GetParent()->GetParent() : stageNode->GetParent())); fullScreenManager_ = MakeRefPtr(rootNode_); selectOverlayManager_ = MakeRefPtr(rootNode_); + postEventManager_ = MakeRefPtr(); dragDropManager_ = MakeRefPtr(); sharedTransitionManager_ = MakeRefPtr( DynamicCast(installationFree_ ? stageNode->GetParent()->GetParent() : stageNode->GetParent())); @@ -896,6 +898,7 @@ void PipelineContext::SetupSubRootElement() fullScreenManager_ = MakeRefPtr(rootNode_); selectOverlayManager_ = MakeRefPtr(rootNode_); dragDropManager_ = MakeRefPtr(); + postEventManager_ = MakeRefPtr(); } const RefPtr& PipelineContext::GetStageManager() @@ -2961,4 +2964,9 @@ void PipelineContext::SubscribeContainerModalButtonsRectChange( CHECK_NULL_VOID(containerPattern); containerPattern->SubscribeContainerModalButtonsRectChange(std::move(callback)); } + +const RefPtr& PipelineContext::GetPostEventManager() +{ + return postEventManager_; +} } // namespace OHOS::Ace::NG diff --git a/frameworks/core/pipeline_ng/pipeline_context.h b/frameworks/core/pipeline_ng/pipeline_context.h index f98e3691b6e..0caca591d71 100644 --- a/frameworks/core/pipeline_ng/pipeline_context.h +++ b/frameworks/core/pipeline_ng/pipeline_context.h @@ -34,6 +34,7 @@ #include "core/components_ng/manager/drag_drop/drag_drop_manager.h" #include "core/components_ng/manager/frame_rate/frame_rate_manager.h" #include "core/components_ng/manager/full_screen/full_screen_manager.h" +#include "core/components_ng/manager/post_event/post_event_manager.h" #include "core/components_ng/manager/safe_area/safe_area_manager.h" #include "core/components_ng/manager/select_overlay/select_overlay_manager.h" #include "core/components_ng/manager/shared_overlay/shared_overlay_manager.h" @@ -550,6 +551,7 @@ public: bool IsDragging() const override; void SetIsDragging(bool isDragging) override; + const RefPtr& GetPostEventManager(); void SetContainerModalTitleVisible(bool customTitleSettedShow, bool floatingTitleSettedShow); void SetContainerModalTitleHeight(int32_t height); @@ -725,6 +727,7 @@ private: mutable std::mutex navigationMutex_; std::map> navigationNodes_; std::list delayedTasks_; + RefPtr postEventManager_; ACE_DISALLOW_COPY_AND_MOVE(PipelineContext); }; diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index f0af3984b69..94fb14e790b 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -232,6 +232,7 @@ ohos_source_set("ace_components_manager") { "$ace_root/frameworks/core/components_ng/manager/drag_drop/drag_drop_proxy.cpp", "$ace_root/frameworks/core/components_ng/manager/frame_rate/frame_rate_manager.cpp", "$ace_root/frameworks/core/components_ng/manager/full_screen/full_screen_manager.cpp", + "$ace_root/frameworks/core/components_ng/manager/post_event/post_event_manager.cpp", "$ace_root/frameworks/core/components_ng/manager/safe_area/safe_area_manager.cpp", "$ace_root/frameworks/core/components_ng/manager/select_overlay/select_overlay_client.cpp", "$ace_root/frameworks/core/components_ng/manager/select_overlay/select_overlay_manager.cpp", -- Gitee