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 
IsAllowedType(SourceTool type)68 bool NGGestureRecognizer::IsAllowedType(SourceTool type)
69 {
70     // allow all types by default
71     if (!gestureInfo_) {
72         return true;
73     }
74 
75     auto allowedTypes = gestureInfo_->GetAllowedTypes();
76     return allowedTypes.empty() || allowedTypes.find(type) != allowedTypes.end();
77 }
78 
OnRejectBridgeObj()79 void NGGestureRecognizer::OnRejectBridgeObj()
80 {
81     if (bridgeObjList_.empty()) {
82         return;
83     }
84     for (const auto& item : bridgeObjList_) {
85         auto bridgeObj = item.Upgrade();
86         if (bridgeObj) {
87             bridgeObj->OnRejected();
88             bridgeObj->OnRejectBridgeObj();
89         }
90     }
91 }
92 
HandleEvent(const TouchEvent & point)93 bool NGGestureRecognizer::HandleEvent(const TouchEvent& point)
94 {
95     if (!IsAllowedType(point.sourceTool) && point.type != TouchType::CANCEL) {
96         if (point.type == TouchType::DOWN) {
97             RemoveUnsupportEvent(point.id);
98         }
99         return true;
100     }
101     if (!ShouldResponse() || bridgeMode_) {
102         return true;
103     }
104     auto multiFingerRecognizer = AceType::DynamicCast<MultiFingersRecognizer>(Claim(this));
105     if (multiFingerRecognizer) {
106         multiFingerRecognizer->ResetTouchPointsForSucceedBlock();
107     }
108     return ProcessTouchEvent(point);
109 }
110 
ProcessTouchEvent(const TouchEvent & point)111 bool NGGestureRecognizer::ProcessTouchEvent(const TouchEvent& point)
112 {
113     switch (point.type) {
114         case TouchType::MOVE:
115             HandleTouchMoveEvent(point);
116             HandleEventToBridgeObjList(point, bridgeObjList_);
117             break;
118         case TouchType::DOWN:
119             HandleTouchDown(point);
120             break;
121         case TouchType::UP:
122             HandleTouchUp(point);
123             break;
124         case TouchType::CANCEL:
125             HandleTouchCancel(point);
126             break;
127         default:
128             break;
129     }
130     return true;
131 }
132 
HandleTouchDown(const TouchEvent & point)133 void NGGestureRecognizer::HandleTouchDown(const TouchEvent& point)
134 {
135     deviceId_ = point.deviceId;
136     deviceType_ = point.sourceType;
137     inputEventType_ = (deviceType_ == SourceType::MOUSE) ? InputEventType::MOUSE_BUTTON : InputEventType::TOUCH_SCREEN;
138 
139     auto result = AboutToAddCurrentFingers(point);
140     if (result) {
141         HandleTouchDownEvent(point);
142         HandleEventToBridgeObjList(point, bridgeObjList_);
143     }
144 }
145 
HandleTouchUp(const TouchEvent & point)146 void NGGestureRecognizer::HandleTouchUp(const TouchEvent& point)
147 {
148     auto result = AboutToMinusCurrentFingers(point.id);
149     if (result) {
150         HandleTouchUpEvent(point);
151         HandleEventToBridgeObjList(point, bridgeObjList_);
152         currentFingers_--;
153     }
154 }
155 
HandleTouchCancel(const TouchEvent & point)156 void NGGestureRecognizer::HandleTouchCancel(const TouchEvent& point)
157 {
158     auto result = AboutToMinusCurrentFingers(point.id);
159     if (result) {
160         HandleTouchCancelEvent(point);
161         HandleEventToBridgeObjList(point, bridgeObjList_);
162         currentFingers_--;
163     }
164 }
165 
HandleEvent(const AxisEvent & event)166 bool NGGestureRecognizer::HandleEvent(const AxisEvent& event)
167 {
168     if (!IsAllowedType(event.sourceTool) && event.action != AxisAction::CANCEL) {
169         if (event.action == AxisAction::BEGIN) {
170             RemoveUnsupportEvent(event.id);
171         }
172         return true;
173     }
174     if (!ShouldResponse() || bridgeMode_) {
175         return true;
176     }
177     switch (event.action) {
178         case AxisAction::BEGIN:
179             deviceId_ = event.deviceId;
180             deviceType_ = event.sourceType;
181             inputEventType_ = InputEventType::AXIS;
182             HandleTouchDownEvent(event);
183             break;
184         case AxisAction::UPDATE:
185             HandleTouchMoveEvent(event);
186             break;
187         case AxisAction::END:
188             HandleTouchUpEvent(event);
189             break;
190         default:
191             HandleTouchCancelEvent(event);
192             break;
193     }
194     for (const auto& item : bridgeObjList_) {
195         auto bridgeObj = item.Upgrade();
196         if (bridgeObj) {
197             bridgeObj->HandleBridgeModeEvent(event);
198         }
199     }
200     return true;
201 }
202 
HandleBridgeModeEvent(const TouchEvent & point)203 void NGGestureRecognizer::HandleBridgeModeEvent(const TouchEvent& point)
204 {
205     switch (point.type) {
206         case TouchType::MOVE:
207             HandleTouchMoveEvent(point);
208             HandleEventToBridgeObjList(point, bridgeObjList_);
209             break;
210         case TouchType::DOWN: {
211             deviceId_ = point.deviceId;
212             deviceType_ = point.sourceType;
213             if (deviceType_ == SourceType::MOUSE) {
214                 inputEventType_ = InputEventType::MOUSE_BUTTON;
215             } else {
216                 inputEventType_ = InputEventType::TOUCH_SCREEN;
217             }
218             auto result = AboutToAddCurrentFingers(point);
219             if (result) {
220                 HandleTouchDownEvent(point);
221                 HandleEventToBridgeObjList(point, bridgeObjList_);
222             }
223             break;
224         }
225         case TouchType::UP: {
226             auto result = AboutToMinusCurrentFingers(point.id);
227             if (result) {
228                 HandleTouchUpEvent(point);
229                 currentFingers_--;
230                 HandleEventToBridgeObjList(point, bridgeObjList_);
231             }
232             break;
233         }
234         case TouchType::CANCEL: {
235             auto result = AboutToMinusCurrentFingers(point.id);
236             if (result) {
237                 HandleTouchCancelEvent(point);
238                 currentFingers_--;
239                 HandleEventToBridgeObjList(point, bridgeObjList_);
240             }
241             break;
242         }
243         default:
244             break;
245     }
246 }
247 
HandleEventToBridgeObjList(const TouchEvent & point,const std::list<WeakPtr<NGGestureRecognizer>> & bridgeObjList)248 void NGGestureRecognizer::HandleEventToBridgeObjList(
249     const TouchEvent& point, const std::list<WeakPtr<NGGestureRecognizer>>& bridgeObjList)
250 {
251     for (const auto& item : bridgeObjList) {
252         auto bridgeObj = item.Upgrade();
253         if (bridgeObj) {
254             bridgeObj->HandleBridgeModeEvent(point);
255         }
256     }
257 }
258 
HandleBridgeModeEvent(const AxisEvent & event)259 void NGGestureRecognizer::HandleBridgeModeEvent(const AxisEvent& event)
260 {
261     switch (event.action) {
262         case AxisAction::BEGIN:
263             deviceId_ = event.deviceId;
264             deviceType_ = event.sourceType;
265             inputEventType_ = InputEventType::AXIS;
266             HandleTouchDownEvent(event);
267             break;
268         case AxisAction::UPDATE:
269             HandleTouchMoveEvent(event);
270             break;
271         case AxisAction::END:
272             HandleTouchUpEvent(event);
273             break;
274         default:
275             HandleTouchCancelEvent(event);
276             break;
277     }
278     for (const auto& item : bridgeObjList_) {
279         auto bridgeObj = item.Upgrade();
280         if (bridgeObj) {
281             bridgeObj->HandleBridgeModeEvent(event);
282         }
283     }
284 }
285 
BatchAdjudicate(const RefPtr<NGGestureRecognizer> & recognizer,GestureDisposal disposal)286 void NGGestureRecognizer::BatchAdjudicate(const RefPtr<NGGestureRecognizer>& recognizer, GestureDisposal disposal)
287 {
288     RefPtr<NGGestureRecognizer> gestureGroup;
289     if (!eventImportGestureGroup_.Invalid()) {
290         gestureGroup = eventImportGestureGroup_.Upgrade();
291     } else {
292         gestureGroup = gestureGroup_.Upgrade();
293     }
294     if (gestureGroup) {
295         gestureGroup->Adjudicate(recognizer, disposal);
296         return;
297     }
298 
299     auto referee = GetCurrentGestureReferee(recognizer);
300     if (!referee) {
301         recognizer->OnRejected();
302         return;
303     }
304     referee->Adjudicate(recognizer, disposal);
305 }
306 
Transform(PointF & localPointF,const WeakPtr<FrameNode> & node,bool isRealTime,bool isPostEventResult,int32_t postEventNodeId)307 void NGGestureRecognizer::Transform(PointF& localPointF, const WeakPtr<FrameNode>& node, bool isRealTime,
308     bool isPostEventResult, int32_t postEventNodeId)
309 {
310     if (node.Invalid()) {
311         return;
312     }
313 
314     std::vector<Matrix4> vTrans {};
315     auto host = node.Upgrade();
316     CHECK_NULL_VOID(host);
317 
318     std::function<Matrix4()> getLocalMatrix;
319     if (isRealTime) {
320         getLocalMatrix = [&host]()->Matrix4 {
321             auto context = host->GetRenderContext();
322             CHECK_NULL_RETURN(context, Matrix4::CreateIdentity());
323             return context->GetLocalTransformMatrix();
324         };
325     } else {
326         getLocalMatrix = [&host]()->Matrix4 {
327             return host->GetLocalMatrix();
328         };
329     }
330 
331     while (host) {
332         auto localMat = getLocalMatrix();
333         vTrans.emplace_back(localMat);
334         if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
335             TAG_LOGD(AceLogTag::ACE_GESTURE, "need to break when inject WindowsScene, id:"
336                 SEC_PLD(%{public}d) ".", SEC_PARAM(host->GetId()));
337             break;
338         }
339         if ((postEventNodeId == host->GetId()) && isPostEventResult) {
340             TAG_LOGD(AceLogTag::ACE_GESTURE, "need to break when used in NodeContainer, id:"
341                 SEC_PLD(%{public}d) ".", SEC_PARAM(host->GetId()));
342             break;
343         }
344         host = host->GetAncestorNodeOfFrame();
345     }
346 
347     Point temp(localPointF.GetX(), localPointF.GetY());
348     for (auto iter = vTrans.rbegin(); iter != vTrans.rend(); iter++) {
349         temp = *iter * temp;
350     }
351     localPointF.SetX(temp.GetX());
352     localPointF.SetY(temp.GetY());
353 }
354 
SetTransInfo(int transId)355 void NGGestureRecognizer::SetTransInfo(int transId)
356 {
357     transId_ = transId;
358 }
359 
AboutToAccept()360 void NGGestureRecognizer::AboutToAccept()
361 {
362     if (AceType::InstanceOf<RecognizerGroup>(this)) {
363         HandleWillAccept();
364         OnAccepted();
365         HandleDidAccept();
366         return;
367     }
368 
369     auto eventManager = GetCurrentEventManager();
370     CHECK_NULL_VOID(eventManager);
371     auto frameNode = GetAttachedNode();
372     auto ctrl = eventManager->GetResponseCtrl();
373     CHECK_NULL_VOID(ctrl);
374     if (!ctrl->ShouldResponse(frameNode)) {
375         return;
376     }
377     if (fromCardOrUIExtension_) {
378         eventManager->SetInnerFlag(true);
379     } else {
380         eventManager->SetInnerFlag(false);
381     }
382     ctrl->TrySetFirstResponse(frameNode);
383     HandleWillAccept();
384     OnAccepted();
385     HandleDidAccept();
386 }
387 
HandleWillAccept()388 void NGGestureRecognizer::HandleWillAccept()
389 {
390     auto node = GetAttachedNode().Upgrade();
391     if (AceType::InstanceOf<ClickRecognizer>(this)) {
392         auto clickRecognizer = AceType::DynamicCast<ClickRecognizer>(this);
393         CHECK_NULL_VOID(clickRecognizer);
394         GestureEvent gestureEventInfo = clickRecognizer->GetGestureEventInfo();
395         ClickInfo clickInfo = clickRecognizer->GetClickInfo();
396         UIObserverHandler::GetInstance().NotifyWillClick(gestureEventInfo, clickInfo, node);
397     }
398 }
399 
HandleDidAccept()400 void NGGestureRecognizer::HandleDidAccept()
401 {
402     auto node = GetAttachedNode().Upgrade();
403     if (AceType::InstanceOf<ClickRecognizer>(this)) {
404         auto clickRecognizer = AceType::DynamicCast<ClickRecognizer>(this);
405         CHECK_NULL_VOID(clickRecognizer);
406         GestureEvent gestureEventInfo = clickRecognizer->GetGestureEventInfo();
407         ClickInfo clickInfo = clickRecognizer->GetClickInfo();
408         UIObserverHandler::GetInstance().NotifyDidClick(gestureEventInfo, clickInfo, node);
409     }
410 }
411 
ReconcileGestureInfoFrom(const RefPtr<NGGestureRecognizer> & recognizer)412 void NGGestureRecognizer::ReconcileGestureInfoFrom(const RefPtr<NGGestureRecognizer>& recognizer)
413 {
414     CHECK_NULL_VOID(recognizer);
415     auto currGestureInfo = recognizer->GetGestureInfo();
416     if (gestureInfo_ && currGestureInfo) {
417         gestureInfo_->SetAllowedTypes(currGestureInfo->GetAllowedTypes());
418     }
419 }
420 
Dump() const421 RefPtr<GestureSnapshot> NGGestureRecognizer::Dump() const
422 {
423     RefPtr<GestureSnapshot> info = TouchEventTarget::Dump();
424     auto group = gestureGroup_.Upgrade();
425     if (group) {
426         info->parentId = reinterpret_cast<uintptr_t>(AceType::RawPtr(group));
427     }
428     return info;
429 }
430 
AddGestureProcedure(const std::string & procedure) const431 void NGGestureRecognizer::AddGestureProcedure(const std::string& procedure) const
432 {
433     auto context = PipelineContext::GetCurrentContext();
434     CHECK_NULL_VOID(context);
435     auto eventMgr = context->GetEventManager();
436     CHECK_NULL_VOID(eventMgr);
437     eventMgr->GetEventTreeRecord(isPostEventResult_ ? EventTreeType::POST_EVENT : EventTreeType::TOUCH)
438         .AddGestureProcedure(reinterpret_cast<uintptr_t>(this), procedure,
439         extraInfo_, TransRefereeState(this->GetRefereeState()),
440         TransGestureDisposal(this->GetGestureDisposal()));
441 }
442 
AddGestureProcedure(const TouchEvent & point,const RefPtr<NGGestureRecognizer> & recognizer) const443 void NGGestureRecognizer::AddGestureProcedure(const TouchEvent& point,
444     const RefPtr<NGGestureRecognizer>& recognizer) const
445 {
446     if (!recognizer) {
447         return;
448     }
449     auto context = PipelineContext::GetCurrentContext();
450     CHECK_NULL_VOID(context);
451     auto eventMgr = context->GetEventManager();
452     CHECK_NULL_VOID(eventMgr);
453     eventMgr->GetEventTreeRecord(isPostEventResult_ ? EventTreeType::POST_EVENT : EventTreeType::TOUCH)
454         .AddGestureProcedure(reinterpret_cast<uintptr_t>(AceType::RawPtr(recognizer)),
455         point, recognizer->GetExtraInfo(), TransRefereeState(recognizer->GetRefereeState()),
456         TransGestureDisposal(recognizer->GetGestureDisposal()));
457 }
458 
SetGestureGroup(const WeakPtr<NGGestureRecognizer> & gestureGroup)459 bool NGGestureRecognizer::SetGestureGroup(const WeakPtr<NGGestureRecognizer>& gestureGroup)
460 {
461     if (!gestureGroup_.Invalid() && !gestureGroup.Invalid()) {
462         return false;
463     }
464 
465     gestureGroup_ = gestureGroup;
466     return true;
467 }
468 
SetEventImportGestureGroup(const WeakPtr<NGGestureRecognizer> & gestureGroup)469 void NGGestureRecognizer::SetEventImportGestureGroup(const WeakPtr<NGGestureRecognizer>& gestureGroup)
470 {
471     if (gestureGroup.Invalid()) {
472         return;
473     }
474 
475     eventImportGestureGroup_ = gestureGroup;
476 }
477 
IsInAttachedNode(const TouchEvent & event,bool isRealTime)478 bool NGGestureRecognizer::IsInAttachedNode(const TouchEvent& event, bool isRealTime)
479 {
480     bool isChildTouchTestResult = false;
481     auto frameNode = GetAttachedNode();
482     if (frameNode.Invalid()) {
483         return true;
484     }
485     auto host = frameNode.Upgrade();
486     CHECK_NULL_RETURN(host, true);
487     auto id = host->GetInspectorIdValue("");
488     isChildTouchTestResult = std::any_of(event.childTouchTestList.begin(), event.childTouchTestList.end(),
489         [id](const std::string& inspectorId) {
490             return inspectorId == id;
491         });
492     if (isChildTouchTestResult) {
493         return true;
494     }
495 
496     PointF localPoint(event.x, event.y);
497     if (isRealTime) {
498         NGGestureRecognizer::Transform(localPoint, frameNode, !isPostEventResult_,
499             isPostEventResult_, event.postEventNodeId);
500     } else {
501         NGGestureRecognizer::Transform(localPoint, frameNode, false,
502             isPostEventResult_, event.postEventNodeId);
503     }
504     auto renderContext = host->GetRenderContext();
505     CHECK_NULL_RETURN(renderContext, false);
506     auto paintRect = renderContext->GetPaintRectWithoutTransform();
507     localPoint = localPoint + paintRect.GetOffset();
508     auto responseRegion = host->GetResponseRegionListForRecognizer(static_cast<int32_t>(event.sourceType));
509     auto result = host->InResponseRegionList(localPoint, responseRegion);
510     if (!result) {
511         std::string responseInfo = std::string("responseRegionList = ");
512         for (const auto& item : responseRegion) {
513             responseInfo.append(item.ToString()).append("; ");
514         }
515         TAG_LOGW(AceLogTag::ACE_GESTURE, SEC_PLD(,
516             "%{public}s IsInAttachedNode result is negative, node tag = %{public}s, id = %{public}s, point = "
517             "%{public}s, frameRect = %{public}s, %{public}s"),
518             SEC_PARAM(AceType::TypeName(this), host->GetTag().c_str(), std::to_string(host->GetId()).c_str(),
519             localPoint.ToString().c_str(), host->GetFrameRectWithoutSafeArea().ToString().c_str(),
520             responseInfo.c_str()));
521     }
522     return result;
523 }
524 
SetResponseLinkRecognizers(const ResponseLinkResult & responseLinkResult)525 void NGGestureRecognizer::SetResponseLinkRecognizers(const ResponseLinkResult& responseLinkResult)
526 {
527     responseLinkRecognizer_ = responseLinkResult;
528 }
529 
IsInResponseLinkRecognizers()530 bool NGGestureRecognizer::IsInResponseLinkRecognizers()
531 {
532     return std::any_of(responseLinkRecognizer_.begin(), responseLinkRecognizer_.end(),
533         [recognizer = Claim(this)](const RefPtr<NGGestureRecognizer>& item) { return item == recognizer; });
534 }
535 
AboutToAddCurrentFingers(const TouchEvent & event)536 bool NGGestureRecognizer::AboutToAddCurrentFingers(const TouchEvent& event)
537 {
538     bool isInAttachedNode = IsInAttachedNode(event, !AceType::InstanceOf<ClickRecognizer>(this));
539     if (!isInAttachedNode) {
540         return false;
541     }
542     if (fingersId_.find(event.id) != fingersId_.end()) {
543         auto node = GetAttachedNode().Upgrade();
544         TAG_LOGI(AceLogTag::ACE_GESTURE,
545             "Recognizer has already receive touchId: %{public}d event, "
546             "node tag = %{public}s, id = " SEC_PLD(%{public}s) ".",
547             event.id, node ? node->GetTag().c_str() : "null",
548             SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
549         return false;
550     }
551     currentFingers_++;
552     return true;
553 }
554 
AboutToMinusCurrentFingers(int32_t touchId)555 bool NGGestureRecognizer::AboutToMinusCurrentFingers(int32_t touchId)
556 {
557     if (fingersId_.find(touchId) != fingersId_.end()) {
558         return true;
559     }
560     auto node = GetAttachedNode().Upgrade();
561     TAG_LOGI(AceLogTag::ACE_GESTURE,
562         "Recognizer has already receive touchId: %{public}d up event, "
563         "node tag = %{public}s, id = " SEC_PLD(%{public}s) ".",
564         touchId, node ? node->GetTag().c_str() : "null",
565         SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
566     return false;
567 }
568 } // namespace OHOS::Ace::NG
569