1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/manager/post_event/post_event_manager.h"
17
18 #include "base/log/log_wrapper.h"
19 #include "core/pipeline_ng/pipeline_context.h"
20
21 namespace OHOS::Ace::NG {
22
PostEvent(const RefPtr<NG::UINode> & uiNode,TouchEvent & touchEvent)23 bool PostEventManager::PostEvent(const RefPtr<NG::UINode>& uiNode, TouchEvent& touchEvent)
24 {
25 if (!CheckPointValidity(touchEvent)) {
26 return false;
27 }
28 CHECK_NULL_RETURN(uiNode, false);
29 touchEvent.postEventNodeId = uiNode->GetId();
30 auto result = false;
31 switch (touchEvent.type) {
32 case TouchType::DOWN:
33 result = PostDownEvent(uiNode, touchEvent);
34 break;
35 case TouchType::MOVE:
36 result = PostMoveEvent(uiNode, touchEvent);
37 break;
38 case TouchType::UP:
39 case TouchType::CANCEL:
40 result = PostUpEvent(uiNode, touchEvent);
41 break;
42 default:
43 TAG_LOGE(AceLogTag::ACE_GESTURE, "dispatchEvent touchEvent type unkown");
44 break;
45 }
46 return result;
47 }
48
PostDownEvent(const RefPtr<NG::UINode> & targetNode,const TouchEvent & touchEvent)49 bool PostEventManager::PostDownEvent(const RefPtr<NG::UINode>& targetNode, const TouchEvent& touchEvent)
50 {
51 CHECK_NULL_RETURN(targetNode, false);
52
53 for (const auto& iter : postEventAction_) {
54 if (iter.targetNode == targetNode && iter.touchEvent.type == TouchType::DOWN &&
55 iter.touchEvent.id == touchEvent.id) {
56 auto lastEventMap = lastEventMap_;
57 auto lastItem = lastEventMap.find(touchEvent.id);
58 if (lastItem != lastEventMap.end()) {
59 auto event = lastItem->second.touchEvent;
60 event.type = TouchType::CANCEL;
61 PostUpEvent(lastItem->second.targetNode, event);
62 break;
63 }
64 return false;
65 }
66 }
67 auto pipelineContext = PipelineContext::GetCurrentContext();
68 CHECK_NULL_RETURN(pipelineContext, false);
69 auto eventManager = pipelineContext->GetEventManager();
70 CHECK_NULL_RETURN(eventManager, false);
71 auto scalePoint = touchEvent.CreateScalePoint(pipelineContext->GetViewScale());
72 eventManager->GetEventTreeRecord(EventTreeType::POST_EVENT).AddTouchPoint(scalePoint);
73 TouchRestrict touchRestrict { TouchRestrict::NONE };
74 touchRestrict.sourceType = touchEvent.sourceType;
75 touchRestrict.touchEvent = touchEvent;
76 touchRestrict.inputEventType = InputEventType::TOUCH_SCREEN;
77 touchRestrict.touchTestType = EventTreeType::POST_EVENT;
78 auto result = eventManager->PostEventTouchTest(scalePoint, targetNode, touchRestrict);
79 if (!result) {
80 return false;
81 }
82 HandlePostEvent(targetNode, touchEvent);
83 return true;
84 }
85
PostMoveEvent(const RefPtr<NG::UINode> & targetNode,const TouchEvent & touchEvent)86 bool PostEventManager::PostMoveEvent(const RefPtr<NG::UINode>& targetNode, const TouchEvent& touchEvent)
87 {
88 CHECK_NULL_RETURN(targetNode, false);
89
90 if (!HaveReceiveDownEvent(targetNode, touchEvent.id) || HaveReceiveUpOrCancelEvent(targetNode, touchEvent.id)) {
91 return false;
92 }
93
94 HandlePostEvent(targetNode, touchEvent);
95 return true;
96 }
97
PostUpEvent(const RefPtr<NG::UINode> & targetNode,const TouchEvent & touchEvent)98 bool PostEventManager::PostUpEvent(const RefPtr<NG::UINode>& targetNode, const TouchEvent& touchEvent)
99 {
100 CHECK_NULL_RETURN(targetNode, false);
101
102 if (!HaveReceiveDownEvent(targetNode, touchEvent.id) || HaveReceiveUpOrCancelEvent(targetNode, touchEvent.id)) {
103 return false;
104 }
105
106 HandlePostEvent(targetNode, touchEvent);
107 return true;
108 }
109
HandlePostEvent(const RefPtr<NG::UINode> & targetNode,const TouchEvent & touchEvent)110 void PostEventManager::HandlePostEvent(const RefPtr<NG::UINode>& targetNode, const TouchEvent& touchEvent)
111 {
112 // push dispatchAction and store
113 PostEventAction postEventAction;
114 postEventAction.targetNode = targetNode;
115 postEventAction.touchEvent = touchEvent;
116 lastEventMap_[touchEvent.id] = postEventAction;
117 postEventAction_.push_back(postEventAction);
118 auto pipelineContext = PipelineContext::GetCurrentContext();
119 CHECK_NULL_VOID(pipelineContext);
120 auto eventManager = pipelineContext->GetEventManager();
121 if (touchEvent.type != TouchType::DOWN && touchEvent.type != TouchType::MOVE) {
122 eventManager->GetEventTreeRecord(EventTreeType::POST_EVENT).AddTouchPoint(touchEvent);
123 }
124 eventManager->PostEventFlushTouchEventEnd(touchEvent);
125 eventManager->PostEventDispatchTouchEvent(touchEvent);
126 // when receive UP event, clear DispatchAction which is same targetNode and same id
127 CheckAndClearPostEventAction(targetNode, touchEvent.id);
128 }
129
CheckAndClearPostEventAction(const RefPtr<NG::UINode> & targetNode,int32_t id)130 void PostEventManager::CheckAndClearPostEventAction(const RefPtr<NG::UINode>& targetNode, int32_t id)
131 {
132 bool receiveDown = false;
133 bool receiveUp = false;
134 for (const auto& iter : postEventAction_) {
135 if (iter.targetNode == targetNode && iter.touchEvent.id == id) {
136 if (iter.touchEvent.type == TouchType::DOWN) {
137 receiveDown = true;
138 } else if ((iter.touchEvent.type == TouchType::UP || iter.touchEvent.type == TouchType::CANCEL) &&
139 receiveDown) {
140 receiveUp = true;
141 }
142 }
143 }
144 if (receiveUp) {
145 for (auto iter = postEventAction_.begin(); iter != postEventAction_.end();) {
146 if (iter->targetNode == targetNode && iter->touchEvent.id == id) {
147 iter = postEventAction_.erase(iter);
148 } else {
149 ++iter;
150 }
151 }
152 lastEventMap_.erase(id);
153 }
154 }
155
HaveReceiveDownEvent(const RefPtr<NG::UINode> & targetNode,int32_t id)156 bool PostEventManager::HaveReceiveDownEvent(const RefPtr<NG::UINode>& targetNode, int32_t id)
157 {
158 return std::any_of(postEventAction_.begin(), postEventAction_.end(), [targetNode, id](const auto& actionItem) {
159 return actionItem.targetNode == targetNode && actionItem.touchEvent.type == TouchType::DOWN &&
160 actionItem.touchEvent.id == id;
161 });
162 }
163
HaveReceiveUpOrCancelEvent(const RefPtr<NG::UINode> & targetNode,int32_t id)164 bool PostEventManager::HaveReceiveUpOrCancelEvent(const RefPtr<NG::UINode>& targetNode, int32_t id)
165 {
166 return std::any_of(postEventAction_.begin(), postEventAction_.end(), [targetNode, id](const auto& actionItem) {
167 return actionItem.targetNode == targetNode &&
168 (actionItem.touchEvent.type == TouchType::UP || actionItem.touchEvent.type == TouchType::CANCEL) &&
169 actionItem.touchEvent.id == id;
170 });
171 }
172
CheckPointValidity(const TouchEvent & touchEvent)173 bool PostEventManager::CheckPointValidity(const TouchEvent& touchEvent)
174 {
175 return !std::any_of(postEventAction_.begin(), postEventAction_.end(), [touchEvent](const auto& actionItem) {
176 return actionItem.touchEvent.id == touchEvent.id && actionItem.touchEvent.time == touchEvent.time;
177 });
178 }
179 } // namespace OHOS::Ace::NG
180