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