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)48 PanRecognizer::PanRecognizer(int32_t fingers, const PanDirection& direction, double distance)
49 : MultiFingersRecognizer(fingers), direction_(direction), distance_(distance), mouseDistance_(distance),
50 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_);
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
71 distance_ = LessNotEqual(distanceNumber, 0.0) ? DEFAULT_PAN_DISTANCE.ConvertToPx() : distanceNumber;
72 fingers_ = fingersNumber;
73 if (fingers_ > MAX_PAN_FINGERS || fingers_ < DEFAULT_PAN_FINGERS) {
74 fingers_ = DEFAULT_PAN_FINGERS;
75 }
76
77 if (directNum >= PanDirection::NONE && directNum <= PanDirection::ALL) {
78 direction_.type = directNum;
79 }
80
81 newFingers_ = fingers_;
82 newDistance_ = distance_;
83 mouseDistance_ = distance_;
84 newDirection_ = direction_;
85
86 PanFingersFuncType changeFingers = [weak = AceType::WeakClaim(this)](int32_t fingers) {
87 auto panRecognizer = weak.Upgrade();
88 CHECK_NULL_VOID(panRecognizer);
89 panRecognizer->ChangeFingers(fingers);
90 };
91 onChangeFingers_ = OnPanFingersFunc(changeFingers);
92 panGestureOption_->SetOnPanFingersId(onChangeFingers_);
93
94 PanDirectionFuncType changeDirection = [weak = AceType::WeakClaim(this)](const PanDirection& direction) {
95 auto panRecognizer = weak.Upgrade();
96 CHECK_NULL_VOID(panRecognizer);
97 panRecognizer->ChangeDirection(direction);
98 };
99 onChangeDirection_ = OnPanDirectionFunc(changeDirection);
100 panGestureOption_->SetOnPanDirectionId(onChangeDirection_);
101
102 PanDistanceFuncType changeDistance = [weak = AceType::WeakClaim(this)](double distance) {
103 auto panRecognizer = weak.Upgrade();
104 CHECK_NULL_VOID(panRecognizer);
105 panRecognizer->ChangeDistance(distance);
106 };
107 onChangeDistance_ = OnPanDistanceFunc(changeDistance);
108 panGestureOption_->SetOnPanDistanceId(onChangeDistance_);
109 }
110
OnAccepted()111 void PanRecognizer::OnAccepted()
112 {
113 int64_t acceptTime = GetSysTimestamp();
114 int64_t inputTime = acceptTime;
115 if (firstInputTime_.has_value()) {
116 inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
117 }
118 if (SystemProperties::GetTraceInputEventEnabled()) {
119 ACE_SCOPED_TRACE("UserEvent InputTime:%lld AcceptTime:%lld InputType:PanGesture",
120 static_cast<long long>(inputTime), static_cast<long long>(acceptTime));
121 }
122
123 auto node = GetAttachedNode().Upgrade();
124 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Pan accepted, tag = %{public}s",
125 node ? node->GetTag().c_str() : "null");
126 refereeState_ = RefereeState::SUCCEED;
127 SendCallbackMsg(onActionStart_);
128 // only report the pan gesture starting for touch event
129 DispatchPanStartedToPerf(lastTouchEvent_);
130 if (IsEnabled()) {
131 isStartTriggered_ = true;
132 }
133 SendCallbackMsg(onActionUpdate_);
134 // if gesture is blocked by double click, recognizer will receive up before onAccepted
135 // in this case, recognizer need to send onActionEnd when onAccepted
136 if (isTouchEventFinished_) {
137 isStartTriggered_ = false;
138 SendCallbackMsg(onActionEnd_);
139 }
140 }
141
OnRejected()142 void PanRecognizer::OnRejected()
143 {
144 // fix griditem drag interrupted by click while pull moving
145 if (refereeState_ != RefereeState::SUCCEED) {
146 refereeState_ = RefereeState::FAIL;
147 }
148 SendRejectMsg();
149 firstInputTime_.reset();
150 }
151
UpdateTouchPointInVelocityTracker(const TouchEvent & touchEvent)152 void PanRecognizer::UpdateTouchPointInVelocityTracker(const TouchEvent& touchEvent)
153 {
154 auto updateTask = [this](const TouchEvent& event) {
155 bool end = event.type == TouchType::UP;
156 PointF windowPoint(event.x, event.y);
157 TouchEvent transformEvent = event;
158 auto container = Container::Current();
159 if (container && container->IsUIExtensionWindow()) {
160 auto historyEvent = Platform::GetTouchEventOriginOffset(end ? lastTouchEvent_ : event);
161 windowPoint.SetX(historyEvent.GetX());
162 windowPoint.SetY(historyEvent.GetY());
163 transformEvent.time = Platform::GetTouchEventOriginTimeStamp(end ? lastTouchEvent_ : event);
164 }
165 NGGestureRecognizer::Transform(windowPoint, GetAttachedNode(), false,
166 isPostEventResult_, event.postEventNodeId);
167
168 transformEvent.x = windowPoint.GetX();
169 transformEvent.y = windowPoint.GetY();
170 panVelocity_.UpdateTouchPoint(event.id, transformEvent, end);
171 };
172 if (touchEvent.history.empty()) {
173 updateTask(touchEvent);
174 return;
175 }
176 for (const auto& historyEvent: touchEvent.history) {
177 updateTask(historyEvent);
178 }
179 }
180
UpdateAxisPointInVelocityTracker(const AxisEvent & event,bool end)181 void PanRecognizer::UpdateAxisPointInVelocityTracker(const AxisEvent& event, bool end)
182 {
183 auto pesudoTouchEvent = TouchEvent();
184 pesudoTouchEvent.time = event.time;
185 auto revertAxisValue = event.ConvertToSummationAxisValue(lastAxisEvent_);
186 pesudoTouchEvent.x = revertAxisValue.first;
187 pesudoTouchEvent.y = revertAxisValue.second;
188 panVelocity_.UpdateTouchPoint(event.id, pesudoTouchEvent, end);
189 lastAxisEvent_ = event;
190 if (!end) {
191 lastAxisEvent_.horizontalAxis = pesudoTouchEvent.x;
192 lastAxisEvent_.verticalAxis = pesudoTouchEvent.y;
193 }
194 }
195
HandleTouchDownEvent(const TouchEvent & event)196 void PanRecognizer::HandleTouchDownEvent(const TouchEvent& event)
197 {
198 extraInfo_ = "";
199 isTouchEventFinished_ = false;
200 if (!firstInputTime_.has_value()) {
201 firstInputTime_ = event.time;
202 }
203
204 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d down, state: %{public}d", event.touchEventId,
205 event.id, refereeState_);
206 fingers_ = newFingers_;
207 distance_ = newDistance_;
208 direction_ = newDirection_;
209
210 if (direction_.type == PanDirection::NONE) {
211 auto node = GetAttachedNode().Upgrade();
212 TAG_LOGI(AceLogTag::ACE_GESTURE, "Pan recognizer direction is none, "
213 "node tag = %{public}s, id = " SEC_PLD(%{public}s) ".",
214 node ? node->GetTag().c_str() : "null",
215 SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
216 extraInfo_ += "direction is NONE.";
217 Adjudicate(Claim(this), GestureDisposal::REJECT);
218 return;
219 }
220 if (event.sourceType == SourceType::MOUSE && !isAllowMouse_) {
221 Adjudicate(Claim(this), GestureDisposal::REJECT);
222 extraInfo_ += "mouse event is not allowed.";
223 return;
224 }
225 if (!IsInAttachedNode(event)) {
226 Adjudicate(Claim(this), GestureDisposal::REJECT);
227 return;
228 }
229
230 if (fingersId_.find(event.id) == fingersId_.end()) {
231 fingersId_.insert(event.id);
232 }
233
234 deviceId_ = event.deviceId;
235 deviceType_ = event.sourceType;
236 lastTouchEvent_ = event;
237 touchPoints_[event.id] = event;
238 touchPointsDistance_[event.id] = Offset(0.0, 0.0);
239 auto fingerNum = static_cast<int32_t>(touchPoints_.size());
240
241 if (fingerNum >= fingers_) {
242 if (refereeState_ == RefereeState::READY) {
243 panVelocity_.Reset(event.id);
244 UpdateTouchPointInVelocityTracker(event);
245 refereeState_ = RefereeState::DETECTING;
246 } else {
247 TAG_LOGI(AceLogTag::ACE_GESTURE, "Pan gesture refereeState is not READY");
248 }
249 }
250 }
251
HandleTouchDownEvent(const AxisEvent & event)252 void PanRecognizer::HandleTouchDownEvent(const AxisEvent& event)
253 {
254 extraInfo_ = "";
255 isTouchEventFinished_ = false;
256 if (!firstInputTime_.has_value()) {
257 firstInputTime_ = event.time;
258 }
259 if (event.isRotationEvent) {
260 return;
261 }
262 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d axis start, state:%{public}d",
263 event.touchEventId, event.id, refereeState_);
264 fingers_ = newFingers_;
265 distance_ = newDistance_;
266 direction_ = newDirection_;
267
268 if (fingers_ != AXIS_PAN_FINGERS) {
269 extraInfo_ += "fingers does not meet the requirements of the axis event.";
270 Adjudicate(Claim(this), GestureDisposal::REJECT);
271 return;
272 }
273
274 if (direction_.type == PanDirection::NONE) {
275 extraInfo_ += "direction is NONE in axis case.";
276 Adjudicate(Claim(this), GestureDisposal::REJECT);
277 return;
278 }
279
280 deviceId_ = event.deviceId;
281 deviceType_ = event.sourceType;
282 lastAxisEvent_ = event;
283
284 touchPoints_[event.id] = TouchEvent();
285 UpdateTouchPointWithAxisEvent(event);
286 panVelocity_.Reset(event.id);
287 auto pesudoTouchEvent = TouchEvent();
288 pesudoTouchEvent.time = event.time;
289 auto revertAxisValue = event.ConvertToSummationAxisValue(lastAxisEvent_);
290 pesudoTouchEvent.x = revertAxisValue.first;
291 pesudoTouchEvent.y = revertAxisValue.second;
292 panVelocity_.UpdateTouchPoint(event.id, pesudoTouchEvent, false);
293 refereeState_ = RefereeState::DETECTING;
294 }
295
HandleTouchUpEvent(const TouchEvent & event)296 void PanRecognizer::HandleTouchUpEvent(const TouchEvent& event)
297 {
298 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d up, state: %{public}d", event.touchEventId,
299 event.id, refereeState_);
300 extraInfo_ = "currentFingers: " + std::to_string(currentFingers_) + " fingers: " + std::to_string(fingers_);
301 if (fingersId_.find(event.id) != fingersId_.end()) {
302 fingersId_.erase(event.id);
303 }
304 if (currentFingers_ < fingers_) {
305 return;
306 }
307
308 // In CrossPlatform, MOVE point has sampled, but the UP point is original coordinate,
309 // and participating in the Velocity calculation may cause abnormal rates
310 if (currentFingers_ == fingers_ && SystemProperties::IsNeedResampleTouchPoints()) {
311 UpdateTouchPointInVelocityTracker(event);
312 } else if (currentFingers_ > fingers_) {
313 panVelocity_.Reset(event.id);
314 UpdateTouchPointInVelocityTracker(event);
315 }
316
317 UpdateTouchEventInfo(event);
318
319 if ((currentFingers_ <= fingers_) &&
320 (refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
321 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
322 return;
323 }
324
325 if (refereeState_ == RefereeState::SUCCEED) {
326 if (currentFingers_ == fingers_) {
327 auto velocityTrackerIter = panVelocity_.GetVelocityMap().find(event.id);
328 if (velocityTrackerIter != panVelocity_.GetVelocityMap().end() &&
329 std::abs(panVelocity_.GetMainAxisVelocity()) <= MIN_SPEED_THRESHOLD) {
330 velocityTrackerIter->second.DumpVelocityPoints();
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 auto velocityTrackerIter = panVelocity_.GetVelocityMap().find(event.id);
372 if (velocityTrackerIter != panVelocity_.GetVelocityMap().end()) {
373 velocityTrackerIter->second.DumpVelocityPoints();
374 }
375 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW,
376 "PanVelocity main axis velocity is %{public}f", panVelocity_.GetMainAxisVelocity());
377
378 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
379 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
380 return;
381 }
382
383 if (refereeState_ == RefereeState::SUCCEED) {
384 // AxisEvent is single one.
385 isStartTriggered_ = false;
386 SendCallbackMsg(onActionEnd_);
387 AddOverTimeTrace();
388 }
389 panVelocity_.ResetAll();
390 }
391
HandleTouchMoveEvent(const TouchEvent & event)392 void PanRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
393 {
394 isTouchEventFinished_ = false;
395 if (static_cast<int32_t>(touchPoints_.size()) < fingers_) {
396 return;
397 }
398
399 UpdateTouchEventInfo(event);
400 UpdateTouchPointInVelocityTracker(event);
401 if (refereeState_ == RefereeState::DETECTING) {
402 auto result = IsPanGestureAccept();
403 if (result == GestureAcceptResult::ACCEPT) {
404 if (HandlePanAccept()) {
405 return;
406 }
407 } else if (result == GestureAcceptResult::REJECT) {
408 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
409 }
410 } else if (refereeState_ == RefereeState::SUCCEED) {
411 if ((direction_.type & PanDirection::VERTICAL) == 0) {
412 averageDistance_.SetY(0.0);
413 for (auto& element : touchPointsDistance_) {
414 element.second.SetY(0.0);
415 }
416 } else if ((direction_.type & PanDirection::HORIZONTAL) == 0) {
417 averageDistance_.SetX(0.0);
418 for (auto& element : touchPointsDistance_) {
419 element.second.SetX(0.0);
420 }
421 }
422 if (isFlushTouchEventsEnd_) {
423 if (!isStartTriggered_ && IsEnabled()) {
424 SendCallbackMsg(onActionStart_);
425 isStartTriggered_ = true;
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 (IsBridgeMode()) {
517 OnAccepted();
518 return false;
519 }
520 Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
521 return false;
522 }
523
HandleTouchCancelEvent(const TouchEvent & event)524 void PanRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
525 {
526 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d cancel", event.touchEventId, event.id);
527 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
528 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
529 return;
530 }
531
532 if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) == fingers_) {
533 // AxisEvent is single one.
534 SendCancelMsg();
535 refereeState_ = RefereeState::READY;
536 }
537 }
538
HandleTouchCancelEvent(const AxisEvent & event)539 void PanRecognizer::HandleTouchCancelEvent(const AxisEvent& event)
540 {
541 isTouchEventFinished_ = false;
542 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan axis cancel", event.touchEventId);
543 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
544 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
545 return;
546 }
547
548 if (refereeState_ == RefereeState::SUCCEED) {
549 SendCancelMsg();
550 }
551 }
552
CalculateTruthFingers(bool isDirectionUp) const553 bool PanRecognizer::CalculateTruthFingers(bool isDirectionUp) const
554 {
555 float totalDistance = 0.0f;
556 for (auto& element : touchPointsDistance_) {
557 auto each_point_move = element.second.GetY();
558 if (GreatNotEqual(each_point_move, 0.0) && isDirectionUp) {
559 totalDistance += each_point_move;
560 } else if (LessNotEqual(each_point_move, 0.0) && !isDirectionUp) {
561 totalDistance -= each_point_move;
562 }
563 }
564 auto judgeDistance = distance_;
565 if (deviceType_ == SourceType::MOUSE) {
566 judgeDistance = mouseDistance_;
567 }
568 return GreatNotEqual(totalDistance, judgeDistance) && static_cast<int32_t>(touchPointsDistance_.size()) >= fingers_;
569 }
570
IsPanGestureAccept() const571 PanRecognizer::GestureAcceptResult PanRecognizer::IsPanGestureAccept() const
572 {
573 auto judgeDistance = deviceType_ == SourceType::MOUSE ? mouseDistance_ : distance_;
574 if ((direction_.type & PanDirection::ALL) == PanDirection::ALL) {
575 double offset = averageDistance_.GetDistance();
576 if (fabs(offset) < judgeDistance) {
577 return GestureAcceptResult::DETECTING;
578 }
579 return GestureAcceptResult::ACCEPT;
580 }
581
582 if (fabs(averageDistance_.GetX()) > fabs(averageDistance_.GetY())) {
583 if ((direction_.type & PanDirection::HORIZONTAL) != 0) {
584 double offset = averageDistance_.GetX();
585 if (fabs(offset) < judgeDistance) {
586 return GestureAcceptResult::DETECTING;
587 }
588 if ((direction_.type & PanDirection::LEFT) == 0 && offset < 0) {
589 return GestureAcceptResult::REJECT;
590 }
591 if ((direction_.type & PanDirection::RIGHT) == 0 && offset > 0) {
592 return GestureAcceptResult::REJECT;
593 }
594 return GestureAcceptResult::ACCEPT;
595 }
596 return GestureAcceptResult::DETECTING;
597 }
598 if ((direction_.type & PanDirection::VERTICAL) != 0) {
599 double offset = averageDistance_.GetY();
600 if (fabs(offset) < judgeDistance) {
601 return GestureAcceptResult::DETECTING;
602 }
603 if (inputEventType_ == InputEventType::AXIS) {
604 if ((direction_.type & PanDirection::UP) == 0 && offset < 0) {
605 return GestureAcceptResult::REJECT;
606 }
607 if ((direction_.type & PanDirection::DOWN) == 0 && offset > 0) {
608 return GestureAcceptResult::REJECT;
609 }
610 } else {
611 if ((direction_.type & PanDirection::UP) == 0) {
612 return CalculateTruthFingers(true) ? GestureAcceptResult::ACCEPT : GestureAcceptResult::REJECT;
613 }
614 if ((direction_.type & PanDirection::DOWN) == 0) {
615 return CalculateTruthFingers(false) ? GestureAcceptResult::ACCEPT : GestureAcceptResult::REJECT;
616 }
617 }
618 return GestureAcceptResult::ACCEPT;
619 }
620 return GestureAcceptResult::DETECTING;
621 }
622
GetRawGlobalLocation(int32_t postEventNodeId)623 Offset PanRecognizer::GetRawGlobalLocation(int32_t postEventNodeId)
624 {
625 PointF localPoint(globalPoint_.GetX(), globalPoint_.GetY());
626 if (!lastTouchEvent_.history.empty() && (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::BOXSELECT)) {
627 auto lastPoint = lastTouchEvent_.history.back();
628 PointF rawLastPoint(lastPoint.GetOffset().GetX(), lastPoint.GetOffset().GetY());
629 NGGestureRecognizer::Transform(
630 rawLastPoint, GetAttachedNode(), false, isPostEventResult_, postEventNodeId);
631 return Offset(rawLastPoint.GetX(), rawLastPoint.GetY());
632 }
633 NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
634 isPostEventResult_, postEventNodeId);
635 return Offset(localPoint.GetX(), localPoint.GetY());
636 }
637
OnResetStatus()638 void PanRecognizer::OnResetStatus()
639 {
640 MultiFingersRecognizer::OnResetStatus();
641 touchPoints_.clear();
642 averageDistance_.Reset();
643 touchPointsDistance_.clear();
644 isStartTriggered_ = false;
645 }
646
OnSucceedCancel()647 void PanRecognizer::OnSucceedCancel()
648 {
649 SendCancelMsg();
650 }
651
GetGestureEventInfo()652 GestureEvent PanRecognizer::GetGestureEventInfo()
653 {
654 GestureEvent info;
655 info.SetTimeStamp(time_);
656 UpdateFingerListInfo();
657 info.SetDeviceId(deviceId_);
658 info.SetFingerList(fingerList_);
659 info.SetSourceDevice(deviceType_);
660 info.SetOffsetX((direction_.type & PanDirection::HORIZONTAL) == 0 ? 0.0 : averageDistance_.GetX());
661 info.SetOffsetY((direction_.type & PanDirection::VERTICAL) == 0 ? 0.0 : averageDistance_.GetY());
662 info.SetDelta(delta_);
663 info.SetVelocity(panVelocity_.GetVelocity());
664 info.SetMainVelocity(panVelocity_.GetMainAxisVelocity());
665 TouchEvent touchPoint = {};
666 if (!touchPoints_.empty()) {
667 touchPoint = touchPoints_.begin()->second;
668 }
669 PointF localPoint(globalPoint_.GetX(), globalPoint_.GetY());
670 NGGestureRecognizer::Transform(
671 localPoint, GetAttachedNode(), false, isPostEventResult_, touchPoint.postEventNodeId);
672 info.SetRawGlobalLocation(GetRawGlobalLocation(touchPoint.postEventNodeId));
673 info.SetPointerId(touchPoint.id);
674 info.SetTargetDisplayId(touchPoint.targetDisplayId);
675 info.SetIsInterpolated(touchPoint.isInterpolated);
676 info.SetInputXDeltaSlope(touchPoint.inputXDeltaSlope);
677 info.SetInputYDeltaSlope(touchPoint.inputYDeltaSlope);
678 info.SetMainDelta(mainDelta_ / static_cast<double>(touchPoints_.size()));
679 if (inputEventType_ == InputEventType::AXIS) {
680 info.SetScreenLocation(lastAxisEvent_.GetScreenOffset());
681 info.SetSourceTool(lastAxisEvent_.sourceTool);
682 info.SetVerticalAxis(lastAxisEvent_.verticalAxis);
683 info.SetHorizontalAxis(lastAxisEvent_.horizontalAxis);
684 info.SetPressedKeyCodes(lastAxisEvent_.pressedCodes);
685 } else {
686 info.SetScreenLocation(lastTouchEvent_.GetScreenOffset());
687 info.SetSourceTool(lastTouchEvent_.sourceTool);
688 info.SetPressedKeyCodes(lastTouchEvent_.pressedKeyCodes_);
689 }
690 info.SetGlobalPoint(globalPoint_).SetLocalLocation(Offset(localPoint.GetX(), localPoint.GetY()));
691 info.SetTarget(GetEventTarget().value_or(EventTarget()));
692 info.SetInputEventType(inputEventType_);
693 info.SetForce(lastTouchEvent_.force);
694 info.SetTiltX(lastTouchEvent_.tiltX.value_or(0.0));
695 info.SetTiltY(lastTouchEvent_.tiltY.value_or(0.0));
696 info.SetPointerEvent(lastPointEvent_);
697 info.SetIsPostEventResult(isPostEventResult_);
698 info.SetPostEventNodeId(lastTouchEvent_.postEventNodeId);
699 return info;
700 }
701
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & callback)702 void PanRecognizer::SendCallbackMsg(const std::unique_ptr<GestureEventFunc>& callback)
703 {
704 if (callback && *callback && IsEnabled() && (!gestureInfo_ || !gestureInfo_->GetDisposeTag())) {
705 GestureEvent info = GetGestureEventInfo();
706 // callback may be overwritten in its invoke so we copy it first
707 auto callbackFunction = *callback;
708 callbackFunction(info);
709 }
710 }
711
TriggerGestureJudgeCallback()712 GestureJudgeResult PanRecognizer::TriggerGestureJudgeCallback()
713 {
714 auto targetComponent = GetTargetComponent();
715 CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
716 auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
717 auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
718 auto callbackNative = targetComponent->GetOnGestureJudgeNativeBeginCallback();
719 if (!callback && !callbackNative && !sysJudge_ && !gestureRecognizerJudgeFunc) {
720 return GestureJudgeResult::CONTINUE;
721 }
722 auto info = std::make_shared<PanGestureEvent>();
723 UpdateFingerListInfo();
724 info->SetFingerList(fingerList_);
725 info->SetTimeStamp(time_);
726 info->SetDeviceId(deviceId_);
727 info->SetOffsetX((direction_.type & PanDirection::HORIZONTAL) == 0 ? 0.0 : averageDistance_.GetX());
728 info->SetOffsetY((direction_.type & PanDirection::VERTICAL) == 0 ? 0.0 : averageDistance_.GetY());
729 info->SetSourceDevice(deviceType_);
730 if (inputEventType_ == InputEventType::AXIS) {
731 info->SetVelocity(Velocity());
732 info->SetMainVelocity(0.0);
733 info->SetSourceTool(lastAxisEvent_.sourceTool);
734 } else {
735 info->SetVelocity(panVelocity_.GetVelocity());
736 info->SetMainVelocity(panVelocity_.GetMainAxisVelocity());
737 info->SetSourceTool(lastTouchEvent_.sourceTool);
738 }
739 info->SetTarget(GetEventTarget().value_or(EventTarget()));
740 info->SetForce(lastTouchEvent_.force);
741 if (lastTouchEvent_.tiltX.has_value()) {
742 info->SetTiltX(lastTouchEvent_.tiltX.value());
743 }
744 if (lastTouchEvent_.tiltY.has_value()) {
745 info->SetTiltY(lastTouchEvent_.tiltY.value());
746 }
747 if (gestureInfo_) {
748 gestureInfo_->SetInputEventType(inputEventType_);
749 }
750 if (gestureRecognizerJudgeFunc &&
751 gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_) == GestureJudgeResult::REJECT) {
752 return GestureJudgeResult::REJECT;
753 }
754 if (!gestureRecognizerJudgeFunc && callback && callback(gestureInfo_, info) == GestureJudgeResult::REJECT) {
755 // If outer callback exits, prioritize checking outer callback. If outer reject, return reject.
756 return GestureJudgeResult::REJECT;
757 }
758 if (callbackNative && callbackNative(gestureInfo_, info) == GestureJudgeResult::REJECT) {
759 // If outer callback doesn't exit or accept, check inner callback. If inner reject, return reject.
760 return GestureJudgeResult::REJECT;
761 }
762 if (sysJudge_ && sysJudge_(gestureInfo_, info) == GestureJudgeResult::REJECT) {
763 return GestureJudgeResult::REJECT;
764 }
765 return GestureJudgeResult::CONTINUE;
766 }
767
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)768 bool PanRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
769 {
770 RefPtr<PanRecognizer> curr = AceType::DynamicCast<PanRecognizer>(recognizer);
771 if (!curr) {
772 ResetStatus();
773 return false;
774 }
775
776 if (curr->fingers_ != fingers_ || curr->priorityMask_ != priorityMask_) {
777 if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) >= fingers_) {
778 SendCancelMsg();
779 }
780 ResetStatus();
781 return false;
782 }
783
784 direction_.type = curr->direction_.type;
785 newDirection_.type = curr->newDirection_.type;
786 distance_ = curr->distance_;
787 newDistance_ = curr->newDistance_;
788 mouseDistance_ = curr->mouseDistance_;
789
790 onActionStart_ = std::move(curr->onActionStart_);
791 onActionUpdate_ = std::move(curr->onActionUpdate_);
792 onActionEnd_ = std::move(curr->onActionEnd_);
793 onActionCancel_ = std::move(curr->onActionCancel_);
794 ReconcileGestureInfoFrom(recognizer);
795 return true;
796 }
797
GetAxisDirection()798 Axis PanRecognizer::GetAxisDirection()
799 {
800 auto hasHorizontal = direction_.type & PanDirection::HORIZONTAL;
801 auto hasVertical = direction_.type & PanDirection::VERTICAL;
802 if (direction_.type == PanDirection::ALL || (hasHorizontal && hasVertical)) {
803 return Axis::FREE;
804 }
805 if (hasHorizontal) {
806 return Axis::HORIZONTAL;
807 }
808 if (hasVertical) {
809 return Axis::VERTICAL;
810 }
811 return Axis::NONE;
812 }
813
SetDirection(const PanDirection & direction)814 void PanRecognizer::SetDirection(const PanDirection& direction)
815 {
816 ChangeDirection(direction);
817 panVelocity_.SetDirection(direction_.type);
818 panVelocity_.SetDirection(direction_.type);
819 }
820
ChangeFingers(int32_t fingers)821 void PanRecognizer::ChangeFingers(int32_t fingers)
822 {
823 if (fingers_ != fingers) {
824 newFingers_ = fingers;
825 }
826 }
827
ChangeDirection(const PanDirection & direction)828 void PanRecognizer::ChangeDirection(const PanDirection& direction)
829 {
830 if (direction_.type != direction.type) {
831 direction_.type = direction.type;
832 newDirection_.type = direction.type;
833 }
834 }
835
ChangeDistance(double distance)836 void PanRecognizer::ChangeDistance(double distance)
837 {
838 if (distance_ != distance) {
839 if (refereeState_ == RefereeState::READY || refereeState_ == RefereeState::DETECTING) {
840 distance_ = distance;
841 }
842 newDistance_ = distance;
843 mouseDistance_ = distance;
844 }
845 }
846
GetMainAxisDelta()847 double PanRecognizer::GetMainAxisDelta()
848 {
849 switch (direction_.type) {
850 case PanDirection::ALL:
851 return delta_.GetDistance();
852 case PanDirection::HORIZONTAL:
853 return delta_.GetX();
854 case PanDirection::VERTICAL:
855 return delta_.GetY();
856 default:
857 return 0.0;
858 }
859 }
860
Dump() const861 RefPtr<GestureSnapshot> PanRecognizer::Dump() const
862 {
863 RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
864 std::stringstream oss;
865 oss << "direction: " << direction_.type << ", "
866 << "isForDrag: " << isForDrag_ << ", "
867 << "distance: " << distance_ << ", "
868 << "fingers: " << fingers_ << ", "
869 << DumpGestureInfo();
870 info->customInfo = oss.str();
871 return info;
872 }
873
GetDragEventActuator()874 RefPtr<DragEventActuator> PanRecognizer::GetDragEventActuator()
875 {
876 auto targetComponent = GetTargetComponent();
877 CHECK_NULL_RETURN(targetComponent, nullptr);
878 auto uiNode = targetComponent->GetUINode().Upgrade();
879 CHECK_NULL_RETURN(uiNode, nullptr);
880 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
881 CHECK_NULL_RETURN(frameNode, nullptr);
882 auto gestureEventHub = frameNode->GetOrCreateGestureEventHub();
883 CHECK_NULL_RETURN(gestureEventHub, nullptr);
884 return gestureEventHub->GetDragEventActuator();
885 }
886
GetFastestTracker(std::function<double (VelocityTracker &)> && func)887 int32_t PanRecognizer::PanVelocity::GetFastestTracker(std::function<double(VelocityTracker&)>&& func)
888 {
889 int32_t maxId = -1;
890 double maxV = 0.0;
891 for (auto& [id, tracker] : trackerMap_) {
892 double v = std::abs(func(tracker));
893 if (v > maxV) {
894 maxId = id;
895 maxV = v;
896 }
897 }
898 return maxId;
899 }
900
GetVelocity()901 Velocity PanRecognizer::PanVelocity::GetVelocity()
902 {
903 auto&& func = [](VelocityTracker& tracker) { return tracker.GetVelocity().GetVelocityValue(); };
904 int32_t id = GetFastestTracker(func);
905 return (id != -1) ? trackerMap_[id].GetVelocity() : Velocity();
906 }
907
GetMainAxisVelocity()908 double PanRecognizer::PanVelocity::GetMainAxisVelocity()
909 {
910 auto&& func = [axis = axis_](VelocityTracker& tracker) {
911 tracker.SetMainAxis(axis);
912 return tracker.GetMainAxisVelocity();
913 };
914 int32_t id = GetFastestTracker(func);
915 return (id != -1) ? trackerMap_[id].GetMainAxisVelocity() : 0.0;
916 }
917
UpdateTouchPoint(int32_t id,const TouchEvent & event,bool end)918 void PanRecognizer::PanVelocity::UpdateTouchPoint(int32_t id, const TouchEvent& event, bool end)
919 {
920 trackerMap_[id].UpdateTouchPoint(event, end);
921 }
922
Reset(int32_t id)923 void PanRecognizer::PanVelocity::Reset(int32_t id)
924 {
925 trackerMap_.erase(id);
926 }
927
ResetAll()928 void PanRecognizer::PanVelocity::ResetAll()
929 {
930 trackerMap_.clear();
931 }
932
SetDirection(int32_t directionType)933 void PanRecognizer::PanVelocity::SetDirection(int32_t directionType)
934 {
935 auto axis = Axis::FREE;
936 if ((directionType & PanDirection::VERTICAL) == 0) {
937 axis = Axis::HORIZONTAL;
938 } else if ((directionType & PanDirection::HORIZONTAL) == 0) {
939 axis = Axis::VERTICAL;
940 }
941 axis_ = axis;
942 }
943
AddOverTimeTrace()944 void PanRecognizer::AddOverTimeTrace()
945 {
946 int64_t overTime = GetSysTimestamp();
947 int64_t inputTime = overTime;
948 if (firstInputTime_.has_value()) {
949 inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
950 }
951 if (SystemProperties::GetTraceInputEventEnabled()) {
952 ACE_SCOPED_TRACE("UserEvent InputTime:%lld OverTime:%lld InputType:PanGesture",
953 static_cast<long long>(inputTime), static_cast<long long>(overTime));
954 }
955 firstInputTime_.reset();
956 }
957
UpdateTouchEventInfo(const TouchEvent & event)958 void PanRecognizer::UpdateTouchEventInfo(const TouchEvent& event)
959 {
960 globalPoint_ = Point(event.x, event.y);
961 lastTouchEvent_ = event;
962 PointF windowPoint(event.GetOffset().GetX(), event.GetOffset().GetY());
963 PointF windowTouchPoint(touchPoints_[event.id].GetOffset().GetX(), touchPoints_[event.id].GetOffset().GetY());
964 NGGestureRecognizer::Transform(windowPoint, GetAttachedNode(), false,
965 isPostEventResult_, event.postEventNodeId);
966 NGGestureRecognizer::Transform(windowTouchPoint, GetAttachedNode(), false,
967 isPostEventResult_, event.postEventNodeId);
968 delta_ =
969 (Offset(windowPoint.GetX(), windowPoint.GetY()) - Offset(windowTouchPoint.GetX(), windowTouchPoint.GetY()));
970
971 if (SystemProperties::GetDebugEnabled()) {
972 TAG_LOGD(AceLogTag::ACE_GESTURE, "Delta is x %{public}f, y %{public}f ", delta_.GetX(), delta_.GetY());
973 }
974 mainDelta_ = GetMainAxisDelta();
975 averageDistance_ += delta_ / static_cast<double>(touchPoints_.size());
976 touchPoints_[event.id] = event;
977 touchPointsDistance_[event.id] += delta_;
978 time_ = event.time;
979 }
980
DispatchPanStartedToPerf(const TouchEvent & event)981 void PanRecognizer::DispatchPanStartedToPerf(const TouchEvent& event)
982 {
983 int64_t inputTime = event.time.time_since_epoch().count();
984 if (inputTime <= 0 || event.sourceType != SourceType::TOUCH) {
985 return;
986 }
987 PerfMonitor* pMonitor = PerfMonitor::GetPerfMonitor();
988 if (pMonitor == nullptr) {
989 return;
990 }
991 pMonitor->RecordInputEvent(FIRST_MOVE, PERF_TOUCH_EVENT, inputTime);
992 }
993 } // namespace OHOS::Ace::NG
994