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