• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/base/observer_handler.h"
17 #include "core/components_ng/gestures/recognizers/click_recognizer.h"
18 #include "core/components_ng/manager/event/json_child_report.h"
19 #include "core/components_ng/manager/event/json_report.h"
20 #include "core/common/reporter/reporter.h"
21 #include "core/components_ng/event/event_constants.h"
22 
23 #include "base/ressched/ressched_report.h"
24 #include "core/common/recorder/event_definition.h"
25 #include "core/common/recorder/event_recorder.h"
26 
27 namespace OHOS::Ace::NG {
28 namespace {
29 
30 int32_t MULTI_FINGER_TIMEOUT = 300;
31 constexpr int32_t MULTI_FINGER_TIMEOUT_TOUCH = 300;
32 constexpr int32_t MULTI_FINGER_TIMEOUT_MOUSE = 300;
33 int32_t MULTI_TAP_TIMEOUT = 300;
34 constexpr int32_t MULTI_TAP_TIMEOUT_TOUCH = 300;
35 constexpr int32_t MULTI_TAP_TIMEOUT_MOUSE = 300;
36 constexpr int32_t MAX_THRESHOLD_MANYTAP = 60;
37 constexpr int32_t MAX_TAP_FINGERS = 10;
38 constexpr double MAX_THRESHOLD = 20.0;
39 constexpr int32_t DEFAULT_TAP_FINGERS = 1;
40 constexpr int32_t DOUBLE_CLICK_COUNT = 2;
41 constexpr int32_t DEFAULT_LONGPRESS_DURATION = 800000000;
42 
43 } // namespace
44 
ForceCleanRecognizer()45 void ClickRecognizer::ForceCleanRecognizer()
46 {
47     MultiFingersRecognizer::ForceCleanRecognizer();
48     tappedCount_ = 0;
49     equalsToFingers_ = false;
50     focusPoint_ = {};
51     fingerDeadlineTimer_.Cancel();
52     tapDeadlineTimer_.Cancel();
53     currentTouchPointsNum_ = 0;
54     responseRegionBuffer_.clear();
55     localMatrix_.clear();
56 }
57 
IsPointInRegion(const TouchEvent & event)58 bool ClickRecognizer::IsPointInRegion(const TouchEvent& event)
59 {
60     auto distanceThreshold = distanceThreshold_.ConvertToPx();
61     if (distanceThreshold < std::numeric_limits<double>::infinity()) {
62         Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
63         if (offset.GetDistance() > distanceThreshold) {
64             TAG_LOGI(AceLogTag::ACE_GESTURE, "Click move distance is larger than distanceThreshold_, "
65             "distanceThreshold_ is %{public}f", distanceThreshold);
66             extraInfo_ += "move distance out of distanceThreshold.";
67             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
68             return false;
69         } else {
70             return true;
71         }
72     }
73     PointF localPoint(event.x, event.y);
74     auto frameNode = GetAttachedNode();
75     if (!frameNode.Invalid()) {
76         auto host = frameNode.Upgrade();
77         CHECK_NULL_RETURN(host, false);
78         bool needPostEvent = isPostEventResult_ || event.passThrough;
79         TransformForRecognizer(
80             localPoint, frameNode, false, needPostEvent, event.postEventNodeId);
81         auto renderContext = host->GetRenderContext();
82         CHECK_NULL_RETURN(renderContext, false);
83         auto paintRect = renderContext->GetPaintRectWithoutTransform();
84         localPoint = localPoint + paintRect.GetOffset();
85         if (!host->InResponseRegionList(localPoint, responseRegionBuffer_)) {
86             TAG_LOGI(AceLogTag::ACE_GESTURE,
87                 "InputTracking id:%{public}d, this MOVE/UP event is out of region, try to reject click gesture",
88                 event.touchEventId);
89             extraInfo_ += "move/up event out of region.";
90             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
91             return false;
92         }
93     }
94     return true;
95 }
96 
ClickRecognizer(int32_t fingers,int32_t count,double distanceThreshold,bool isLimitFingerCount)97 ClickRecognizer::ClickRecognizer(int32_t fingers, int32_t count, double distanceThreshold, bool isLimitFingerCount)
98     : MultiFingersRecognizer(fingers, isLimitFingerCount), count_(count)
99 {
100     if (fingers_ > MAX_TAP_FINGERS || fingers_ < DEFAULT_TAP_FINGERS) {
101         fingers_ = DEFAULT_TAP_FINGERS;
102     }
103     distanceThreshold_ = Dimension(
104         Dimension(distanceThreshold, DimensionUnit::PX).ConvertToVp(), DimensionUnit::VP);
105 
106     userDT_ = distanceThreshold_.ConvertToPx();
107     if (userDT_ <= 0) {
108         distanceThreshold_ = Dimension(std::numeric_limits<double>::infinity(), DimensionUnit::PX);
109     }
110 
111     SetOnAccessibility(GetOnAccessibilityEventFunc());
112 }
113 
ClickRecognizer(int32_t fingers,int32_t count,Dimension distanceThreshold,bool isLimitFingerCount)114 ClickRecognizer::ClickRecognizer(int32_t fingers, int32_t count, Dimension distanceThreshold, bool isLimitFingerCount)
115     : MultiFingersRecognizer(fingers, isLimitFingerCount), count_(count), distanceThreshold_(distanceThreshold)
116 {
117     if (fingers_ > MAX_TAP_FINGERS || fingers_ < DEFAULT_TAP_FINGERS) {
118         fingers_ = DEFAULT_TAP_FINGERS;
119     }
120 
121     userDT_ = distanceThreshold.ConvertToPx();
122     if (userDT_ <= 0) {
123         distanceThreshold_ = Dimension(std::numeric_limits<double>::infinity(), DimensionUnit::PX);
124     }
125 
126     SetOnAccessibility(GetOnAccessibilityEventFunc());
127 }
128 
InitGlobalValue(SourceType sourceType)129 void ClickRecognizer::InitGlobalValue(SourceType sourceType)
130 {
131     switch (sourceType) {
132         case SourceType::TOUCH:
133             MULTI_FINGER_TIMEOUT = MULTI_FINGER_TIMEOUT_TOUCH;
134             MULTI_TAP_TIMEOUT = MULTI_TAP_TIMEOUT_TOUCH;
135             break;
136         case SourceType::MOUSE:
137         case SourceType::TOUCH_PAD:
138             MULTI_FINGER_TIMEOUT = MULTI_FINGER_TIMEOUT_MOUSE;
139             MULTI_TAP_TIMEOUT = MULTI_TAP_TIMEOUT_MOUSE;
140             break;
141         default:
142             break;
143     }
144 }
145 
GetClickInfo()146 ClickInfo ClickRecognizer::GetClickInfo()
147 {
148     TouchEvent touchPoint = {};
149     if (!touchPoints_.empty()) {
150         touchPoint = touchPoints_.begin()->second;
151     }
152     ClickInfo info(touchPoint.id);
153     PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
154     TransformForRecognizer(localPoint, GetAttachedNode(), false,
155         isPostEventResult_, touchPoint.postEventNodeId);
156     Offset localOffset(localPoint.GetX(), localPoint.GetY());
157     info.SetTimeStamp(touchPoint.time);
158     info.SetScreenLocation(touchPoint.GetScreenOffset());
159     info.SetGlobalDisplayLocation(touchPoint.GetGlobalDisplayOffset());
160     info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(localOffset);
161     info.SetSourceDevice(deviceType_);
162     info.SetDeviceId(deviceId_);
163     info.SetTarget(GetEventTarget().value_or(EventTarget()));
164     info.SetForce(touchPoint.force);
165     auto frameNode = GetAttachedNode().Upgrade();
166     std::string patternName = "";
167     if (frameNode) {
168         patternName = frameNode->GetTag();
169     }
170     info.SetPatternName(patternName.c_str());
171     if (touchPoint.tiltX.has_value()) {
172         info.SetTiltX(touchPoint.tiltX.value());
173     }
174     if (touchPoint.tiltY.has_value()) {
175         info.SetTiltY(touchPoint.tiltY.value());
176     }
177     if (touchPoint.rollAngle.has_value()) {
178         info.SetRollAngle(touchPoint.rollAngle.value());
179     }
180     info.SetSourceTool(touchPoint.sourceTool);
181     info.SetTargetDisplayId(touchPoint.targetDisplayId);
182     return info;
183 }
184 
OnAccepted()185 void ClickRecognizer::OnAccepted()
186 {
187     int64_t acceptTime = GetSysTimestamp();
188     int64_t inputTime = acceptTime;
189     if (firstInputTime_.has_value()) {
190         inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
191     }
192     if (SystemProperties::GetTraceInputEventEnabled()) {
193         ACE_SCOPED_TRACE("UserEvent InputTime:%lld AcceptTime:%lld InputType:ClickGesture",
194             static_cast<long long>(inputTime), static_cast<long long>(acceptTime));
195     }
196     firstInputTime_.reset();
197 
198     auto node = GetAttachedNode().Upgrade();
199     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "CLK RACC, T: %{public}s",
200         node ? node->GetTag().c_str() : "null");
201     auto lastRefereeState = refereeState_;
202     lastRefereeState_ = refereeState_;
203     refereeState_ = RefereeState::SUCCEED;
204     ResSchedReport::GetInstance().ResSchedDataReport("click");
205     if (backupTouchPointsForSucceedBlock_.has_value()) {
206         touchPoints_ = backupTouchPointsForSucceedBlock_.value();
207         backupTouchPointsForSucceedBlock_.reset();
208     }
209     TouchEvent touchPoint = {};
210     if (!touchPoints_.empty()) {
211         touchPoint = touchPoints_.begin()->second;
212     }
213     PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
214     bool needPostEvent = isPostEventResult_ || touchPoint.passThrough;
215     localMatrix_ = NGGestureRecognizer::GetTransformMatrix(
216         GetAttachedNode(), false, needPostEvent, touchPoint.postEventNodeId);
217     TransformForRecognizer(
218         localPoint, GetAttachedNode(), false, needPostEvent, touchPoint.postEventNodeId);
219     Offset localOffset(localPoint.GetX(), localPoint.GetY());
220     if (onClick_) {
221         ClickInfo info = GetClickInfo();
222         onClick_(info);
223     }
224 
225     if (remoteMessage_) {
226         ClickInfo info = GetClickInfo();
227         info.SetTimeStamp(touchPoint.time);
228         info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(localOffset);
229         remoteMessage_(info);
230     }
231     UpdateFingerListInfo();
232     SendCallbackMsg(onAction_, GestureCallbackType::ACTION);
233 
234     int64_t overTime = GetSysTimestamp();
235     if (SystemProperties::GetTraceInputEventEnabled()) {
236         ACE_SCOPED_TRACE("UserEvent InputTime:%lld OverTime:%lld InputType:ClickGesture",
237             static_cast<long long>(inputTime), static_cast<long long>(overTime));
238     }
239     firstInputTime_.reset();
240 
241     // already send Event in onClick
242     if (onAccessibilityEventFunc_ && !onClick_) {
243         onAccessibilityEventFunc_(AccessibilityEventType::CLICK);
244     }
245     if (lastRefereeState != RefereeState::SUCCEED_BLOCKED) {
246         ResetStateVoluntarily();
247     }
248 }
249 
OnRejected()250 void ClickRecognizer::OnRejected()
251 {
252     SendRejectMsg();
253     lastRefereeState_ = refereeState_;
254     refereeState_ = RefereeState::FAIL;
255     firstInputTime_.reset();
256     backupTouchPointsForSucceedBlock_.reset();
257 }
258 
HandleTouchDownEvent(const TouchEvent & event)259 void ClickRecognizer::HandleTouchDownEvent(const TouchEvent& event)
260 {
261     extraInfo_ = "ETF: " + std::to_string(equalsToFingers_) + " CFP: " + std::to_string(currentTouchPointsNum_);
262     if (!firstInputTime_.has_value()) {
263         firstInputTime_ = event.time;
264     }
265 
266     if (count_ == DOUBLE_CLICK_COUNT) {
267         if (tappedCount_ == 0 || tappedCount_ == 1) {
268             TAG_LOGD(AceLogTag::ACE_GESTURE, "Click recognizer handle touch down event current Click is %{public}d",
269                 tappedCount_);
270         }
271     }
272     auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
273     if (pipeline && pipeline->IsFormRenderExceptDynamicComponent()) {
274         touchDownTime_ = event.time;
275     }
276     if (IsRefereeFinished()) {
277         auto node = GetAttachedNode().Upgrade();
278         TAG_LOGI(AceLogTag::ACE_GESTURE,
279             "Click recognizer handle touch down event refereeState is %{public}d, node tag = %{public}s, id = "
280             SEC_PLD(%{public}s) ".",
281             refereeState_, node ? node->GetTag().c_str() : "null",
282             SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
283         return;
284     }
285     InitGlobalValue(event.sourceType);
286     UpdateInfoWithDownEvent(event);
287 }
288 
UpdateInfoWithDownEvent(const TouchEvent & event)289 void ClickRecognizer::UpdateInfoWithDownEvent(const TouchEvent& event)
290 {
291     // The last recognition sequence has been completed, reset the timer.
292     if (tappedCount_ > 0 && currentTouchPointsNum_ == 0) {
293         responseRegionBuffer_.clear();
294         tapDeadlineTimer_.Cancel();
295     }
296     if (currentTouchPointsNum_ == 0) {
297         auto frameNode = GetAttachedNode();
298         if (!frameNode.Invalid()) {
299             auto host = frameNode.Upgrade();
300             responseRegionBuffer_ = host->GetResponseRegionListForRecognizer(static_cast<int32_t>(event.sourceType));
301         }
302     }
303     if (fingersId_.find(event.id) == fingersId_.end()) {
304         fingersId_.insert(event.id);
305         ++currentTouchPointsNum_;
306         touchPoints_[event.id] = event;
307     }
308     UpdateFingerListInfo();
309     if (fingers_ > currentTouchPointsNum_) {
310         // waiting for multi-finger press
311         DeadlineTimer(fingerDeadlineTimer_, MULTI_FINGER_TIMEOUT);
312     } else {
313         // Turn off the multi-finger press deadline timer
314         fingerDeadlineTimer_.Cancel();
315         equalsToFingers_ = true;
316         if (ExceedSlop()) {
317             TAG_LOGW(AceLogTag::ACE_GESTURE, "Fail to detect multi finger tap due to offset is out of slop");
318             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
319         }
320     }
321     if (currentTouchPointsNum_ == fingers_) {
322         focusPoint_ = ComputeFocusPoint();
323     }
324 }
325 
IsFormRenderClickRejected(const TouchEvent & event)326 bool ClickRecognizer::IsFormRenderClickRejected(const TouchEvent& event)
327 {
328     Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
329     if (event.time.time_since_epoch().count() - touchDownTime_.time_since_epoch().count() >
330         DEFAULT_LONGPRESS_DURATION || offset.GetDistance() > MAX_THRESHOLD) {
331         TAG_LOGI(AceLogTag::ACE_GESTURE, "reject click when up, offset is %{public}f",
332             static_cast<float>(offset.GetDistance()));
333         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
334         return true;
335     }
336     return false;
337 }
338 
TriggerClickAccepted(const TouchEvent & event)339 void ClickRecognizer::TriggerClickAccepted(const TouchEvent& event)
340 {
341     TAG_LOGI(AceLogTag::ACE_GESTURE, "Click try accept");
342     time_ = event.time;
343     if (!useCatchMode_) {
344         OnAccepted();
345         return;
346     }
347     if (CheckLimitFinger()) {
348         extraInfo_ += " isLFC: " + std::to_string(isLimitFingerCount_);
349         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
350         return;
351     }
352     auto onGestureJudgeBeginResult = TriggerGestureJudgeCallback();
353     if (onGestureJudgeBeginResult == GestureJudgeResult::REJECT) {
354         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
355         TAG_LOGI(AceLogTag::ACE_GESTURE, "Click gesture judge reject");
356         return;
357     }
358     Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
359 }
360 
HandleTouchUpEvent(const TouchEvent & event)361 void ClickRecognizer::HandleTouchUpEvent(const TouchEvent& event)
362 {
363     if (fingersId_.find(event.id) != fingersId_.end()) {
364         fingersId_.erase(event.id);
365         --currentTouchPointsNum_;
366     }
367     auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
368     // In a card scenario, determine the interval between finger pressing and finger lifting. Delete this section of
369     // logic when the formal scenario is complete.
370     if (pipeline && pipeline->IsFormRenderExceptDynamicComponent() && IsFormRenderClickRejected(event)) {
371         return;
372     }
373     if (IsRefereeFinished()) {
374         return;
375     }
376     InitGlobalValue(event.sourceType);
377     touchPoints_[event.id] = event;
378     UpdateFingerListInfo();
379     auto isUpInRegion = IsPointInRegion(event);
380     if (currentTouchPointsNum_ == 0) {
381         responseRegionBuffer_.clear();
382     }
383     bool fingersNumberSatisfied = equalsToFingers_;
384     // Check whether multi-finger taps are completed in count_ times
385     if (equalsToFingers_ && (currentTouchPointsNum_ == 0) && isUpInRegion) {
386         // Turn off the multi-finger lift deadline timer
387         fingerDeadlineTimer_.Cancel();
388         tappedCount_++;
389         if (CheckLimitFinger()) {
390             extraInfo_ += " isLFC: " + std::to_string(isLimitFingerCount_);
391             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
392         }
393         if (tappedCount_ == count_) {
394             TriggerClickAccepted(event);
395             return;
396         }
397         equalsToFingers_ = false;
398         // waiting for multi-finger lift
399         DeadlineTimer(tapDeadlineTimer_, MULTI_TAP_TIMEOUT);
400     }
401     if (refereeState_ != RefereeState::PENDING && refereeState_ != RefereeState::FAIL) {
402         if (fingersNumberSatisfied) {
403             Adjudicate(AceType::Claim(this), GestureDisposal::PENDING);
404             AboutToAddToPendingRecognizers(event);
405         } else {
406             extraInfo_ += "finger number not satisfied.";
407             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
408         }
409     }
410     if (currentTouchPointsNum_ < fingers_ && equalsToFingers_) {
411         DeadlineTimer(fingerDeadlineTimer_, MULTI_FINGER_TIMEOUT);
412     }
413 }
414 
HandleTouchMoveEvent(const TouchEvent & event)415 void ClickRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
416 {
417     if (currentFingers_ < fingers_) {
418         return;
419     }
420     if (IsRefereeFinished()) {
421         return;
422     }
423     InitGlobalValue(event.sourceType);
424     // In form scenario, if move more than 20vp, reject click gesture.
425     // Remove form scenario when formal solution is completed.
426     auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
427     if (pipeline && pipeline->IsFormRenderExceptDynamicComponent()) {
428         Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
429         if (offset.GetDistance() > MAX_THRESHOLD) {
430             TAG_LOGI(AceLogTag::ACE_GESTURE, "This gesture is out of offset, try to reject it");
431             extraInfo_ += "offset is out of region.";
432             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
433         }
434     }
435     IsPointInRegion(event);
436     UpdateFingerListInfo();
437 }
438 
HandleTouchCancelEvent(const TouchEvent & event)439 void ClickRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
440 {
441     extraInfo_ += "cancel received.";
442     if (IsRefereeFinished()) {
443         return;
444     }
445     InitGlobalValue(event.sourceType);
446     Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
447 }
448 
ResetStatusInHandleOverdueDeadline()449 void ClickRecognizer::ResetStatusInHandleOverdueDeadline()
450 {
451     auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
452     CHECK_NULL_VOID(context);
453     auto eventManager = context->GetEventManager();
454     CHECK_NULL_VOID(eventManager);
455     auto refereeNG = eventManager->GetGestureRefereeNG(nullptr);
456     CHECK_NULL_VOID(refereeNG);
457     if (refereeNG->QueryAllDone()) {
458         for (const auto& recognizer : responseLinkRecognizer_) {
459             if (recognizer && recognizer != AceType::Claim(this)) {
460                 recognizer->ResetResponseLinkRecognizer();
461             }
462         }
463         ResetResponseLinkRecognizer();
464     }
465 }
466 
HandleOverdueDeadline()467 void ClickRecognizer::HandleOverdueDeadline()
468 {
469     if (currentTouchPointsNum_ < fingers_ || tappedCount_ < count_) {
470         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
471         ResetStatusInHandleOverdueDeadline();
472     }
473 }
474 
DeadlineTimer(CancelableCallback<void ()> & deadlineTimer,int32_t time)475 void ClickRecognizer::DeadlineTimer(CancelableCallback<void()>& deadlineTimer, int32_t time)
476 {
477     auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
478     CHECK_NULL_VOID(context);
479 
480     auto&& callback = [weakPtr = AceType::WeakClaim(this)]() {
481         auto refPtr = weakPtr.Upgrade();
482         if (refPtr) {
483             refPtr->HandleOverdueDeadline();
484         }
485     };
486 
487     deadlineTimer.Reset(callback);
488     auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
489     taskExecutor.PostDelayedTask(deadlineTimer, time, "ArkUIGestureClickDeadlineTimer");
490 }
491 
ComputeFocusPoint()492 Offset ClickRecognizer::ComputeFocusPoint()
493 {
494     Offset sumOfPoints;
495     int32_t count = 0;
496     for (auto& element : touchPoints_) {
497         if (count >= fingers_) {
498             break;
499         }
500         sumOfPoints = sumOfPoints + element.second.GetOffset();
501         count++;
502     }
503     Offset focusPoint = sumOfPoints / count;
504     return focusPoint;
505 }
506 
ExceedSlop()507 bool ClickRecognizer::ExceedSlop()
508 {
509     if (tappedCount_ > 0 && tappedCount_ < count_) {
510         Offset currentFocusPoint = ComputeFocusPoint();
511         Offset slop = currentFocusPoint - focusPoint_;
512         if (GreatOrEqual(PipelineBase::Px2VpWithCurrentDensity(slop.GetDistance()), MAX_THRESHOLD_MANYTAP)) {
513             return true;
514         }
515     }
516     return false;
517 }
518 
GetGestureEventInfo()519 GestureEvent ClickRecognizer::GetGestureEventInfo()
520 {
521     GestureEvent info;
522     info.SetTimeStamp(time_);
523     info.SetFingerList(fingerList_);
524     TouchEvent touchPoint = {};
525     for (const auto& pointKeyVal : touchPoints_) {
526         auto pointVal = pointKeyVal.second;
527         if (pointVal.sourceType != SourceType::NONE) {
528             touchPoint = pointVal;
529             break;
530         }
531     }
532     PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
533     bool needPostEvent = isPostEventResult_ || touchPoint.passThrough;
534     TransformForRecognizer(
535         localPoint, GetAttachedNode(), false, needPostEvent, touchPoint.postEventNodeId);
536     info.SetTimeStamp(touchPoint.time);
537     info.SetScreenLocation(touchPoint.GetScreenOffset());
538     info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(Offset(localPoint.GetX(), localPoint.GetY()));
539     info.SetGlobalDisplayLocation(touchPoint.GetGlobalDisplayOffset());
540     info.SetSourceDevice(deviceType_);
541     info.SetDeviceId(deviceId_);
542     info.SetTarget(GetEventTarget().value_or(EventTarget()));
543     info.SetForce(touchPoint.force);
544     auto frameNode = GetAttachedNode().Upgrade();
545     std::string patternName = "";
546     if (frameNode) {
547         patternName = frameNode->GetTag();
548     }
549     info.SetPatternName(patternName.c_str());
550 
551     if (touchPoint.tiltX.has_value()) {
552         info.SetTiltX(touchPoint.tiltX.value());
553     }
554     if (touchPoint.tiltY.has_value()) {
555         info.SetTiltY(touchPoint.tiltY.value());
556     }
557     if (touchPoint.rollAngle.has_value()) {
558         info.SetRollAngle(touchPoint.rollAngle.value());
559     }
560     info.SetSourceTool(touchPoint.sourceTool);
561     info.SetTargetDisplayId(touchPoint.targetDisplayId);
562 #ifdef SECURITY_COMPONENT_ENABLE
563     info.SetDisplayX(touchPoint.screenX);
564     info.SetDisplayY(touchPoint.screenY);
565 #endif
566     info.SetPointerEvent(lastPointEvent_);
567     info.SetClickPointerEvent(touchPoint.GetTouchEventPointerEvent());
568     info.SetPressedKeyCodes(touchPoint.pressedKeyCodes_);
569     info.SetInputEventType(inputEventType_);
570     info.CopyConvertInfoFrom(touchPoint.convertInfo);
571     return info;
572 }
573 
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & onAction,GestureCallbackType type)574 void ClickRecognizer::SendCallbackMsg(const std::unique_ptr<GestureEventFunc>& onAction, GestureCallbackType type)
575 {
576     if (gestureInfo_ && gestureInfo_->GetDisposeTag()) {
577         return;
578     }
579     if (onAction && *onAction) {
580         GestureEvent info = GetGestureEventInfo();
581         info.SetGestureTypeName(GestureTypeName::TAP_GESTURE);
582         // onAction may be overwritten in its invoke so we copy it first
583         auto onActionFunction = *onAction;
584         HandleGestureAccept(info, type, GestureListenerType::TAP);
585         onActionFunction(info);
586         HandleReports(info, type);
587         RecordClickEventIfNeed(info);
588     }
589 }
590 
HandleReports(const GestureEvent & info,GestureCallbackType type)591 void ClickRecognizer::HandleReports(const GestureEvent& info, GestureCallbackType type)
592 {
593     auto frameNode = GetAttachedNode().Upgrade();
594     CHECK_NULL_VOID(frameNode);
595     if (GetRecognizerType() == GestureTypeName::CLICK) {
596         ClickJsonReport clickReport;
597         clickReport.SetCallbackType(type);
598         clickReport.SetGestureType(GetRecognizerType());
599         clickReport.SetId(frameNode->GetId());
600         clickReport.SetCount(count_);
601         clickReport.SetPoint(info.GetGlobalPoint());
602         clickReport.SetFingerList(info.GetFingerList());
603         Reporter::GetInstance().HandleUISessionReporting(clickReport);
604     } else if (GetRecognizerType() == GestureTypeName::TAP_GESTURE) {
605         TapJsonReport tapReport;
606         tapReport.SetCallbackType(type);
607         tapReport.SetGestureType(GetRecognizerType());
608         tapReport.SetId(frameNode->GetId());
609         tapReport.SetCount(count_);
610         tapReport.SetPoint(info.GetGlobalPoint());
611         tapReport.SetFingerList(info.GetFingerList());
612         Reporter::GetInstance().HandleUISessionReporting(tapReport);
613     }
614 }
615 
RecordClickEventIfNeed(const GestureEvent & info) const616 void ClickRecognizer::RecordClickEventIfNeed(const GestureEvent& info) const
617 {
618     if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
619         auto host = GetAttachedNode().Upgrade();
620         CHECK_NULL_VOID(host);
621         auto accessibilityProperty = host->GetAccessibilityProperty<NG::AccessibilityProperty>();
622         CHECK_NULL_VOID(accessibilityProperty);
623         Recorder::EventParamsBuilder builder;
624         builder.SetEventType(Recorder::EventType::CLICK)
625             .SetId(host->GetInspectorId().value_or(""))
626             .SetType(host->GetTag())
627             .SetText(accessibilityProperty->GetGroupText(true))
628             .SetDescription(host->GetAutoEventParamValue(""))
629             .SetHost(host);
630         auto pointSwitch = Recorder::EventRecorder::Get().IsRecordEnable(Recorder::EventCategory::CATEGORY_POINT);
631         if (pointSwitch) {
632             static const int32_t precision = 2;
633             std::stringstream ss;
634             ss << std::fixed << std::setprecision(precision) << info.GetGlobalPoint().GetX() << ","
635                << info.GetGlobalPoint().GetY();
636             builder.SetExtra(Recorder::KEY_POINT, ss.str());
637         }
638         Recorder::EventRecorder::Get().OnClick(std::move(builder));
639     }
640 }
641 
TriggerGestureJudgeCallback()642 GestureJudgeResult ClickRecognizer::TriggerGestureJudgeCallback()
643 {
644     auto targetComponent = GetTargetComponent();
645     CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
646     auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
647     auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
648     if (!callback && !sysJudge_ && !gestureRecognizerJudgeFunc) {
649         return GestureJudgeResult::CONTINUE;
650     }
651     auto info = std::make_shared<TapGestureEvent>();
652     info->SetTimeStamp(time_);
653     info->SetDeviceId(deviceId_);
654     info->SetFingerList(fingerList_);
655     TouchEvent touchPoint = {};
656     if (!touchPoints_.empty()) {
657         touchPoint = touchPoints_.begin()->second;
658     }
659     info->SetSourceDevice(deviceType_);
660     info->SetTarget(GetEventTarget().value_or(EventTarget()));
661     info->SetForce(touchPoint.force);
662     if (gestureInfo_) {
663         gestureInfo_->SetInputEventType(inputEventType_);
664     }
665     if (touchPoint.tiltX.has_value()) {
666         info->SetTiltX(touchPoint.tiltX.value());
667     }
668     if (touchPoint.tiltY.has_value()) {
669         info->SetTiltY(touchPoint.tiltY.value());
670     }
671     if (touchPoint.rollAngle.has_value()) {
672         info->SetRollAngle(touchPoint.rollAngle.value());
673     }
674     info->SetSourceTool(touchPoint.sourceTool);
675     info->SetRawInputEventType(inputEventType_);
676     info->SetRawInputEvent(lastPointEvent_);
677     info->SetRawInputDeviceId(deviceId_);
678     info->SetTargetDisplayId(touchPoint.targetDisplayId);
679     info->SetPressedKeyCodes(touchPoint.pressedKeyCodes_);
680     if (sysJudge_) {
681         TAG_LOGD(AceLogTag::ACE_GESTURE, "sysJudge");
682         return sysJudge_(gestureInfo_, info);
683     }
684     if (gestureRecognizerJudgeFunc) {
685         return gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_);
686     }
687     return callback(gestureInfo_, info);
688 }
689 
CheckReconcileFromProperties(const RefPtr<NGGestureRecognizer> & recognizer)690 bool ClickRecognizer::CheckReconcileFromProperties(const RefPtr<NGGestureRecognizer>& recognizer)
691 {
692     RefPtr<ClickRecognizer> curr = AceType::DynamicCast<ClickRecognizer>(recognizer);
693     if (!curr) {
694         return true;
695     }
696     if (curr->count_ != count_ || curr->fingers_ != fingers_ || curr->priorityMask_ != priorityMask_) {
697         return true;
698     }
699     if (curr->distanceThreshold_.Value() == std::numeric_limits<double>::infinity() &&
700         distanceThreshold_.Value() == std::numeric_limits<double>::infinity()) {
701         return false;
702     }
703     if (curr->distanceThreshold_ != distanceThreshold_) {
704         return true;
705     }
706     return false;
707 }
708 
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)709 bool ClickRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
710 {
711     RefPtr<ClickRecognizer> curr = AceType::DynamicCast<ClickRecognizer>(recognizer);
712     if (!curr) {
713         ResetStatus();
714         return false;
715     }
716     if (CheckReconcileFromProperties(recognizer)) {
717         ResetStatus();
718         return false;
719     }
720     isLimitFingerCount_ = curr->isLimitFingerCount_;
721 
722     onAction_ = std::move(curr->onAction_);
723     ReconcileGestureInfoFrom(recognizer);
724     return true;
725 }
726 
Dump() const727 RefPtr<GestureSnapshot> ClickRecognizer::Dump() const
728 {
729     RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
730     std::stringstream oss;
731     oss << "count: " << count_ << ", "
732         << "fingers: " << fingers_ << ", "
733         << "userDT: " << userDT_ << ", "
734         << DumpGestureInfo();
735     info->customInfo = oss.str();
736     return info;
737 }
738 
CreateGestureFromRecognizer() const739 RefPtr<Gesture> ClickRecognizer::CreateGestureFromRecognizer() const
740 {
741     return AceType::MakeRefPtr<TapGesture>(count_, fingers_, distanceThreshold_, isLimitFingerCount_);
742 }
743 
CleanRecognizerState()744 void ClickRecognizer::CleanRecognizerState()
745 {
746     if ((refereeState_ == RefereeState::SUCCEED ||
747         refereeState_ == RefereeState::FAIL ||
748         refereeState_ == RefereeState::DETECTING) &&
749         currentFingers_ == 0) {
750         tappedCount_ = 0;
751         lastRefereeState_ = RefereeState::READY;
752         refereeState_ = RefereeState::READY;
753         disposal_ = GestureDisposal::NONE;
754     }
755 }
756 
GetOnAccessibilityEventFunc()757 OnAccessibilityEventFunc ClickRecognizer::GetOnAccessibilityEventFunc()
758 {
759     auto callback = [weak = WeakClaim(this)](AccessibilityEventType eventType) {
760         auto recognizer = weak.Upgrade();
761         CHECK_NULL_VOID(recognizer);
762         auto node = recognizer->GetAttachedNode().Upgrade();
763         CHECK_NULL_VOID(node);
764         node->OnAccessibilityEvent(eventType);
765     };
766     return callback;
767 }
768 
AboutToAddToPendingRecognizers(const TouchEvent & event)769 void ClickRecognizer::AboutToAddToPendingRecognizers(const TouchEvent& event)
770 {
771     if (event.sourceType == SourceType::MOUSE &&
772         (refereeState_ == RefereeState::PENDING || refereeState_ == RefereeState::PENDING_BLOCKED)) {
773         auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
774         CHECK_NULL_VOID(pipeline);
775         auto eventManager = pipeline->GetEventManager();
776         CHECK_NULL_VOID(eventManager);
777         eventManager->AddToMousePendingRecognizers(AceType::WeakClaim(this));
778     }
779 }
780 } // namespace OHOS::Ace::NG
781