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