• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/gestures/recognizers/gesture_recognizer.h"
17 
18 #include "base/log/log.h"
19 #include "base/memory/ace_type.h"
20 #include "base/memory/referenced.h"
21 #include "base/utils/utils.h"
22 #include "core/common/container.h"
23 #include "core/components_ng/base/observer_handler.h"
24 #include "core/components_ng/event/response_ctrl.h"
25 #include "core/components_ng/gestures/gesture_referee.h"
26 #include "core/event/axis_event.h"
27 #include "core/event/touch_event.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29 
30 namespace OHOS::Ace::NG {
31 namespace {
GetCurrentEventManager()32 RefPtr<EventManager> GetCurrentEventManager()
33 {
34     auto context = PipelineContext::GetCurrentContext();
35     CHECK_NULL_RETURN(context, nullptr);
36 
37     return context->GetEventManager();
38 }
39 
GetCurrentGestureReferee(const RefPtr<NGGestureRecognizer> & recognizer)40 RefPtr<GestureReferee> GetCurrentGestureReferee(const RefPtr<NGGestureRecognizer>& recognizer)
41 {
42     auto eventManager = GetCurrentEventManager();
43     CHECK_NULL_RETURN(eventManager, nullptr);
44     return eventManager->GetGestureRefereeNG(recognizer);
45 }
46 
47 } // namespace
48 
ShouldResponse()49 bool NGGestureRecognizer::ShouldResponse()
50 {
51     if (AceType::InstanceOf<RecognizerGroup>(this)) {
52         return true;
53     }
54     auto eventManager = GetCurrentEventManager();
55     CHECK_NULL_RETURN(eventManager, true);
56     auto frameNode = GetAttachedNode();
57     auto ctrl = eventManager->GetResponseCtrl();
58     CHECK_NULL_RETURN(ctrl, true);
59     if (!ctrl->ShouldResponse(frameNode)) {
60         if (refereeState_ != RefereeState::FAIL) {
61             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
62         }
63         return false;
64     }
65     return true;
66 }
67 
OnRejectBridgeObj()68 void NGGestureRecognizer::OnRejectBridgeObj()
69 {
70     if (bridgeObjList_.empty()) {
71         return;
72     }
73     for (const auto& item : bridgeObjList_) {
74         auto bridgeObj = item.Upgrade();
75         if (bridgeObj) {
76             bridgeObj->OnRejected();
77             bridgeObj->OnRejectBridgeObj();
78         }
79     }
80 }
81 
HandleEvent(const TouchEvent & point)82 bool NGGestureRecognizer::HandleEvent(const TouchEvent& point)
83 {
84     if (!ShouldResponse()) {
85         return true;
86     }
87     if (bridgeMode_) {
88         return true;
89     }
90     switch (point.type) {
91         case TouchType::MOVE:
92             HandleTouchMoveEvent(point);
93             HandleEventToBridgeObjList(point, bridgeObjList_);
94             break;
95         case TouchType::DOWN: {
96             deviceId_ = point.deviceId;
97             deviceType_ = point.sourceType;
98             if (deviceType_ == SourceType::MOUSE) {
99                 inputEventType_ = InputEventType::MOUSE_BUTTON;
100             } else {
101                 inputEventType_ = InputEventType::TOUCH_SCREEN;
102             }
103             auto result = AboutToAddCurrentFingers(point);
104             if (result) {
105                 HandleTouchDownEvent(point);
106                 HandleEventToBridgeObjList(point, bridgeObjList_);
107             }
108             break;
109         }
110         case TouchType::UP: {
111             auto result = AboutToMinusCurrentFingers(point.id);
112             if (result) {
113                 HandleTouchUpEvent(point);
114                 HandleEventToBridgeObjList(point, bridgeObjList_);
115                 currentFingers_--;
116             }
117             break;
118         }
119         case TouchType::CANCEL: {
120             auto result = AboutToMinusCurrentFingers(point.id);
121             if (result) {
122                 HandleTouchCancelEvent(point);
123                 HandleEventToBridgeObjList(point, bridgeObjList_);
124                 currentFingers_--;
125             }
126             break;
127         }
128         default:
129             break;
130     }
131     return true;
132 }
133 
HandleEvent(const AxisEvent & event)134 bool NGGestureRecognizer::HandleEvent(const AxisEvent& event)
135 {
136     if (!ShouldResponse()) {
137         return true;
138     }
139     if (bridgeMode_) {
140         return true;
141     }
142     switch (event.action) {
143         case AxisAction::BEGIN:
144             deviceId_ = event.deviceId;
145             deviceType_ = event.sourceType;
146             inputEventType_ = InputEventType::AXIS;
147             HandleTouchDownEvent(event);
148             break;
149         case AxisAction::UPDATE:
150             HandleTouchMoveEvent(event);
151             break;
152         case AxisAction::END:
153             HandleTouchUpEvent(event);
154             break;
155         default:
156             HandleTouchCancelEvent(event);
157             break;
158     }
159     for (const auto& item : bridgeObjList_) {
160         auto bridgeObj = item.Upgrade();
161         if (bridgeObj) {
162             bridgeObj->HandleBridgeModeEvent(event);
163         }
164     }
165     return true;
166 }
167 
HandleBridgeModeEvent(const TouchEvent & point)168 void NGGestureRecognizer::HandleBridgeModeEvent(const TouchEvent& point)
169 {
170     switch (point.type) {
171         case TouchType::MOVE:
172             HandleTouchMoveEvent(point);
173             HandleEventToBridgeObjList(point, bridgeObjList_);
174             break;
175         case TouchType::DOWN: {
176             deviceId_ = point.deviceId;
177             deviceType_ = point.sourceType;
178             if (deviceType_ == SourceType::MOUSE) {
179                 inputEventType_ = InputEventType::MOUSE_BUTTON;
180             } else {
181                 inputEventType_ = InputEventType::TOUCH_SCREEN;
182             }
183             auto result = AboutToAddCurrentFingers(point);
184             if (result) {
185                 HandleTouchDownEvent(point);
186                 HandleEventToBridgeObjList(point, bridgeObjList_);
187             }
188             break;
189         }
190         case TouchType::UP: {
191             auto result = AboutToMinusCurrentFingers(point.id);
192             if (result) {
193                 HandleTouchUpEvent(point);
194                 currentFingers_--;
195                 HandleEventToBridgeObjList(point, bridgeObjList_);
196             }
197             break;
198         }
199         case TouchType::CANCEL: {
200             auto result = AboutToMinusCurrentFingers(point.id);
201             if (result) {
202                 HandleTouchCancelEvent(point);
203                 currentFingers_--;
204                 HandleEventToBridgeObjList(point, bridgeObjList_);
205             }
206             break;
207         }
208         default:
209             break;
210     }
211 }
212 
HandleEventToBridgeObjList(const TouchEvent & point,const std::list<WeakPtr<NGGestureRecognizer>> & bridgeObjList)213 void NGGestureRecognizer::HandleEventToBridgeObjList(
214     const TouchEvent& point, const std::list<WeakPtr<NGGestureRecognizer>>& bridgeObjList)
215 {
216     for (const auto& item : bridgeObjList) {
217         auto bridgeObj = item.Upgrade();
218         if (bridgeObj) {
219             bridgeObj->HandleBridgeModeEvent(point);
220         }
221     }
222 }
223 
HandleBridgeModeEvent(const AxisEvent & event)224 void NGGestureRecognizer::HandleBridgeModeEvent(const AxisEvent& event)
225 {
226     switch (event.action) {
227         case AxisAction::BEGIN:
228             deviceId_ = event.deviceId;
229             deviceType_ = event.sourceType;
230             inputEventType_ = InputEventType::AXIS;
231             HandleTouchDownEvent(event);
232             break;
233         case AxisAction::UPDATE:
234             HandleTouchMoveEvent(event);
235             break;
236         case AxisAction::END:
237             HandleTouchUpEvent(event);
238             break;
239         default:
240             HandleTouchCancelEvent(event);
241             break;
242     }
243     for (const auto& item : bridgeObjList_) {
244         auto bridgeObj = item.Upgrade();
245         if (bridgeObj) {
246             bridgeObj->HandleBridgeModeEvent(event);
247         }
248     }
249 }
250 
BatchAdjudicate(const RefPtr<NGGestureRecognizer> & recognizer,GestureDisposal disposal)251 void NGGestureRecognizer::BatchAdjudicate(const RefPtr<NGGestureRecognizer>& recognizer, GestureDisposal disposal)
252 {
253     RefPtr<NGGestureRecognizer> gestureGroup;
254     if (!eventImportGestureGroup_.Invalid()) {
255         gestureGroup = eventImportGestureGroup_.Upgrade();
256     } else {
257         gestureGroup = gestureGroup_.Upgrade();
258     }
259     if (gestureGroup) {
260         gestureGroup->Adjudicate(recognizer, disposal);
261         return;
262     }
263 
264     auto referee = GetCurrentGestureReferee(recognizer);
265     if (!referee) {
266         recognizer->OnRejected();
267         return;
268     }
269     referee->Adjudicate(recognizer, disposal);
270 }
271 
Transform(PointF & localPointF,const WeakPtr<FrameNode> & node,bool isRealTime,bool isPostEventResult,int32_t postEventNodeId)272 void NGGestureRecognizer::Transform(PointF& localPointF, const WeakPtr<FrameNode>& node, bool isRealTime,
273     bool isPostEventResult, int32_t postEventNodeId)
274 {
275     if (node.Invalid()) {
276         return;
277     }
278 
279     std::vector<Matrix4> vTrans {};
280     auto host = node.Upgrade();
281     CHECK_NULL_VOID(host);
282 
283     std::function<Matrix4()> getLocalMatrix;
284     if (isRealTime) {
285         getLocalMatrix = [&host]()->Matrix4 {
286             auto context = host->GetRenderContext();
287             CHECK_NULL_RETURN(context, Matrix4::CreateIdentity());
288             return context->GetLocalTransformMatrix();
289         };
290     } else {
291         getLocalMatrix = [&host]()->Matrix4 {
292             return host->GetLocalMatrix();
293         };
294     }
295 
296     while (host) {
297         auto localMat = getLocalMatrix();
298         vTrans.emplace_back(localMat);
299         if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
300             break;
301         }
302         if ((postEventNodeId == host->GetId()) && isPostEventResult) {
303             TAG_LOGD(AceLogTag::ACE_GESTURE, "need to break when used in NodeContainer, id:%{public}d", host->GetId());
304             break;
305         }
306         host = host->GetAncestorNodeOfFrame();
307     }
308 
309     Point temp(localPointF.GetX(), localPointF.GetY());
310     for (auto iter = vTrans.rbegin(); iter != vTrans.rend(); iter++) {
311         temp = *iter * temp;
312     }
313     localPointF.SetX(temp.GetX());
314     localPointF.SetY(temp.GetY());
315 }
316 
SetTransInfo(int transId)317 void NGGestureRecognizer::SetTransInfo(int transId)
318 {
319     transId_ = transId;
320 }
321 
AboutToAccept()322 void NGGestureRecognizer::AboutToAccept()
323 {
324     if (AceType::InstanceOf<RecognizerGroup>(this)) {
325         HandleWillAccept();
326         OnAccepted();
327         HandleDidAccept();
328         return;
329     }
330 
331     auto eventManager = GetCurrentEventManager();
332     CHECK_NULL_VOID(eventManager);
333     auto frameNode = GetAttachedNode();
334     auto ctrl = eventManager->GetResponseCtrl();
335     CHECK_NULL_VOID(ctrl);
336     if (!ctrl->ShouldResponse(frameNode)) {
337         return;
338     }
339     if (fromCardOrUIExtension_) {
340         eventManager->SetInnerFlag(true);
341     } else {
342         eventManager->SetInnerFlag(false);
343     }
344     ctrl->TrySetFirstResponse(frameNode);
345     HandleWillAccept();
346     OnAccepted();
347     HandleDidAccept();
348 }
349 
HandleWillAccept()350 void NGGestureRecognizer::HandleWillAccept()
351 {
352     auto node = GetAttachedNode().Upgrade();
353     if (AceType::InstanceOf<ClickRecognizer>(this)) {
354         auto clickRecognizer = AceType::DynamicCast<ClickRecognizer>(this);
355         CHECK_NULL_VOID(clickRecognizer);
356         GestureEvent gestureEventInfo = clickRecognizer->GetGestureEventInfo();
357         ClickInfo clickInfo = clickRecognizer->GetClickInfo();
358         UIObserverHandler::GetInstance().NotifyWillClick(gestureEventInfo, clickInfo, node);
359     }
360 }
361 
HandleDidAccept()362 void NGGestureRecognizer::HandleDidAccept()
363 {
364     auto node = GetAttachedNode().Upgrade();
365     if (AceType::InstanceOf<ClickRecognizer>(this)) {
366         auto clickRecognizer = AceType::DynamicCast<ClickRecognizer>(this);
367         CHECK_NULL_VOID(clickRecognizer);
368         GestureEvent gestureEventInfo = clickRecognizer->GetGestureEventInfo();
369         ClickInfo clickInfo = clickRecognizer->GetClickInfo();
370         UIObserverHandler::GetInstance().NotifyDidClick(gestureEventInfo, clickInfo, node);
371     }
372 }
373 
Dump() const374 RefPtr<GestureSnapshot> NGGestureRecognizer::Dump() const
375 {
376     RefPtr<GestureSnapshot> info = TouchEventTarget::Dump();
377     auto group = gestureGroup_.Upgrade();
378     if (group) {
379         info->parentId = reinterpret_cast<uintptr_t>(AceType::RawPtr(group));
380     }
381     return info;
382 }
383 
AddGestureProcedure(const std::string & procedure) const384 void NGGestureRecognizer::AddGestureProcedure(const std::string& procedure) const
385 {
386     auto context = PipelineContext::GetCurrentContext();
387     CHECK_NULL_VOID(context);
388     auto eventMgr = context->GetEventManager();
389     CHECK_NULL_VOID(eventMgr);
390     eventMgr->GetEventTreeRecord(isPostEventResult_ ? EventTreeType::POST_EVENT : EventTreeType::TOUCH)
391         .AddGestureProcedure(reinterpret_cast<uintptr_t>(this), procedure, TransRefereeState(this->GetRefereeState()),
392             TransGestureDisposal(this->GetGestureDisposal()));
393 }
394 
AddGestureProcedure(const TouchEvent & point,const RefPtr<NGGestureRecognizer> & recognizer) const395 void NGGestureRecognizer::AddGestureProcedure(const TouchEvent& point,
396     const RefPtr<NGGestureRecognizer>& recognizer) const
397 {
398     if (!recognizer) {
399         return;
400     }
401     auto context = PipelineContext::GetCurrentContext();
402     CHECK_NULL_VOID(context);
403     auto eventMgr = context->GetEventManager();
404     CHECK_NULL_VOID(eventMgr);
405     eventMgr->GetEventTreeRecord(isPostEventResult_ ? EventTreeType::POST_EVENT : EventTreeType::TOUCH)
406         .AddGestureProcedure(reinterpret_cast<uintptr_t>(AceType::RawPtr(recognizer)), point,
407             TransRefereeState(recognizer->GetRefereeState()), TransGestureDisposal(recognizer->GetGestureDisposal()));
408 }
409 
SetGestureGroup(const WeakPtr<NGGestureRecognizer> & gestureGroup)410 bool NGGestureRecognizer::SetGestureGroup(const WeakPtr<NGGestureRecognizer>& gestureGroup)
411 {
412     if (!gestureGroup_.Invalid() && !gestureGroup.Invalid()) {
413         return false;
414     }
415 
416     gestureGroup_ = gestureGroup;
417     return true;
418 }
419 
SetEventImportGestureGroup(const WeakPtr<NGGestureRecognizer> & gestureGroup)420 void NGGestureRecognizer::SetEventImportGestureGroup(const WeakPtr<NGGestureRecognizer>& gestureGroup)
421 {
422     if (gestureGroup.Invalid()) {
423         return;
424     }
425 
426     eventImportGestureGroup_ = gestureGroup;
427 }
428 
IsInAttachedNode(const TouchEvent & event,bool isRealTime)429 bool NGGestureRecognizer::IsInAttachedNode(const TouchEvent& event, bool isRealTime)
430 {
431     bool isChildTouchTestResult = false;
432     auto frameNode = GetAttachedNode();
433     if (frameNode.Invalid()) {
434         return true;
435     }
436     auto host = frameNode.Upgrade();
437     CHECK_NULL_RETURN(host, true);
438     auto id = host->GetInspectorIdValue("");
439     isChildTouchTestResult = std::any_of(event.childTouchTestList.begin(), event.childTouchTestList.end(),
440         [id](const std::string& inspectorId) {
441             return inspectorId == id;
442         });
443     if (isChildTouchTestResult) {
444         return true;
445     }
446 
447     PointF localPoint(event.x, event.y);
448     if (isRealTime) {
449         NGGestureRecognizer::Transform(localPoint, frameNode, !isPostEventResult_,
450             isPostEventResult_, event.postEventNodeId);
451     } else {
452         NGGestureRecognizer::Transform(localPoint, frameNode, false,
453             isPostEventResult_, event.postEventNodeId);
454     }
455     auto renderContext = host->GetRenderContext();
456     CHECK_NULL_RETURN(renderContext, false);
457     auto paintRect = renderContext->GetPaintRectWithoutTransform();
458     localPoint = localPoint + paintRect.GetOffset();
459     auto responseRegion = host->GetResponseRegionListForRecognizer(static_cast<int32_t>(event.sourceType));
460     auto result = host->InResponseRegionList(localPoint, responseRegion);
461     if (!result) {
462         std::string responseInfo = std::string("responseRegionList = ");
463         for (const auto& item : responseRegion) {
464             responseInfo.append(item.ToString()).append("; ");
465         }
466         TAG_LOGI(AceLogTag::ACE_GESTURE,
467             "%{public}s IsInAttachedNode result is negative, node tag = %{public}s, id = %{public}s, point = "
468             "%{public}s, frameRect = %{public}s, %{public}s",
469             AceType::TypeName(this), host->GetTag().c_str(), std::to_string(host->GetId()).c_str(),
470             localPoint.ToString().c_str(), host->GetFrameRectWithoutSafeArea().ToString().c_str(),
471             responseInfo.c_str());
472     }
473     return result;
474 }
475 
SetResponseLinkRecognizers(const ResponseLinkResult & responseLinkResult)476 void NGGestureRecognizer::SetResponseLinkRecognizers(const ResponseLinkResult& responseLinkResult)
477 {
478     responseLinkRecognizer_ = responseLinkResult;
479 }
480 
IsInResponseLinkRecognizers()481 bool NGGestureRecognizer::IsInResponseLinkRecognizers()
482 {
483     return std::any_of(responseLinkRecognizer_.begin(), responseLinkRecognizer_.end(),
484         [recognizer = Claim(this)](const RefPtr<NGGestureRecognizer>& item) { return item == recognizer; });
485 }
486 
AboutToAddCurrentFingers(const TouchEvent & event)487 bool NGGestureRecognizer::AboutToAddCurrentFingers(const TouchEvent& event)
488 {
489     bool isInAttachedNode = IsInAttachedNode(event, !AceType::InstanceOf<ClickRecognizer>(this));
490     if (!isInAttachedNode) {
491         return false;
492     }
493     if (fingersId_.find(event.id) != fingersId_.end()) {
494         auto node = GetAttachedNode().Upgrade();
495         TAG_LOGI(AceLogTag::ACE_GESTURE,
496             "Recognizer has already receive touchId: %{public}d event, node tag = %{public}s, id = %{public}s",
497             event.id, node ? node->GetTag().c_str() : "null",
498             node ? std::to_string(node->GetId()).c_str() : "invalid");
499         return false;
500     }
501     currentFingers_++;
502     return true;
503 }
504 
AboutToMinusCurrentFingers(int32_t touchId)505 bool NGGestureRecognizer::AboutToMinusCurrentFingers(int32_t touchId)
506 {
507     if (fingersId_.find(touchId) != fingersId_.end()) {
508         return true;
509     }
510     auto node = GetAttachedNode().Upgrade();
511     TAG_LOGI(AceLogTag::ACE_GESTURE,
512         "Recognizer has already receive touchId: %{public}d up event, node tag = %{public}s, id = %{public}s",
513         touchId, node ? node->GetTag().c_str() : "null",
514         node ? std::to_string(node->GetId()).c_str() : "invalid");
515     return false;
516 }
517 } // namespace OHOS::Ace::NG
518