1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/gestures/recognizers/pan_recognizer.h"
17
18 #include "base/geometry/offset.h"
19 #include "base/log/log.h"
20 #include "base/log/log_wrapper.h"
21 #include "base/perfmonitor/perf_monitor.h"
22 #include "base/ressched/ressched_report.h"
23 #include "base/utils/utils.h"
24 #include "core/components_ng/gestures/base_gesture_event.h"
25 #include "core/components_ng/gestures/gesture_referee.h"
26 #include "core/components_ng/gestures/recognizers/gesture_recognizer.h"
27 #include "core/components_ng/gestures/recognizers/multi_fingers_recognizer.h"
28 #include "core/event/axis_event.h"
29 #include "core/pipeline_ng/pipeline_context.h"
30
31 namespace OHOS::Ace::NG {
32
33 namespace {
34
35 constexpr int32_t MAX_PAN_FINGERS = 10;
36 constexpr int32_t DEFAULT_PAN_FINGERS = 1;
37 constexpr int32_t AXIS_PAN_FINGERS = 1;
38 constexpr float MIN_SPEED_THRESHOLD = 500.0f;
39
40 } // namespace
41
ForceCleanRecognizer()42 void PanRecognizer::ForceCleanRecognizer()
43 {
44 MultiFingersRecognizer::ForceCleanRecognizer();
45 OnResetStatus();
46 }
47
PanRecognizer(int32_t fingers,const PanDirection & direction,double distance,bool isLimitFingerCount)48 PanRecognizer::PanRecognizer(int32_t fingers, const PanDirection& direction, double distance, bool isLimitFingerCount)
49 : MultiFingersRecognizer(fingers, isLimitFingerCount), direction_(direction), distance_(distance),
50 mouseDistance_(distance), newFingers_(fingers_), newDistance_(distance_), newDirection_(direction_)
51 {
52 panVelocity_.SetDirection(direction_.type);
53 if (fingers_ > MAX_PAN_FINGERS || fingers_ < DEFAULT_PAN_FINGERS) {
54 fingers_ = DEFAULT_PAN_FINGERS;
55 }
56 }
57
CreateGestureFromRecognizer() const58 RefPtr<Gesture> PanRecognizer::CreateGestureFromRecognizer() const
59 {
60 return AceType::MakeRefPtr<PanGesture>(fingers_, direction_, distance_, isLimitFingerCount_);
61 }
62
PanRecognizer(const RefPtr<PanGestureOption> & panGestureOption)63 PanRecognizer::PanRecognizer(const RefPtr<PanGestureOption>& panGestureOption) : panGestureOption_(panGestureOption)
64 {
65 auto context = PipelineContext::GetCurrentContext();
66 CHECK_NULL_VOID(context);
67 uint32_t directNum = panGestureOption->GetDirection().type;
68 double distanceNumber = panGestureOption->GetDistance();
69 int32_t fingersNumber = panGestureOption->GetFingers();
70 bool isLimitFingerCount = panGestureOption->GetIsLimitFingerCount();
71
72 distance_ = LessNotEqual(distanceNumber, 0.0) ? DEFAULT_PAN_DISTANCE.ConvertToPx() : distanceNumber;
73 fingers_ = fingersNumber;
74 isLimitFingerCount_ = isLimitFingerCount;
75 if (fingers_ > MAX_PAN_FINGERS || fingers_ < DEFAULT_PAN_FINGERS) {
76 fingers_ = DEFAULT_PAN_FINGERS;
77 }
78
79 if (directNum >= PanDirection::NONE && directNum <= PanDirection::ALL) {
80 direction_.type = directNum;
81 }
82
83 newFingers_ = fingers_;
84 newDistance_ = distance_;
85 mouseDistance_ = distance_;
86 newDirection_ = direction_;
87
88 PanFingersFuncType changeFingers = [weak = AceType::WeakClaim(this)](int32_t fingers) {
89 auto panRecognizer = weak.Upgrade();
90 CHECK_NULL_VOID(panRecognizer);
91 panRecognizer->ChangeFingers(fingers);
92 };
93 onChangeFingers_ = OnPanFingersFunc(changeFingers);
94 panGestureOption_->SetOnPanFingersId(onChangeFingers_);
95
96 PanDirectionFuncType changeDirection = [weak = AceType::WeakClaim(this)](const PanDirection& direction) {
97 auto panRecognizer = weak.Upgrade();
98 CHECK_NULL_VOID(panRecognizer);
99 panRecognizer->ChangeDirection(direction);
100 };
101 onChangeDirection_ = OnPanDirectionFunc(changeDirection);
102 panGestureOption_->SetOnPanDirectionId(onChangeDirection_);
103
104 PanDistanceFuncType changeDistance = [weak = AceType::WeakClaim(this)](double distance) {
105 auto panRecognizer = weak.Upgrade();
106 CHECK_NULL_VOID(panRecognizer);
107 panRecognizer->ChangeDistance(distance);
108 };
109 onChangeDistance_ = OnPanDistanceFunc(changeDistance);
110 panGestureOption_->SetOnPanDistanceId(onChangeDistance_);
111 }
112
OnAccepted()113 void PanRecognizer::OnAccepted()
114 {
115 int64_t acceptTime = GetSysTimestamp();
116 int64_t inputTime = acceptTime;
117 if (firstInputTime_.has_value()) {
118 inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
119 }
120 if (SystemProperties::GetTraceInputEventEnabled()) {
121 ACE_SCOPED_TRACE("UserEvent InputTime:%lld AcceptTime:%lld InputType:PanGesture",
122 static_cast<long long>(inputTime), static_cast<long long>(acceptTime));
123 }
124
125 auto node = GetAttachedNode().Upgrade();
126 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Pan accepted, tag = %{public}s",
127 node ? node->GetTag().c_str() : "null");
128 refereeState_ = RefereeState::SUCCEED;
129 SendCallbackMsg(onActionStart_);
130 // only report the pan gesture starting for touch event
131 DispatchPanStartedToPerf(lastTouchEvent_);
132 if (IsEnabled()) {
133 isStartTriggered_ = true;
134 }
135 SendCallbackMsg(onActionUpdate_);
136 // if gesture is blocked by double click, recognizer will receive up before onAccepted
137 // in this case, recognizer need to send onActionEnd when onAccepted
138 if (isTouchEventFinished_) {
139 isStartTriggered_ = false;
140 SendCallbackMsg(onActionEnd_);
141 }
142 }
143
OnRejected()144 void PanRecognizer::OnRejected()
145 {
146 // fix griditem drag interrupted by click while pull moving
147 if (refereeState_ != RefereeState::SUCCEED) {
148 refereeState_ = RefereeState::FAIL;
149 }
150 SendRejectMsg();
151 firstInputTime_.reset();
152 }
153
UpdateTouchPointInVelocityTracker(const TouchEvent & touchEvent)154 void PanRecognizer::UpdateTouchPointInVelocityTracker(const TouchEvent& touchEvent)
155 {
156 auto updateTask = [this](const TouchEvent& event) {
157 bool end = event.type == TouchType::UP;
158 PointF windowPoint(event.x, event.y);
159 TouchEvent transformEvent = event;
160 auto container = Container::Current();
161 if (container && container->IsUIExtensionWindow()) {
162 auto historyEvent = Platform::GetTouchEventOriginOffset(end ? lastTouchEvent_ : event);
163 windowPoint.SetX(historyEvent.GetX());
164 windowPoint.SetY(historyEvent.GetY());
165 transformEvent.time = Platform::GetTouchEventOriginTimeStamp(end ? lastTouchEvent_ : event);
166 }
167 NGGestureRecognizer::Transform(windowPoint, GetAttachedNode(), false,
168 isPostEventResult_, event.postEventNodeId);
169
170 transformEvent.x = windowPoint.GetX();
171 transformEvent.y = windowPoint.GetY();
172 panVelocity_.UpdateTouchPoint(event.id, transformEvent, end);
173 };
174 if (touchEvent.history.empty()) {
175 updateTask(touchEvent);
176 return;
177 }
178 for (const auto& historyEvent: touchEvent.history) {
179 updateTask(historyEvent);
180 }
181 }
182
UpdateAxisPointInVelocityTracker(const AxisEvent & event,bool end)183 void PanRecognizer::UpdateAxisPointInVelocityTracker(const AxisEvent& event, bool end)
184 {
185 auto pesudoTouchEvent = TouchEvent();
186 pesudoTouchEvent.time = event.time;
187 auto revertAxisValue = event.ConvertToSummationAxisValue(lastAxisEvent_);
188 pesudoTouchEvent.x = revertAxisValue.first;
189 pesudoTouchEvent.y = revertAxisValue.second;
190 panVelocity_.UpdateTouchPoint(event.id, pesudoTouchEvent, end);
191 lastAxisEvent_ = event;
192 if (!end) {
193 lastAxisEvent_.horizontalAxis = pesudoTouchEvent.x;
194 lastAxisEvent_.verticalAxis = pesudoTouchEvent.y;
195 }
196 }
197
HandleTouchDownEvent(const TouchEvent & event)198 void PanRecognizer::HandleTouchDownEvent(const TouchEvent& event)
199 {
200 extraInfo_ = "";
201 isTouchEventFinished_ = false;
202 if (!firstInputTime_.has_value()) {
203 firstInputTime_ = event.time;
204 }
205
206 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d down, state: %{public}d", event.touchEventId,
207 event.id, refereeState_);
208 fingers_ = newFingers_;
209 distance_ = newDistance_;
210 direction_ = newDirection_;
211
212 if (direction_.type == PanDirection::NONE) {
213 auto node = GetAttachedNode().Upgrade();
214 TAG_LOGI(AceLogTag::ACE_GESTURE, "Pan recognizer direction is none, "
215 "node tag = %{public}s, id = " SEC_PLD(%{public}s) ".",
216 node ? node->GetTag().c_str() : "null",
217 SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
218 extraInfo_ += "direction is NONE.";
219 Adjudicate(Claim(this), GestureDisposal::REJECT);
220 return;
221 }
222 if (event.sourceType == SourceType::MOUSE && !isAllowMouse_) {
223 Adjudicate(Claim(this), GestureDisposal::REJECT);
224 extraInfo_ += "mouse event is not allowed.";
225 return;
226 }
227 if (!IsInAttachedNode(event)) {
228 Adjudicate(Claim(this), GestureDisposal::REJECT);
229 return;
230 }
231
232 if (fingersId_.find(event.id) == fingersId_.end()) {
233 fingersId_.insert(event.id);
234 }
235
236 deviceId_ = event.deviceId;
237 deviceType_ = event.sourceType;
238 lastTouchEvent_ = event;
239 touchPoints_[event.id] = event;
240 touchPointsDistance_[event.id] = Offset(0.0, 0.0);
241 auto fingerNum = static_cast<int32_t>(touchPoints_.size());
242
243 if (fingerNum >= fingers_) {
244 if (refereeState_ == RefereeState::READY) {
245 panVelocity_.Reset(event.id);
246 UpdateTouchPointInVelocityTracker(event);
247 refereeState_ = RefereeState::DETECTING;
248 } else {
249 TAG_LOGI(AceLogTag::ACE_GESTURE, "Pan gesture refereeState is not READY");
250 }
251 }
252 }
253
HandleTouchDownEvent(const AxisEvent & event)254 void PanRecognizer::HandleTouchDownEvent(const AxisEvent& event)
255 {
256 extraInfo_ = "";
257 isTouchEventFinished_ = false;
258 if (!firstInputTime_.has_value()) {
259 firstInputTime_ = event.time;
260 }
261 if (event.isRotationEvent) {
262 return;
263 }
264 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d axis start, state:%{public}d",
265 event.touchEventId, event.id, refereeState_);
266 fingers_ = newFingers_;
267 distance_ = newDistance_;
268 direction_ = newDirection_;
269
270 if (fingers_ != AXIS_PAN_FINGERS) {
271 extraInfo_ += "fingers does not meet the requirements of the axis event.";
272 Adjudicate(Claim(this), GestureDisposal::REJECT);
273 return;
274 }
275
276 if (direction_.type == PanDirection::NONE) {
277 extraInfo_ += "direction is NONE in axis case.";
278 Adjudicate(Claim(this), GestureDisposal::REJECT);
279 return;
280 }
281
282 deviceId_ = event.deviceId;
283 deviceType_ = event.sourceType;
284 lastAxisEvent_ = event;
285
286 touchPoints_[event.id] = TouchEvent();
287 UpdateTouchPointWithAxisEvent(event);
288 panVelocity_.Reset(event.id);
289 auto pesudoTouchEvent = TouchEvent();
290 pesudoTouchEvent.time = event.time;
291 auto revertAxisValue = event.ConvertToSummationAxisValue(lastAxisEvent_);
292 pesudoTouchEvent.x = revertAxisValue.first;
293 pesudoTouchEvent.y = revertAxisValue.second;
294 panVelocity_.UpdateTouchPoint(event.id, pesudoTouchEvent, false);
295 refereeState_ = RefereeState::DETECTING;
296 }
297
HandleTouchUpEvent(const TouchEvent & event)298 void PanRecognizer::HandleTouchUpEvent(const TouchEvent& event)
299 {
300 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d up, state: %{public}d", event.touchEventId,
301 event.id, refereeState_);
302 extraInfo_ = "currentFingers: " + std::to_string(currentFingers_) + " fingers: " + std::to_string(fingers_);
303 if (fingersId_.find(event.id) != fingersId_.end()) {
304 fingersId_.erase(event.id);
305 }
306 if (currentFingers_ < fingers_) {
307 return;
308 }
309
310 // In CrossPlatform, MOVE point has sampled, but the UP point is original coordinate,
311 // and participating in the Velocity calculation may cause abnormal rates
312 if (currentFingers_ == fingers_ && SystemProperties::IsNeedResampleTouchPoints()) {
313 UpdateTouchPointInVelocityTracker(event);
314 } else if (currentFingers_ > fingers_) {
315 panVelocity_.Reset(event.id);
316 UpdateTouchPointInVelocityTracker(event);
317 }
318
319 UpdateTouchEventInfo(event);
320
321 if ((currentFingers_ <= fingers_) &&
322 (refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
323 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
324 return;
325 }
326
327 if (refereeState_ == RefereeState::SUCCEED) {
328 if (currentFingers_ == fingers_) {
329 if (std::abs(panVelocity_.GetMainAxisVelocity()) <= MIN_SPEED_THRESHOLD) {
330 DumpVelocityInfo(event.id);
331 }
332 // last one to fire end.
333 isStartTriggered_ = false;
334 SendCallbackMsg(onActionEnd_);
335 averageDistance_.Reset();
336 AddOverTimeTrace();
337 refereeState_ = RefereeState::READY;
338 }
339 }
340
341 // Clear All fingers' velocity when fingersId is empty.
342 if (fingersId_.empty()) {
343 panVelocity_.ResetAll();
344 isTouchEventFinished_ = true;
345 }
346 }
347
HandleTouchUpEvent(const AxisEvent & event)348 void PanRecognizer::HandleTouchUpEvent(const AxisEvent& event)
349 {
350 isTouchEventFinished_ = false;
351 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d axis end, state: %{public}d",
352 event.touchEventId, event.id, refereeState_);
353 // if axisEvent received rotateEvent, no need to active Pan recognizer.
354 if (event.isRotationEvent) {
355 return;
356 }
357
358 if (event.sourceTool == SourceTool::MOUSE) {
359 delta_ = event.ConvertToOffset();
360 mainDelta_ = GetMainAxisDelta();
361 averageDistance_ += delta_;
362 }
363
364 globalPoint_ = Point(event.x, event.y);
365
366 touchPoints_[event.id] = TouchEvent();
367 UpdateTouchPointWithAxisEvent(event);
368 UpdateAxisPointInVelocityTracker(event, true);
369 time_ = event.time;
370
371 DumpVelocityInfo(event.id);
372 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW,
373 "PanVelocity main axis velocity is %{public}f", panVelocity_.GetMainAxisVelocity());
374
375 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
376 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
377 return;
378 }
379
380 if (refereeState_ == RefereeState::SUCCEED) {
381 // AxisEvent is single one.
382 isStartTriggered_ = false;
383 SendCallbackMsg(onActionEnd_);
384 AddOverTimeTrace();
385 }
386 panVelocity_.ResetAll();
387 }
388
HandleTouchMoveEvent(const TouchEvent & event)389 void PanRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
390 {
391 isTouchEventFinished_ = false;
392 if (static_cast<int32_t>(touchPoints_.size()) < fingers_) {
393 return;
394 }
395
396 UpdateTouchEventInfo(event);
397 UpdateTouchPointInVelocityTracker(event);
398 if (refereeState_ == RefereeState::DETECTING) {
399 auto result = IsPanGestureAccept();
400 if (result == GestureAcceptResult::ACCEPT) {
401 if (HandlePanAccept()) {
402 return;
403 }
404 } else if (result == GestureAcceptResult::REJECT) {
405 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
406 }
407 } else if (refereeState_ == RefereeState::SUCCEED) {
408 if ((direction_.type & PanDirection::VERTICAL) == 0) {
409 averageDistance_.SetY(0.0);
410 for (auto& element : touchPointsDistance_) {
411 element.second.SetY(0.0);
412 }
413 } else if ((direction_.type & PanDirection::HORIZONTAL) == 0) {
414 averageDistance_.SetX(0.0);
415 for (auto& element : touchPointsDistance_) {
416 element.second.SetX(0.0);
417 }
418 }
419 if (isFlushTouchEventsEnd_) {
420 if (!isStartTriggered_ && IsEnabled()) {
421 SendCallbackMsg(onActionStart_);
422 isStartTriggered_ = true;
423 }
424 if (static_cast<int32_t>(touchPoints_.size()) > fingers_ && isLimitFingerCount_) {
425 return;
426 }
427 SendCallbackMsg(onActionUpdate_);
428 }
429 }
430 }
431
OnFlushTouchEventsBegin()432 void PanRecognizer::OnFlushTouchEventsBegin()
433 {
434 isFlushTouchEventsEnd_ = false;
435 }
436
OnFlushTouchEventsEnd()437 void PanRecognizer::OnFlushTouchEventsEnd()
438 {
439 isFlushTouchEventsEnd_ = true;
440 }
441
HandleTouchMoveEvent(const AxisEvent & event)442 void PanRecognizer::HandleTouchMoveEvent(const AxisEvent& event)
443 {
444 isTouchEventFinished_ = false;
445 if (fingers_ != AXIS_PAN_FINGERS || event.isRotationEvent) {
446 return;
447 }
448
449 auto pipeline = PipelineContext::GetCurrentContext();
450 bool isShiftKeyPressed = false;
451 bool hasDifferentDirectionGesture = false;
452 if (pipeline) {
453 isShiftKeyPressed =
454 pipeline->IsKeyInPressed(KeyCode::KEY_SHIFT_LEFT) || pipeline->IsKeyInPressed(KeyCode::KEY_SHIFT_RIGHT);
455 hasDifferentDirectionGesture = pipeline->HasDifferentDirectionGesture();
456 }
457 delta_ = event.ConvertToOffset(isShiftKeyPressed, hasDifferentDirectionGesture);
458 if (event.sourceTool == SourceTool::MOUSE) {
459 if ((direction_.type & PanDirection::HORIZONTAL) == 0) { // Direction is vertical
460 delta_.SetX(0.0);
461 } else if ((direction_.type & PanDirection::VERTICAL) == 0) { // Direction is horizontal
462 delta_.SetY(0.0);
463 }
464 }
465
466 globalPoint_ = Point(event.x, event.y);
467 mainDelta_ = GetMainAxisDelta();
468 averageDistance_ += delta_;
469
470 UpdateTouchPointWithAxisEvent(event);
471 UpdateAxisPointInVelocityTracker(event);
472 time_ = event.time;
473
474 if (refereeState_ == RefereeState::DETECTING) {
475 auto result = IsPanGestureAccept();
476 if (result == GestureAcceptResult::ACCEPT) {
477 if (HandlePanAccept()) {
478 return;
479 }
480 } else if (result == GestureAcceptResult::REJECT) {
481 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
482 }
483 } else if (refereeState_ == RefereeState::SUCCEED) {
484 if ((direction_.type & PanDirection::VERTICAL) == 0) {
485 averageDistance_.SetY(0.0);
486 } else if ((direction_.type & PanDirection::HORIZONTAL) == 0) {
487 averageDistance_.SetX(0.0);
488 }
489 if (!isStartTriggered_ && IsEnabled()) {
490 SendCallbackMsg(onActionStart_);
491 isStartTriggered_ = true;
492 }
493 SendCallbackMsg(onActionUpdate_);
494 }
495 }
496
HandlePanAccept()497 bool PanRecognizer::HandlePanAccept()
498 {
499 if (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::DRAG) {
500 auto dragEventActuator = GetDragEventActuator();
501 CHECK_NULL_RETURN(dragEventActuator, true);
502 if (dragEventActuator->IsDragUserReject()) {
503 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
504 return true;
505 }
506 }
507 if (TriggerGestureJudgeCallback() == GestureJudgeResult::REJECT) {
508 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
509 if (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::DRAG) {
510 auto dragEventActuator = GetDragEventActuator();
511 CHECK_NULL_RETURN(dragEventActuator, true);
512 dragEventActuator->SetIsDragUserReject(true);
513 }
514 return true;
515 }
516 if (CheckLimitFinger()) {
517 return false;
518 }
519 if (IsBridgeMode()) {
520 OnAccepted();
521 return false;
522 }
523 Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
524 return false;
525 }
526
HandleTouchCancelEvent(const TouchEvent & event)527 void PanRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
528 {
529 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d cancel", event.touchEventId, event.id);
530 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
531 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
532 return;
533 }
534
535 if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) == fingers_) {
536 // AxisEvent is single one.
537 SendCancelMsg();
538 refereeState_ = RefereeState::READY;
539 }
540 }
541
HandleTouchCancelEvent(const AxisEvent & event)542 void PanRecognizer::HandleTouchCancelEvent(const AxisEvent& event)
543 {
544 isTouchEventFinished_ = false;
545 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan axis cancel", event.touchEventId);
546 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
547 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
548 return;
549 }
550
551 if (refereeState_ == RefereeState::SUCCEED) {
552 SendCancelMsg();
553 }
554 }
555
CalculateTruthFingers(bool isDirectionUp) const556 bool PanRecognizer::CalculateTruthFingers(bool isDirectionUp) const
557 {
558 float totalDistance = 0.0f;
559 for (auto& element : touchPointsDistance_) {
560 auto each_point_move = element.second.GetY();
561 if (GreatNotEqual(each_point_move, 0.0) && isDirectionUp) {
562 totalDistance += each_point_move;
563 } else if (LessNotEqual(each_point_move, 0.0) && !isDirectionUp) {
564 totalDistance -= each_point_move;
565 }
566 }
567 auto judgeDistance = distance_;
568 if (deviceType_ == SourceType::MOUSE) {
569 judgeDistance = mouseDistance_;
570 }
571 return GreatNotEqual(totalDistance, judgeDistance) && static_cast<int32_t>(touchPointsDistance_.size()) >= fingers_;
572 }
573
IsPanGestureAccept() const574 PanRecognizer::GestureAcceptResult PanRecognizer::IsPanGestureAccept() const
575 {
576 auto judgeDistance = deviceType_ == SourceType::MOUSE ? mouseDistance_ : distance_;
577 if ((direction_.type & PanDirection::ALL) == PanDirection::ALL) {
578 double offset = averageDistance_.GetDistance();
579 if (fabs(offset) < judgeDistance) {
580 return GestureAcceptResult::DETECTING;
581 }
582 return GestureAcceptResult::ACCEPT;
583 }
584
585 if (fabs(averageDistance_.GetX()) > fabs(averageDistance_.GetY())) {
586 if ((direction_.type & PanDirection::HORIZONTAL) != 0) {
587 double offset = averageDistance_.GetX();
588 if (fabs(offset) < judgeDistance) {
589 return GestureAcceptResult::DETECTING;
590 }
591 if ((direction_.type & PanDirection::LEFT) == 0 && offset < 0) {
592 return GestureAcceptResult::REJECT;
593 }
594 if ((direction_.type & PanDirection::RIGHT) == 0 && offset > 0) {
595 return GestureAcceptResult::REJECT;
596 }
597 return GestureAcceptResult::ACCEPT;
598 }
599 return GestureAcceptResult::DETECTING;
600 }
601 if ((direction_.type & PanDirection::VERTICAL) != 0) {
602 double offset = averageDistance_.GetY();
603 if (fabs(offset) < judgeDistance) {
604 return GestureAcceptResult::DETECTING;
605 }
606 if (inputEventType_ == InputEventType::AXIS) {
607 if ((direction_.type & PanDirection::UP) == 0 && offset < 0) {
608 return GestureAcceptResult::REJECT;
609 }
610 if ((direction_.type & PanDirection::DOWN) == 0 && offset > 0) {
611 return GestureAcceptResult::REJECT;
612 }
613 } else {
614 if ((direction_.type & PanDirection::UP) == 0) {
615 return CalculateTruthFingers(true) ? GestureAcceptResult::ACCEPT : GestureAcceptResult::REJECT;
616 }
617 if ((direction_.type & PanDirection::DOWN) == 0) {
618 return CalculateTruthFingers(false) ? GestureAcceptResult::ACCEPT : GestureAcceptResult::REJECT;
619 }
620 }
621 return GestureAcceptResult::ACCEPT;
622 }
623 return GestureAcceptResult::DETECTING;
624 }
625
GetRawGlobalLocation(int32_t postEventNodeId)626 Offset PanRecognizer::GetRawGlobalLocation(int32_t postEventNodeId)
627 {
628 PointF localPoint(globalPoint_.GetX(), globalPoint_.GetY());
629 if (!lastTouchEvent_.history.empty() && (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::BOXSELECT)) {
630 auto lastPoint = lastTouchEvent_.history.back();
631 PointF rawLastPoint(lastPoint.GetOffset().GetX(), lastPoint.GetOffset().GetY());
632 NGGestureRecognizer::Transform(
633 rawLastPoint, GetAttachedNode(), false, isPostEventResult_, postEventNodeId);
634 return Offset(rawLastPoint.GetX(), rawLastPoint.GetY());
635 }
636 NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
637 isPostEventResult_, postEventNodeId);
638 return Offset(localPoint.GetX(), localPoint.GetY());
639 }
640
OnResetStatus()641 void PanRecognizer::OnResetStatus()
642 {
643 MultiFingersRecognizer::OnResetStatus();
644 touchPoints_.clear();
645 averageDistance_.Reset();
646 touchPointsDistance_.clear();
647 isStartTriggered_ = false;
648 }
649
OnSucceedCancel()650 void PanRecognizer::OnSucceedCancel()
651 {
652 SendCancelMsg();
653 }
654
GetGestureEventInfo()655 GestureEvent PanRecognizer::GetGestureEventInfo()
656 {
657 GestureEvent info;
658 info.SetTimeStamp(time_);
659 UpdateFingerListInfo();
660 info.SetDeviceId(deviceId_);
661 info.SetFingerList(fingerList_);
662 info.SetSourceDevice(deviceType_);
663 info.SetOffsetX((direction_.type & PanDirection::HORIZONTAL) == 0 ? 0.0 : averageDistance_.GetX());
664 info.SetOffsetY((direction_.type & PanDirection::VERTICAL) == 0 ? 0.0 : averageDistance_.GetY());
665 info.SetDelta(delta_);
666 info.SetVelocity(panVelocity_.GetVelocity());
667 info.SetMainVelocity(panVelocity_.GetMainAxisVelocity());
668 TouchEvent touchPoint = {};
669 if (!touchPoints_.empty()) {
670 touchPoint = touchPoints_.begin()->second;
671 }
672 PointF localPoint(globalPoint_.GetX(), globalPoint_.GetY());
673 NGGestureRecognizer::Transform(
674 localPoint, GetAttachedNode(), false, isPostEventResult_, touchPoint.postEventNodeId);
675 info.SetRawGlobalLocation(GetRawGlobalLocation(touchPoint.postEventNodeId));
676 info.SetPointerId(touchPoint.id);
677 info.SetTargetDisplayId(touchPoint.targetDisplayId);
678 info.SetIsInterpolated(touchPoint.isInterpolated);
679 info.SetInputXDeltaSlope(touchPoint.inputXDeltaSlope);
680 info.SetInputYDeltaSlope(touchPoint.inputYDeltaSlope);
681 info.SetMainDelta(mainDelta_ / static_cast<double>(touchPoints_.size()));
682 if (inputEventType_ == InputEventType::AXIS) {
683 info.SetScreenLocation(lastAxisEvent_.GetScreenOffset());
684 info.SetSourceTool(lastAxisEvent_.sourceTool);
685 info.SetVerticalAxis(lastAxisEvent_.verticalAxis);
686 info.SetHorizontalAxis(lastAxisEvent_.horizontalAxis);
687 info.SetPressedKeyCodes(lastAxisEvent_.pressedCodes);
688 info.SetPointerEventId(lastAxisEvent_.touchEventId);
689 } else {
690 info.SetScreenLocation(lastTouchEvent_.GetScreenOffset());
691 info.SetSourceTool(lastTouchEvent_.sourceTool);
692 info.SetPressedKeyCodes(lastTouchEvent_.pressedKeyCodes_);
693 info.SetPointerEventId(lastTouchEvent_.touchEventId);
694 }
695 info.SetGlobalPoint(globalPoint_).SetLocalLocation(Offset(localPoint.GetX(), localPoint.GetY()));
696 info.SetTarget(GetEventTarget().value_or(EventTarget()));
697 info.SetInputEventType(inputEventType_);
698 info.SetForce(lastTouchEvent_.force);
699 info.SetTiltX(lastTouchEvent_.tiltX.value_or(0.0));
700 info.SetTiltY(lastTouchEvent_.tiltY.value_or(0.0));
701 info.SetPointerEvent(lastPointEvent_);
702 info.SetIsPostEventResult(isPostEventResult_);
703 info.SetPostEventNodeId(lastTouchEvent_.postEventNodeId);
704 return info;
705 }
706
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & callback)707 void PanRecognizer::SendCallbackMsg(const std::unique_ptr<GestureEventFunc>& callback)
708 {
709 if (callback && *callback && IsEnabled() && (!gestureInfo_ || !gestureInfo_->GetDisposeTag())) {
710 GestureEvent info = GetGestureEventInfo();
711 // callback may be overwritten in its invoke so we copy it first
712 auto callbackFunction = *callback;
713 callbackFunction(info);
714 }
715 }
716
TriggerGestureJudgeCallback()717 GestureJudgeResult PanRecognizer::TriggerGestureJudgeCallback()
718 {
719 auto targetComponent = GetTargetComponent();
720 CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
721 auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
722 auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
723 auto callbackNative = targetComponent->GetOnGestureJudgeNativeBeginCallback();
724 if (!callback && !callbackNative && !sysJudge_ && !gestureRecognizerJudgeFunc) {
725 return GestureJudgeResult::CONTINUE;
726 }
727 auto info = std::make_shared<PanGestureEvent>();
728 UpdateFingerListInfo();
729 info->SetFingerList(fingerList_);
730 info->SetTimeStamp(time_);
731 info->SetDeviceId(deviceId_);
732 info->SetOffsetX((direction_.type & PanDirection::HORIZONTAL) == 0 ? 0.0 : averageDistance_.GetX());
733 info->SetOffsetY((direction_.type & PanDirection::VERTICAL) == 0 ? 0.0 : averageDistance_.GetY());
734 info->SetSourceDevice(deviceType_);
735 if (inputEventType_ == InputEventType::AXIS) {
736 info->SetVelocity(Velocity());
737 info->SetMainVelocity(0.0);
738 info->SetSourceTool(lastAxisEvent_.sourceTool);
739 } else {
740 info->SetVelocity(panVelocity_.GetVelocity());
741 info->SetMainVelocity(panVelocity_.GetMainAxisVelocity());
742 info->SetSourceTool(lastTouchEvent_.sourceTool);
743 }
744 info->SetTarget(GetEventTarget().value_or(EventTarget()));
745 info->SetForce(lastTouchEvent_.force);
746 if (lastTouchEvent_.tiltX.has_value()) {
747 info->SetTiltX(lastTouchEvent_.tiltX.value());
748 }
749 if (lastTouchEvent_.tiltY.has_value()) {
750 info->SetTiltY(lastTouchEvent_.tiltY.value());
751 }
752 if (gestureInfo_) {
753 gestureInfo_->SetInputEventType(inputEventType_);
754 }
755 if (gestureRecognizerJudgeFunc &&
756 gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_) == GestureJudgeResult::REJECT) {
757 return GestureJudgeResult::REJECT;
758 }
759 if (!gestureRecognizerJudgeFunc && callback && callback(gestureInfo_, info) == GestureJudgeResult::REJECT) {
760 // If outer callback exits, prioritize checking outer callback. If outer reject, return reject.
761 return GestureJudgeResult::REJECT;
762 }
763 if (callbackNative && callbackNative(gestureInfo_, info) == GestureJudgeResult::REJECT) {
764 // If outer callback doesn't exit or accept, check inner callback. If inner reject, return reject.
765 return GestureJudgeResult::REJECT;
766 }
767 if (sysJudge_ && sysJudge_(gestureInfo_, info) == GestureJudgeResult::REJECT) {
768 return GestureJudgeResult::REJECT;
769 }
770 return GestureJudgeResult::CONTINUE;
771 }
772
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)773 bool PanRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
774 {
775 RefPtr<PanRecognizer> curr = AceType::DynamicCast<PanRecognizer>(recognizer);
776 if (!curr) {
777 ResetStatus();
778 return false;
779 }
780
781 if (curr->fingers_ != fingers_ || curr->priorityMask_ != priorityMask_) {
782 if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) >= fingers_) {
783 SendCancelMsg();
784 }
785 ResetStatus();
786 return false;
787 }
788
789 direction_.type = curr->direction_.type;
790 newDirection_.type = curr->newDirection_.type;
791 distance_ = curr->distance_;
792 newDistance_ = curr->newDistance_;
793 mouseDistance_ = curr->mouseDistance_;
794
795 onActionStart_ = std::move(curr->onActionStart_);
796 onActionUpdate_ = std::move(curr->onActionUpdate_);
797 onActionEnd_ = std::move(curr->onActionEnd_);
798 onActionCancel_ = std::move(curr->onActionCancel_);
799 ReconcileGestureInfoFrom(recognizer);
800 return true;
801 }
802
GetAxisDirection()803 Axis PanRecognizer::GetAxisDirection()
804 {
805 auto hasHorizontal = direction_.type & PanDirection::HORIZONTAL;
806 auto hasVertical = direction_.type & PanDirection::VERTICAL;
807 if (direction_.type == PanDirection::ALL || (hasHorizontal && hasVertical)) {
808 return Axis::FREE;
809 }
810 if (hasHorizontal) {
811 return Axis::HORIZONTAL;
812 }
813 if (hasVertical) {
814 return Axis::VERTICAL;
815 }
816 return Axis::NONE;
817 }
818
SetDirection(const PanDirection & direction)819 void PanRecognizer::SetDirection(const PanDirection& direction)
820 {
821 ChangeDirection(direction);
822 panVelocity_.SetDirection(direction_.type);
823 panVelocity_.SetDirection(direction_.type);
824 }
825
ChangeFingers(int32_t fingers)826 void PanRecognizer::ChangeFingers(int32_t fingers)
827 {
828 if (fingers_ != fingers) {
829 newFingers_ = fingers;
830 }
831 }
832
ChangeDirection(const PanDirection & direction)833 void PanRecognizer::ChangeDirection(const PanDirection& direction)
834 {
835 if (direction_.type != direction.type) {
836 direction_.type = direction.type;
837 newDirection_.type = direction.type;
838 }
839 }
840
ChangeDistance(double distance)841 void PanRecognizer::ChangeDistance(double distance)
842 {
843 if (distance_ != distance) {
844 if (refereeState_ == RefereeState::READY || refereeState_ == RefereeState::DETECTING) {
845 distance_ = distance;
846 }
847 newDistance_ = distance;
848 mouseDistance_ = distance;
849 }
850 }
851
GetMainAxisDelta()852 double PanRecognizer::GetMainAxisDelta()
853 {
854 switch (direction_.type) {
855 case PanDirection::ALL:
856 return delta_.GetDistance();
857 case PanDirection::HORIZONTAL:
858 return delta_.GetX();
859 case PanDirection::VERTICAL:
860 return delta_.GetY();
861 default:
862 return 0.0;
863 }
864 }
865
Dump() const866 RefPtr<GestureSnapshot> PanRecognizer::Dump() const
867 {
868 RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
869 std::stringstream oss;
870 oss << "direction: " << direction_.type << ", "
871 << "isForDrag: " << isForDrag_ << ", "
872 << "distance: " << distance_ << ", "
873 << "fingers: " << fingers_ << ", "
874 << DumpGestureInfo();
875 info->customInfo = oss.str();
876 return info;
877 }
878
GetDragEventActuator()879 RefPtr<DragEventActuator> PanRecognizer::GetDragEventActuator()
880 {
881 auto targetComponent = GetTargetComponent();
882 CHECK_NULL_RETURN(targetComponent, nullptr);
883 auto uiNode = targetComponent->GetUINode().Upgrade();
884 CHECK_NULL_RETURN(uiNode, nullptr);
885 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
886 CHECK_NULL_RETURN(frameNode, nullptr);
887 auto gestureEventHub = frameNode->GetOrCreateGestureEventHub();
888 CHECK_NULL_RETURN(gestureEventHub, nullptr);
889 return gestureEventHub->GetDragEventActuator();
890 }
891
GetFastestTracker(std::function<double (VelocityTracker &)> && func)892 int32_t PanRecognizer::PanVelocity::GetFastestTracker(std::function<double(VelocityTracker&)>&& func)
893 {
894 int32_t maxId = -1;
895 double maxV = 0.0;
896 for (auto& [id, tracker] : trackerMap_) {
897 double v = std::abs(func(tracker));
898 if (v > maxV) {
899 maxId = id;
900 maxV = v;
901 }
902 }
903 return maxId;
904 }
905
GetVelocity()906 Velocity PanRecognizer::PanVelocity::GetVelocity()
907 {
908 auto&& func = [](VelocityTracker& tracker) { return tracker.GetVelocity().GetVelocityValue(); };
909 int32_t id = GetFastestTracker(func);
910 return (id != -1) ? trackerMap_[id].GetVelocity() : Velocity();
911 }
912
GetMainAxisVelocity()913 double PanRecognizer::PanVelocity::GetMainAxisVelocity()
914 {
915 auto&& func = [axis = axis_](VelocityTracker& tracker) {
916 tracker.SetMainAxis(axis);
917 return tracker.GetMainAxisVelocity();
918 };
919 int32_t id = GetFastestTracker(func);
920 return (id != -1) ? trackerMap_[id].GetMainAxisVelocity() : 0.0;
921 }
922
UpdateTouchPoint(int32_t id,const TouchEvent & event,bool end)923 void PanRecognizer::PanVelocity::UpdateTouchPoint(int32_t id, const TouchEvent& event, bool end)
924 {
925 trackerMap_[id].UpdateTouchPoint(event, end);
926 }
927
Reset(int32_t id)928 void PanRecognizer::PanVelocity::Reset(int32_t id)
929 {
930 trackerMap_.erase(id);
931 }
932
ResetAll()933 void PanRecognizer::PanVelocity::ResetAll()
934 {
935 trackerMap_.clear();
936 }
937
SetDirection(int32_t directionType)938 void PanRecognizer::PanVelocity::SetDirection(int32_t directionType)
939 {
940 auto axis = Axis::FREE;
941 if ((directionType & PanDirection::VERTICAL) == 0) {
942 axis = Axis::HORIZONTAL;
943 } else if ((directionType & PanDirection::HORIZONTAL) == 0) {
944 axis = Axis::VERTICAL;
945 }
946 axis_ = axis;
947 }
948
AddOverTimeTrace()949 void PanRecognizer::AddOverTimeTrace()
950 {
951 int64_t overTime = GetSysTimestamp();
952 int64_t inputTime = overTime;
953 if (firstInputTime_.has_value()) {
954 inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
955 }
956 if (SystemProperties::GetTraceInputEventEnabled()) {
957 ACE_SCOPED_TRACE("UserEvent InputTime:%lld OverTime:%lld InputType:PanGesture",
958 static_cast<long long>(inputTime), static_cast<long long>(overTime));
959 }
960 firstInputTime_.reset();
961 }
962
UpdateTouchEventInfo(const TouchEvent & event)963 void PanRecognizer::UpdateTouchEventInfo(const TouchEvent& event)
964 {
965 globalPoint_ = Point(event.x, event.y);
966 lastTouchEvent_ = event;
967 PointF windowPoint(event.GetOffset().GetX(), event.GetOffset().GetY());
968 PointF windowTouchPoint(touchPoints_[event.id].GetOffset().GetX(), touchPoints_[event.id].GetOffset().GetY());
969 NGGestureRecognizer::Transform(windowPoint, GetAttachedNode(), false,
970 isPostEventResult_, event.postEventNodeId);
971 NGGestureRecognizer::Transform(windowTouchPoint, GetAttachedNode(), false,
972 isPostEventResult_, event.postEventNodeId);
973 delta_ =
974 (Offset(windowPoint.GetX(), windowPoint.GetY()) - Offset(windowTouchPoint.GetX(), windowTouchPoint.GetY()));
975
976 if (SystemProperties::GetDebugEnabled()) {
977 TAG_LOGD(AceLogTag::ACE_GESTURE, "Delta is x %{public}f, y %{public}f ", delta_.GetX(), delta_.GetY());
978 }
979 mainDelta_ = GetMainAxisDelta();
980 averageDistance_ += delta_ / static_cast<double>(touchPoints_.size());
981 touchPoints_[event.id] = event;
982 touchPointsDistance_[event.id] += delta_;
983 time_ = event.time;
984 }
985
DispatchPanStartedToPerf(const TouchEvent & event)986 void PanRecognizer::DispatchPanStartedToPerf(const TouchEvent& event)
987 {
988 int64_t inputTime = event.time.time_since_epoch().count();
989 if (inputTime <= 0 || event.sourceType != SourceType::TOUCH) {
990 return;
991 }
992 PerfMonitor* pMonitor = PerfMonitor::GetPerfMonitor();
993 if (pMonitor == nullptr) {
994 return;
995 }
996 pMonitor->RecordInputEvent(FIRST_MOVE, PERF_TOUCH_EVENT, inputTime);
997 }
998
DumpVelocityInfo(int32_t fingerId)999 void PanRecognizer::DumpVelocityInfo(int32_t fingerId)
1000 {
1001 auto velocityTrackerIter = panVelocity_.GetVelocityMap().find(fingerId);
1002 if (velocityTrackerIter != panVelocity_.GetVelocityMap().end()) {
1003 velocityTrackerIter->second.DumpVelocityPoints();
1004 } else {
1005 TAG_LOGI(AceLogTag::ACE_GESTURE, "Dump velocity fail with fingerId:%{public}d", fingerId);
1006 }
1007 }
1008 } // namespace OHOS::Ace::NG
1009