1 /*
2  * Copyright (c) 2021-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/gestures/recognizers/click_recognizer.h"
17 
18 #include "base/geometry/offset.h"
19 #include "base/log/log.h"
20 #include "base/ressched/ressched_report.h"
21 #include "base/utils/utils.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components_ng/gestures/base_gesture_event.h"
24 #include "core/components_ng/gestures/gesture_referee.h"
25 #include "core/components_ng/gestures/recognizers/gesture_recognizer.h"
26 #include "core/components_ng/gestures/recognizers/multi_fingers_recognizer.h"
27 #include "core/pipeline_ng/pipeline_context.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 
32 int32_t MULTI_FINGER_TIMEOUT = 300;
33 constexpr int32_t MULTI_FINGER_TIMEOUT_TOUCH = 300;
34 constexpr int32_t MULTI_FINGER_TIMEOUT_MOUSE = 300;
35 int32_t MULTI_TAP_TIMEOUT = 300;
36 constexpr int32_t MULTI_TAP_TIMEOUT_TOUCH = 300;
37 constexpr int32_t MULTI_TAP_TIMEOUT_MOUSE = 300;
38 constexpr int32_t MAX_THRESHOLD_MANYTAP = 60;
39 constexpr int32_t MAX_TAP_FINGERS = 10;
40 constexpr double MAX_THRESHOLD = 20.0;
41 constexpr int32_t DEFAULT_TAP_FINGERS = 1;
42 constexpr int32_t DEFAULT_LONGPRESS_DURATION = 800000000;
43 
44 } // namespace
45 
ForceCleanRecognizer()46 void ClickRecognizer::ForceCleanRecognizer()
47 {
48     MultiFingersRecognizer::ForceCleanRecognizer();
49     OnResetStatus();
50 }
51 
IsPointInRegion(const TouchEvent & event)52 bool ClickRecognizer::IsPointInRegion(const TouchEvent& event)
53 {
54     if (distanceThreshold_ < std::numeric_limits<double>::infinity()) {
55         Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
56         if (offset.GetDistance() > distanceThreshold_) {
57             TAG_LOGI(AceLogTag::ACE_GESTURE, "Click move distance is larger than distanceThreshold_, "
58             "distanceThreshold_ is %{public}f", distanceThreshold_);
59             extraInfo_ += "move distance out of distanceThreshold.";
60             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
61             return false;
62         } else {
63             return true;
64         }
65     }
66     PointF localPoint(event.x, event.y);
67     auto frameNode = GetAttachedNode();
68     if (!frameNode.Invalid()) {
69         auto host = frameNode.Upgrade();
70         CHECK_NULL_RETURN(host, false);
71         NGGestureRecognizer::Transform(localPoint, frameNode, false, isPostEventResult_, event.postEventNodeId);
72         auto renderContext = host->GetRenderContext();
73         CHECK_NULL_RETURN(renderContext, false);
74         auto paintRect = renderContext->GetPaintRectWithoutTransform();
75         localPoint = localPoint + paintRect.GetOffset();
76         if (!host->InResponseRegionList(localPoint, responseRegionBuffer_)) {
77             TAG_LOGI(AceLogTag::ACE_GESTURE,
78                 "InputTracking id:%{public}d, this MOVE/UP event is out of region, try to reject click gesture",
79                 event.touchEventId);
80             extraInfo_ += "move/up event out of region.";
81             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
82             return false;
83         }
84     }
85     return true;
86 }
87 
ClickRecognizer(int32_t fingers,int32_t count,double distanceThreshold)88 ClickRecognizer::ClickRecognizer(int32_t fingers, int32_t count, double distanceThreshold)
89     : MultiFingersRecognizer(fingers), count_(count), distanceThreshold_(distanceThreshold)
90 {
91     if (fingers_ > MAX_TAP_FINGERS || fingers_ < DEFAULT_TAP_FINGERS) {
92         fingers_ = DEFAULT_TAP_FINGERS;
93     }
94     if (distanceThreshold_ <= 0) {
95         distanceThreshold_ = std::numeric_limits<double>::infinity();
96     }
97 }
98 
InitGlobalValue(SourceType sourceType)99 void ClickRecognizer::InitGlobalValue(SourceType sourceType)
100 {
101     switch (sourceType) {
102         case SourceType::TOUCH:
103             MULTI_FINGER_TIMEOUT = MULTI_FINGER_TIMEOUT_TOUCH;
104             MULTI_TAP_TIMEOUT = MULTI_TAP_TIMEOUT_TOUCH;
105             break;
106         case SourceType::MOUSE:
107         case SourceType::TOUCH_PAD:
108             MULTI_FINGER_TIMEOUT = MULTI_FINGER_TIMEOUT_MOUSE;
109             MULTI_TAP_TIMEOUT = MULTI_TAP_TIMEOUT_MOUSE;
110             break;
111         default:
112             break;
113     }
114 }
115 
GetClickInfo()116 ClickInfo ClickRecognizer::GetClickInfo()
117 {
118     TouchEvent touchPoint = {};
119     if (!touchPoints_.empty()) {
120         touchPoint = touchPoints_.begin()->second;
121     }
122     ClickInfo info(touchPoint.id);
123     PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
124     NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
125         isPostEventResult_, touchPoint.postEventNodeId);
126     Offset localOffset(localPoint.GetX(), localPoint.GetY());
127     info.SetTimeStamp(touchPoint.time);
128     info.SetScreenLocation(touchPoint.GetScreenOffset());
129     info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(localOffset);
130     info.SetSourceDevice(deviceType_);
131     info.SetDeviceId(deviceId_);
132     info.SetTarget(GetEventTarget().value_or(EventTarget()));
133     info.SetForce(touchPoint.force);
134     auto frameNode = GetAttachedNode().Upgrade();
135     std::string patternName = "";
136     if (frameNode) {
137         patternName = frameNode->GetTag();
138     }
139     info.SetPatternName(patternName.c_str());
140     if (touchPoint.tiltX.has_value()) {
141         info.SetTiltX(touchPoint.tiltX.value());
142     }
143     if (touchPoint.tiltY.has_value()) {
144         info.SetTiltY(touchPoint.tiltY.value());
145     }
146     info.SetSourceTool(touchPoint.sourceTool);
147     return info;
148 }
149 
OnAccepted()150 void ClickRecognizer::OnAccepted()
151 {
152     int64_t acceptTime = GetSysTimestamp();
153     int64_t inputTime = acceptTime;
154     if (firstInputTime_.has_value()) {
155         inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
156     }
157     if (SystemProperties::GetTraceInputEventEnabled()) {
158         ACE_SCOPED_TRACE("UserEvent InputTime:%lld AcceptTime:%lld InputType:ClickGesture",
159             static_cast<long long>(inputTime), static_cast<long long>(acceptTime));
160     }
161     firstInputTime_.reset();
162 
163     auto node = GetAttachedNode().Upgrade();
164     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Click accepted, tag: %{public}s",
165         node ? node->GetTag().c_str() : "null");
166     if (onAccessibilityEventFunc_) {
167         onAccessibilityEventFunc_(AccessibilityEventType::CLICK);
168     }
169     refereeState_ = RefereeState::SUCCEED;
170     ResSchedReport::GetInstance().ResSchedDataReport("click");
171     if (backupTouchPointsForSucceedBlock_.has_value()) {
172         touchPoints_ = backupTouchPointsForSucceedBlock_.value();
173         backupTouchPointsForSucceedBlock_.reset();
174     }
175     TouchEvent touchPoint = {};
176     if (!touchPoints_.empty()) {
177         touchPoint = touchPoints_.begin()->second;
178     }
179     PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
180     NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
181         isPostEventResult_, touchPoint.postEventNodeId);
182     Offset localOffset(localPoint.GetX(), localPoint.GetY());
183     if (onClick_) {
184         ClickInfo info = GetClickInfo();
185         onClick_(info);
186     }
187 
188     if (remoteMessage_) {
189         ClickInfo info = GetClickInfo();
190         info.SetTimeStamp(touchPoint.time);
191         info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(localOffset);
192         remoteMessage_(info);
193     }
194     UpdateFingerListInfo();
195     SendCallbackMsg(onAction_);
196 
197     int64_t overTime = GetSysTimestamp();
198     if (SystemProperties::GetTraceInputEventEnabled()) {
199         ACE_SCOPED_TRACE("UserEvent InputTime:%lld OverTime:%lld InputType:ClickGesture",
200             static_cast<long long>(inputTime), static_cast<long long>(overTime));
201     }
202     firstInputTime_.reset();
203 }
204 
OnRejected()205 void ClickRecognizer::OnRejected()
206 {
207     SendRejectMsg();
208     refereeState_ = RefereeState::FAIL;
209     firstInputTime_.reset();
210     backupTouchPointsForSucceedBlock_.reset();
211 }
212 
HandleTouchDownEvent(const TouchEvent & event)213 void ClickRecognizer::HandleTouchDownEvent(const TouchEvent& event)
214 {
215     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW,
216         "Id:%{public}d, click %{public}d down, ETF: %{public}d, CTP: %{public}d, state: %{public}d",
217         event.touchEventId, event.id, equalsToFingers_, currentTouchPointsNum_, refereeState_);
218     extraInfo_ = "ETF: " + std::to_string(equalsToFingers_) + " CFP: " + std::to_string(currentTouchPointsNum_);
219     if (!firstInputTime_.has_value()) {
220         firstInputTime_ = event.time;
221     }
222 
223     auto pipeline = PipelineBase::GetCurrentContext();
224     if (pipeline && pipeline->IsFormRender()) {
225         touchDownTime_ = event.time;
226     }
227     if (IsRefereeFinished()) {
228         auto node = GetAttachedNode().Upgrade();
229         TAG_LOGI(AceLogTag::ACE_GESTURE,
230             "Click recognizer handle touch down event refereeState is %{public}d, node tag = %{public}s, id = "
231             SEC_PLD(%{public}s) ".",
232             refereeState_, node ? node->GetTag().c_str() : "null",
233             SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
234         return;
235     }
236     InitGlobalValue(event.sourceType);
237     if (!IsInAttachedNode(event, false)) {
238         Adjudicate(Claim(this), GestureDisposal::REJECT);
239         return;
240     }
241     // The last recognition sequence has been completed, reset the timer.
242     if (tappedCount_ > 0 && currentTouchPointsNum_ == 0) {
243         responseRegionBuffer_.clear();
244         tapDeadlineTimer_.Cancel();
245     }
246     if (currentTouchPointsNum_ == 0) {
247         auto frameNode = GetAttachedNode();
248         if (!frameNode.Invalid()) {
249             auto host = frameNode.Upgrade();
250             responseRegionBuffer_ = host->GetResponseRegionListForRecognizer(static_cast<int32_t>(event.sourceType));
251         }
252     }
253     if (fingersId_.find(event.id) == fingersId_.end()) {
254         fingersId_.insert(event.id);
255         ++currentTouchPointsNum_;
256         touchPoints_[event.id] = event;
257     }
258     UpdateFingerListInfo();
259     if (fingers_ > currentTouchPointsNum_) {
260         // waiting for multi-finger press
261         DeadlineTimer(fingerDeadlineTimer_, MULTI_FINGER_TIMEOUT);
262     } else {
263         // Turn off the multi-finger press deadline timer
264         fingerDeadlineTimer_.Cancel();
265         equalsToFingers_ = true;
266         if (ExceedSlop()) {
267             TAG_LOGW(AceLogTag::ACE_GESTURE, "Fail to detect multi finger tap due to offset is out of slop");
268             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
269         }
270     }
271     if (currentTouchPointsNum_ == fingers_) {
272         focusPoint_ = ComputeFocusPoint();
273     }
274 }
275 
IsFormRenderClickRejected(const TouchEvent & event)276 bool ClickRecognizer::IsFormRenderClickRejected(const TouchEvent& event)
277 {
278     Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
279     if (event.time.time_since_epoch().count() - touchDownTime_.time_since_epoch().count() >
280         DEFAULT_LONGPRESS_DURATION || offset.GetDistance() > MAX_THRESHOLD) {
281         TAG_LOGI(AceLogTag::ACE_GESTURE, "reject click when up, offset is %{public}f",
282             static_cast<float>(offset.GetDistance()));
283         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
284         return true;
285     }
286     return false;
287 }
288 
TriggerClickAccepted(const TouchEvent & event)289 void ClickRecognizer::TriggerClickAccepted(const TouchEvent& event)
290 {
291     TAG_LOGI(AceLogTag::ACE_GESTURE, "Click try accept");
292     time_ = event.time;
293     if (!useCatchMode_) {
294         OnAccepted();
295         return;
296     }
297     auto onGestureJudgeBeginResult = TriggerGestureJudgeCallback();
298     if (onGestureJudgeBeginResult == GestureJudgeResult::REJECT) {
299         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
300         return;
301     }
302     Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
303 }
304 
HandleTouchUpEvent(const TouchEvent & event)305 void ClickRecognizer::HandleTouchUpEvent(const TouchEvent& event)
306 {
307     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, click %{public}d up, state: %{public}d", event.touchEventId,
308         event.id, refereeState_);
309     auto pipeline = PipelineBase::GetCurrentContext();
310     // In a card scenario, determine the interval between finger pressing and finger lifting. Delete this section of
311     // logic when the formal scenario is complete.
312     if (pipeline && pipeline->IsFormRender() && IsFormRenderClickRejected(event)) {
313         return;
314     }
315     if (IsRefereeFinished()) {
316         return;
317     }
318     InitGlobalValue(event.sourceType);
319     touchPoints_[event.id] = event;
320     UpdateFingerListInfo();
321     auto isUpInRegion = IsPointInRegion(event);
322     if (fingersId_.find(event.id) != fingersId_.end()) {
323         fingersId_.erase(event.id);
324         --currentTouchPointsNum_;
325     }
326     if (currentTouchPointsNum_ == 0) {
327         responseRegionBuffer_.clear();
328     }
329     bool fingersNumberSatisfied = equalsToFingers_;
330     // Check whether multi-finger taps are completed in count_ times
331     if (equalsToFingers_ && (currentTouchPointsNum_ == 0) && isUpInRegion) {
332         // Turn off the multi-finger lift deadline timer
333         fingerDeadlineTimer_.Cancel();
334         tappedCount_++;
335         if (tappedCount_ == count_) {
336             TriggerClickAccepted(event);
337             return;
338         }
339         equalsToFingers_ = false;
340         // waiting for multi-finger lift
341         DeadlineTimer(tapDeadlineTimer_, MULTI_TAP_TIMEOUT);
342     }
343     if (refereeState_ != RefereeState::PENDING && refereeState_ != RefereeState::FAIL) {
344         if (fingersNumberSatisfied) {
345             Adjudicate(AceType::Claim(this), GestureDisposal::PENDING);
346         } else {
347             extraInfo_ += "finger number not satisfied.";
348             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
349         }
350     }
351     if (currentTouchPointsNum_ < fingers_ && equalsToFingers_) {
352         DeadlineTimer(fingerDeadlineTimer_, MULTI_FINGER_TIMEOUT);
353     }
354 }
355 
HandleTouchMoveEvent(const TouchEvent & event)356 void ClickRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
357 {
358     if (currentFingers_ < fingers_) {
359         return;
360     }
361     if (IsRefereeFinished()) {
362         return;
363     }
364     InitGlobalValue(event.sourceType);
365     // In form scenario, if move more than 20vp, reject click gesture.
366     // Remove form scenario when formal solution is completed.
367     auto pipeline = PipelineBase::GetCurrentContext();
368     if (pipeline && pipeline->IsFormRender()) {
369         Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
370         if (offset.GetDistance() > MAX_THRESHOLD) {
371             TAG_LOGI(AceLogTag::ACE_GESTURE, "This gesture is out of offset, try to reject it");
372             extraInfo_ += "offset is out of region.";
373             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
374         }
375     }
376     IsPointInRegion(event);
377     UpdateFingerListInfo();
378 }
379 
HandleTouchCancelEvent(const TouchEvent & event)380 void ClickRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
381 {
382     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, click %{public}d cancel", event.touchEventId, event.id);
383     extraInfo_ += "receive cancel event.";
384     if (IsRefereeFinished()) {
385         return;
386     }
387     InitGlobalValue(event.sourceType);
388     Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
389 }
390 
HandleOverdueDeadline()391 void ClickRecognizer::HandleOverdueDeadline()
392 {
393     if (currentTouchPointsNum_ < fingers_ || tappedCount_ < count_) {
394         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
395     }
396 }
397 
DeadlineTimer(CancelableCallback<void ()> & deadlineTimer,int32_t time)398 void ClickRecognizer::DeadlineTimer(CancelableCallback<void()>& deadlineTimer, int32_t time)
399 {
400     auto context = PipelineContext::GetCurrentContext();
401     CHECK_NULL_VOID(context);
402 
403     auto&& callback = [weakPtr = AceType::WeakClaim(this)]() {
404         auto refPtr = weakPtr.Upgrade();
405         if (refPtr) {
406             refPtr->HandleOverdueDeadline();
407         }
408     };
409 
410     deadlineTimer.Reset(callback);
411     auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
412     taskExecutor.PostDelayedTask(deadlineTimer, time, "ArkUIGestureClickDeadlineTimer");
413 }
414 
ComputeFocusPoint()415 Offset ClickRecognizer::ComputeFocusPoint()
416 {
417     Offset sumOfPoints;
418     int32_t count = 0;
419     for (auto& element : touchPoints_) {
420         if (count >= fingers_) {
421             break;
422         }
423         sumOfPoints = sumOfPoints + element.second.GetOffset();
424         count++;
425     }
426     Offset focusPoint = sumOfPoints / count;
427     return focusPoint;
428 }
429 
ExceedSlop()430 bool ClickRecognizer::ExceedSlop()
431 {
432     if (tappedCount_ > 0 && tappedCount_ < count_) {
433         Offset currentFocusPoint = ComputeFocusPoint();
434         Offset slop = currentFocusPoint - focusPoint_;
435         if (GreatOrEqual(PipelineBase::Px2VpWithCurrentDensity(slop.GetDistance()), MAX_THRESHOLD_MANYTAP)) {
436             return true;
437         }
438     }
439     return false;
440 }
441 
GetGestureEventInfo()442 GestureEvent ClickRecognizer::GetGestureEventInfo()
443 {
444     GestureEvent info;
445     info.SetTimeStamp(time_);
446     info.SetFingerList(fingerList_);
447     TouchEvent touchPoint = {};
448     for (const auto& pointKeyVal : touchPoints_) {
449         auto pointVal = pointKeyVal.second;
450         if (pointVal.sourceType != SourceType::NONE) {
451             touchPoint = pointVal;
452             break;
453         }
454     }
455     PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
456     NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
457         isPostEventResult_, touchPoint.postEventNodeId);
458     info.SetTimeStamp(touchPoint.time);
459     info.SetScreenLocation(touchPoint.GetScreenOffset());
460     info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(Offset(localPoint.GetX(), localPoint.GetY()));
461     info.SetSourceDevice(deviceType_);
462     info.SetDeviceId(deviceId_);
463     info.SetTarget(GetEventTarget().value_or(EventTarget()));
464     info.SetForce(touchPoint.force);
465     auto frameNode = GetAttachedNode().Upgrade();
466     std::string patternName = "";
467     if (frameNode) {
468         patternName = frameNode->GetTag();
469     }
470     info.SetPatternName(patternName.c_str());
471 
472     if (touchPoint.tiltX.has_value()) {
473         info.SetTiltX(touchPoint.tiltX.value());
474     }
475     if (touchPoint.tiltY.has_value()) {
476         info.SetTiltY(touchPoint.tiltY.value());
477     }
478     info.SetSourceTool(touchPoint.sourceTool);
479 #ifdef SECURITY_COMPONENT_ENABLE
480     info.SetDisplayX(touchPoint.screenX);
481     info.SetDisplayY(touchPoint.screenY);
482 #endif
483     info.SetPointerEvent(lastPointEvent_);
484     info.SetPressedKeyCodes(touchPoint.pressedKeyCodes_);
485     info.SetInputEventType(inputEventType_);
486     return info;
487 }
488 
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & onAction)489 void ClickRecognizer::SendCallbackMsg(const std::unique_ptr<GestureEventFunc>& onAction)
490 {
491     if (gestureInfo_ && gestureInfo_->GetDisposeTag()) {
492         return;
493     }
494     if (onAction && *onAction) {
495         GestureEvent info = GetGestureEventInfo();
496         // onAction may be overwritten in its invoke so we copy it first
497         auto onActionFunction = *onAction;
498         onActionFunction(info);
499     }
500 }
501 
TriggerGestureJudgeCallback()502 GestureJudgeResult ClickRecognizer::TriggerGestureJudgeCallback()
503 {
504     auto targetComponent = GetTargetComponent();
505     CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
506     auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
507     auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
508     if (!callback && !sysJudge_ && !gestureRecognizerJudgeFunc) {
509         return GestureJudgeResult::CONTINUE;
510     }
511     auto info = std::make_shared<TapGestureEvent>();
512     info->SetTimeStamp(time_);
513     info->SetDeviceId(deviceId_);
514     info->SetFingerList(fingerList_);
515     TouchEvent touchPoint = {};
516     if (!touchPoints_.empty()) {
517         touchPoint = touchPoints_.begin()->second;
518     }
519     info->SetSourceDevice(deviceType_);
520     info->SetTarget(GetEventTarget().value_or(EventTarget()));
521     info->SetForce(touchPoint.force);
522     if (gestureInfo_) {
523         gestureInfo_->SetInputEventType(inputEventType_);
524     }
525     if (touchPoint.tiltX.has_value()) {
526         info->SetTiltX(touchPoint.tiltX.value());
527     }
528     if (touchPoint.tiltY.has_value()) {
529         info->SetTiltY(touchPoint.tiltY.value());
530     }
531     info->SetSourceTool(touchPoint.sourceTool);
532     if (sysJudge_) {
533         return sysJudge_(gestureInfo_, info);
534     }
535     if (gestureRecognizerJudgeFunc) {
536         return gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_);
537     }
538     return callback(gestureInfo_, info);
539 }
540 
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)541 bool ClickRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
542 {
543     RefPtr<ClickRecognizer> curr = AceType::DynamicCast<ClickRecognizer>(recognizer);
544     if (!curr) {
545         ResetStatus();
546         return false;
547     }
548 
549     if (curr->count_ != count_ || curr->fingers_ != fingers_ || curr->priorityMask_ != priorityMask_ ||
550         curr->distanceThreshold_ != distanceThreshold_) {
551         ResetStatus();
552         return false;
553     }
554 
555     onAction_ = std::move(curr->onAction_);
556     ReconcileGestureInfoFrom(recognizer);
557     return true;
558 }
559 
Dump() const560 RefPtr<GestureSnapshot> ClickRecognizer::Dump() const
561 {
562     RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
563     std::stringstream oss;
564     oss << "count: " << count_ << ", "
565         << "fingers: " << fingers_ << ", "
566         << DumpGestureInfo();
567     info->customInfo = oss.str();
568     return info;
569 }
570 
CreateGestureFromRecognizer() const571 RefPtr<Gesture> ClickRecognizer::CreateGestureFromRecognizer() const
572 {
573     return AceType::MakeRefPtr<TapGesture>(count_, fingers_, distanceThreshold_);
574 }
575 
CleanRecognizerState()576 void ClickRecognizer::CleanRecognizerState()
577 {
578     if ((refereeState_ == RefereeState::SUCCEED ||
579         refereeState_ == RefereeState::FAIL ||
580         refereeState_ == RefereeState::DETECTING) &&
581         currentFingers_ == 0) {
582         tappedCount_ = 0;
583         refereeState_ = RefereeState::READY;
584         disposal_ = GestureDisposal::NONE;
585     }
586 }
587 } // namespace OHOS::Ace::NG
588