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 isTouchEventFinished_ = false;
199 if (!firstInputTime_.has_value()) {
200 firstInputTime_ = event.time;
201 }
202
203 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d down, state: %{public}d", event.touchEventId,
204 event.id, refereeState_);
205 fingers_ = newFingers_;
206 distance_ = newDistance_;
207 direction_ = newDirection_;
208
209 if (direction_.type == PanDirection::NONE) {
210 auto node = GetAttachedNode().Upgrade();
211 TAG_LOGI(AceLogTag::ACE_GESTURE, "Pan recognizer direction is none, node tag = %{public}s, id = %{public}s",
212 node ? node->GetTag().c_str() : "null", node ? std::to_string(node->GetId()).c_str() : "invalid");
213 Adjudicate(Claim(this), GestureDisposal::REJECT);
214 return;
215 }
216 if (event.sourceType == SourceType::MOUSE && !isAllowMouse_) {
217 Adjudicate(Claim(this), GestureDisposal::REJECT);
218 return;
219 }
220 if (!IsInAttachedNode(event)) {
221 Adjudicate(Claim(this), GestureDisposal::REJECT);
222 return;
223 }
224
225 if (fingersId_.find(event.id) == fingersId_.end()) {
226 fingersId_.insert(event.id);
227 }
228
229 deviceId_ = event.deviceId;
230 deviceType_ = event.sourceType;
231 lastTouchEvent_ = event;
232 touchPoints_[event.id] = event;
233 touchPointsDistance_[event.id] = Offset(0.0, 0.0);
234 auto fingerNum = static_cast<int32_t>(touchPoints_.size());
235
236 if (fingerNum >= fingers_) {
237 if (refereeState_ == RefereeState::READY) {
238 panVelocity_.Reset(event.id);
239 UpdateTouchPointInVelocityTracker(event);
240 refereeState_ = RefereeState::DETECTING;
241 } else {
242 TAG_LOGI(AceLogTag::ACE_GESTURE, "Pan gesture refereeState is not READY");
243 }
244 }
245 }
246
HandleTouchDownEvent(const AxisEvent & event)247 void PanRecognizer::HandleTouchDownEvent(const AxisEvent& event)
248 {
249 isTouchEventFinished_ = false;
250 if (!firstInputTime_.has_value()) {
251 firstInputTime_ = event.time;
252 }
253 if (event.isRotationEvent) {
254 return;
255 }
256 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d axis start, state:%{public}d",
257 event.touchEventId, event.id, refereeState_);
258 fingers_ = newFingers_;
259 distance_ = newDistance_;
260 direction_ = newDirection_;
261
262 if (fingers_ != AXIS_PAN_FINGERS) {
263 Adjudicate(Claim(this), GestureDisposal::REJECT);
264 return;
265 }
266
267 if (direction_.type == PanDirection::NONE) {
268 Adjudicate(Claim(this), GestureDisposal::REJECT);
269 return;
270 }
271
272 deviceId_ = event.deviceId;
273 deviceType_ = event.sourceType;
274 lastAxisEvent_ = event;
275
276 touchPoints_[event.id] = TouchEvent();
277 UpdateTouchPointWithAxisEvent(event);
278 panVelocity_.Reset(event.id);
279 auto pesudoTouchEvent = TouchEvent();
280 pesudoTouchEvent.time = event.time;
281 auto revertAxisValue = event.ConvertToSummationAxisValue(lastAxisEvent_);
282 pesudoTouchEvent.x = revertAxisValue.first;
283 pesudoTouchEvent.y = revertAxisValue.second;
284 panVelocity_.UpdateTouchPoint(event.id, pesudoTouchEvent, false);
285 refereeState_ = RefereeState::DETECTING;
286 }
287
HandleTouchUpEvent(const TouchEvent & event)288 void PanRecognizer::HandleTouchUpEvent(const TouchEvent& event)
289 {
290 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d up, state: %{public}d", event.touchEventId,
291 event.id, refereeState_);
292 if (fingersId_.find(event.id) != fingersId_.end()) {
293 fingersId_.erase(event.id);
294 }
295 if (currentFingers_ < fingers_) {
296 return;
297 }
298
299 if (currentFingers_ == fingers_) {
300 UpdateTouchPointInVelocityTracker(event);
301 } else if (currentFingers_ > fingers_) {
302 panVelocity_.Reset(event.id);
303 UpdateTouchPointInVelocityTracker(event);
304 }
305 UpdateTouchEventInfo(event);
306
307 if ((currentFingers_ <= fingers_) &&
308 (refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
309 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
310 return;
311 }
312
313 if (refereeState_ == RefereeState::SUCCEED) {
314 if (currentFingers_ == fingers_) {
315 auto velocityTrackerIter = panVelocity_.GetVelocityMap().find(event.id);
316 if (velocityTrackerIter != panVelocity_.GetVelocityMap().end() &&
317 std::abs(panVelocity_.GetMainAxisVelocity()) <= MIN_SPEED_THRESHOLD) {
318 velocityTrackerIter->second.DumpVelocityPoints();
319 }
320 // last one to fire end.
321 isStartTriggered_ = false;
322 SendCallbackMsg(onActionEnd_);
323 averageDistance_.Reset();
324 AddOverTimeTrace();
325 refereeState_ = RefereeState::READY;
326 }
327 }
328
329 // Clear All fingers' velocity when fingersId is empty.
330 if (fingersId_.empty()) {
331 panVelocity_.ResetAll();
332 isTouchEventFinished_ = true;
333 }
334 }
335
HandleTouchUpEvent(const AxisEvent & event)336 void PanRecognizer::HandleTouchUpEvent(const AxisEvent& event)
337 {
338 isTouchEventFinished_ = false;
339 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d axis end, state: %{public}d",
340 event.touchEventId, event.id, refereeState_);
341 // if axisEvent received rotateEvent, no need to active Pan recognizer.
342 if (event.isRotationEvent) {
343 return;
344 }
345
346 if (event.sourceTool == SourceTool::MOUSE) {
347 delta_ = event.ConvertToOffset();
348 mainDelta_ = GetMainAxisDelta();
349 averageDistance_ += delta_;
350 }
351
352 globalPoint_ = Point(event.x, event.y);
353
354 touchPoints_[event.id] = TouchEvent();
355 UpdateTouchPointWithAxisEvent(event);
356 UpdateAxisPointInVelocityTracker(event, true);
357 time_ = event.time;
358
359 auto velocityTrackerIter = panVelocity_.GetVelocityMap().find(event.id);
360 if (velocityTrackerIter != panVelocity_.GetVelocityMap().end()) {
361 velocityTrackerIter->second.DumpVelocityPoints();
362 }
363 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW,
364 "PanVelocity main axis velocity is %{public}f", panVelocity_.GetMainAxisVelocity());
365
366 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
367 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
368 return;
369 }
370
371 if (refereeState_ == RefereeState::SUCCEED) {
372 // AxisEvent is single one.
373 isStartTriggered_ = false;
374 SendCallbackMsg(onActionEnd_);
375 AddOverTimeTrace();
376 }
377 panVelocity_.ResetAll();
378 }
379
HandleTouchMoveEvent(const TouchEvent & event)380 void PanRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
381 {
382 isTouchEventFinished_ = false;
383 if (static_cast<int32_t>(touchPoints_.size()) < fingers_) {
384 return;
385 }
386
387 UpdateTouchEventInfo(event);
388 UpdateTouchPointInVelocityTracker(event);
389 if (refereeState_ == RefereeState::DETECTING) {
390 auto result = IsPanGestureAccept();
391 if (result == GestureAcceptResult::ACCEPT) {
392 if (HandlePanAccept()) {
393 return;
394 }
395 } else if (result == GestureAcceptResult::REJECT) {
396 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
397 }
398 } else if (refereeState_ == RefereeState::SUCCEED) {
399 if ((direction_.type & PanDirection::VERTICAL) == 0) {
400 averageDistance_.SetY(0.0);
401 for (auto& element : touchPointsDistance_) {
402 element.second.SetY(0.0);
403 }
404 } else if ((direction_.type & PanDirection::HORIZONTAL) == 0) {
405 averageDistance_.SetX(0.0);
406 for (auto& element : touchPointsDistance_) {
407 element.second.SetX(0.0);
408 }
409 }
410 if (isFlushTouchEventsEnd_) {
411 if (!isStartTriggered_ && IsEnabled()) {
412 SendCallbackMsg(onActionStart_);
413 isStartTriggered_ = true;
414 }
415 SendCallbackMsg(onActionUpdate_);
416 }
417 }
418 }
419
OnFlushTouchEventsBegin()420 void PanRecognizer::OnFlushTouchEventsBegin()
421 {
422 isFlushTouchEventsEnd_ = false;
423 }
424
OnFlushTouchEventsEnd()425 void PanRecognizer::OnFlushTouchEventsEnd()
426 {
427 isFlushTouchEventsEnd_ = true;
428 }
429
HandleTouchMoveEvent(const AxisEvent & event)430 void PanRecognizer::HandleTouchMoveEvent(const AxisEvent& event)
431 {
432 isTouchEventFinished_ = false;
433 if (fingers_ != AXIS_PAN_FINGERS || event.isRotationEvent) {
434 return;
435 }
436
437 auto pipeline = PipelineContext::GetCurrentContext();
438 bool isShiftKeyPressed = false;
439 bool hasDifferentDirectionGesture = false;
440 if (pipeline) {
441 isShiftKeyPressed =
442 pipeline->IsKeyInPressed(KeyCode::KEY_SHIFT_LEFT) || pipeline->IsKeyInPressed(KeyCode::KEY_SHIFT_RIGHT);
443 hasDifferentDirectionGesture = pipeline->HasDifferentDirectionGesture();
444 }
445 delta_ = event.ConvertToOffset(isShiftKeyPressed, hasDifferentDirectionGesture);
446 if (event.sourceTool == SourceTool::MOUSE) {
447 if ((direction_.type & PanDirection::HORIZONTAL) == 0) { // Direction is vertical
448 delta_.SetX(0.0);
449 } else if ((direction_.type & PanDirection::VERTICAL) == 0) { // Direction is horizontal
450 delta_.SetY(0.0);
451 }
452 }
453
454 globalPoint_ = Point(event.x, event.y);
455 mainDelta_ = GetMainAxisDelta();
456 averageDistance_ += delta_;
457
458 UpdateAxisPointInVelocityTracker(event);
459 time_ = event.time;
460
461 if (refereeState_ == RefereeState::DETECTING) {
462 auto result = IsPanGestureAccept();
463 if (result == GestureAcceptResult::ACCEPT) {
464 if (HandlePanAccept()) {
465 return;
466 }
467 } else if (result == GestureAcceptResult::REJECT) {
468 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
469 }
470 } else if (refereeState_ == RefereeState::SUCCEED) {
471 if ((direction_.type & PanDirection::VERTICAL) == 0) {
472 averageDistance_.SetY(0.0);
473 } else if ((direction_.type & PanDirection::HORIZONTAL) == 0) {
474 averageDistance_.SetX(0.0);
475 }
476 if (!isStartTriggered_ && IsEnabled()) {
477 SendCallbackMsg(onActionStart_);
478 isStartTriggered_ = true;
479 }
480 SendCallbackMsg(onActionUpdate_);
481 }
482 }
483
HandlePanAccept()484 bool PanRecognizer::HandlePanAccept()
485 {
486 if (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::DRAG) {
487 auto dragEventActuator = GetDragEventActuator();
488 CHECK_NULL_RETURN(dragEventActuator, true);
489 if (dragEventActuator->IsDragUserReject()) {
490 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
491 return true;
492 }
493 }
494 if (TriggerGestureJudgeCallback() == GestureJudgeResult::REJECT) {
495 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
496 if (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::DRAG) {
497 auto dragEventActuator = GetDragEventActuator();
498 CHECK_NULL_RETURN(dragEventActuator, true);
499 dragEventActuator->SetIsDragUserReject(true);
500 }
501 return true;
502 }
503 if (IsBridgeMode()) {
504 OnAccepted();
505 return false;
506 }
507 Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
508 return false;
509 }
510
HandleTouchCancelEvent(const TouchEvent & event)511 void PanRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
512 {
513 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan %{public}d cancel", event.touchEventId, event.id);
514 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
515 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
516 return;
517 }
518
519 if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) == fingers_) {
520 // AxisEvent is single one.
521 SendCancelMsg();
522 refereeState_ = RefereeState::READY;
523 }
524 }
525
HandleTouchCancelEvent(const AxisEvent & event)526 void PanRecognizer::HandleTouchCancelEvent(const AxisEvent& event)
527 {
528 isTouchEventFinished_ = false;
529 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, pan axis cancel", event.touchEventId);
530 if ((refereeState_ != RefereeState::SUCCEED) && (refereeState_ != RefereeState::FAIL)) {
531 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
532 return;
533 }
534
535 if (refereeState_ == RefereeState::SUCCEED) {
536 SendCancelMsg();
537 }
538 }
539
CalculateTruthFingers(bool isDirectionUp) const540 bool PanRecognizer::CalculateTruthFingers(bool isDirectionUp) const
541 {
542 float totalDistance = 0.0f;
543 for (auto& element : touchPointsDistance_) {
544 auto each_point_move = element.second.GetY();
545 if (GreatNotEqual(each_point_move, 0.0) && isDirectionUp) {
546 totalDistance += each_point_move;
547 } else if (LessNotEqual(each_point_move, 0.0) && !isDirectionUp) {
548 totalDistance -= each_point_move;
549 }
550 }
551 auto judgeDistance = distance_;
552 if (deviceType_ == SourceType::MOUSE) {
553 judgeDistance = mouseDistance_;
554 }
555 return GreatNotEqual(totalDistance, judgeDistance) && static_cast<int32_t>(touchPointsDistance_.size()) >= fingers_;
556 }
557
IsPanGestureAccept() const558 PanRecognizer::GestureAcceptResult PanRecognizer::IsPanGestureAccept() const
559 {
560 auto judgeDistance = deviceType_ == SourceType::MOUSE ? mouseDistance_ : distance_;
561 if ((direction_.type & PanDirection::ALL) == PanDirection::ALL) {
562 double offset = averageDistance_.GetDistance();
563 if (fabs(offset) < judgeDistance) {
564 return GestureAcceptResult::DETECTING;
565 }
566 return GestureAcceptResult::ACCEPT;
567 }
568
569 if (fabs(averageDistance_.GetX()) > fabs(averageDistance_.GetY())) {
570 if ((direction_.type & PanDirection::HORIZONTAL) != 0) {
571 double offset = averageDistance_.GetX();
572 if (fabs(offset) < judgeDistance) {
573 return GestureAcceptResult::DETECTING;
574 }
575 if ((direction_.type & PanDirection::LEFT) == 0 && offset < 0) {
576 return GestureAcceptResult::REJECT;
577 }
578 if ((direction_.type & PanDirection::RIGHT) == 0 && offset > 0) {
579 return GestureAcceptResult::REJECT;
580 }
581 return GestureAcceptResult::ACCEPT;
582 }
583 return GestureAcceptResult::DETECTING;
584 }
585 if ((direction_.type & PanDirection::VERTICAL) != 0) {
586 double offset = averageDistance_.GetY();
587 if (fabs(offset) < judgeDistance) {
588 return GestureAcceptResult::DETECTING;
589 }
590 if (inputEventType_ == InputEventType::AXIS) {
591 if ((direction_.type & PanDirection::UP) == 0 && offset < 0) {
592 return GestureAcceptResult::REJECT;
593 }
594 if ((direction_.type & PanDirection::DOWN) == 0 && offset > 0) {
595 return GestureAcceptResult::REJECT;
596 }
597 } else {
598 if ((direction_.type & PanDirection::UP) == 0) {
599 return CalculateTruthFingers(true) ? GestureAcceptResult::ACCEPT : GestureAcceptResult::REJECT;
600 }
601 if ((direction_.type & PanDirection::DOWN) == 0) {
602 return CalculateTruthFingers(false) ? GestureAcceptResult::ACCEPT : GestureAcceptResult::REJECT;
603 }
604 }
605 return GestureAcceptResult::ACCEPT;
606 }
607 return GestureAcceptResult::DETECTING;
608 }
609
GetRawGlobalLocation(int32_t postEventNodeId)610 Offset PanRecognizer::GetRawGlobalLocation(int32_t postEventNodeId)
611 {
612 PointF localPoint(globalPoint_.GetX(), globalPoint_.GetY());
613 if (!lastTouchEvent_.history.empty() && (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::BOXSELECT)) {
614 auto lastPoint = lastTouchEvent_.history.back();
615 PointF rawLastPoint(lastPoint.GetOffset().GetX(), lastPoint.GetOffset().GetY());
616 NGGestureRecognizer::Transform(
617 rawLastPoint, GetAttachedNode(), false, isPostEventResult_, postEventNodeId);
618 return Offset(rawLastPoint.GetX(), rawLastPoint.GetY());
619 }
620 NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
621 isPostEventResult_, postEventNodeId);
622 return Offset(localPoint.GetX(), localPoint.GetY());
623 }
624
OnResetStatus()625 void PanRecognizer::OnResetStatus()
626 {
627 MultiFingersRecognizer::OnResetStatus();
628 touchPoints_.clear();
629 averageDistance_.Reset();
630 touchPointsDistance_.clear();
631 isStartTriggered_ = false;
632 }
633
OnSucceedCancel()634 void PanRecognizer::OnSucceedCancel()
635 {
636 SendCancelMsg();
637 }
638
GetGestureEventInfo()639 GestureEvent PanRecognizer::GetGestureEventInfo()
640 {
641 GestureEvent info;
642 info.SetTimeStamp(time_);
643 UpdateFingerListInfo();
644 info.SetDeviceId(deviceId_);
645 info.SetFingerList(fingerList_);
646 info.SetSourceDevice(deviceType_);
647 info.SetOffsetX((direction_.type & PanDirection::HORIZONTAL) == 0 ? 0.0 : averageDistance_.GetX());
648 info.SetOffsetY((direction_.type & PanDirection::VERTICAL) == 0 ? 0.0 : averageDistance_.GetY());
649 info.SetDelta(delta_);
650 info.SetVelocity(panVelocity_.GetVelocity());
651 info.SetMainVelocity(panVelocity_.GetMainAxisVelocity());
652 TouchEvent touchPoint = {};
653 if (!touchPoints_.empty()) {
654 touchPoint = touchPoints_.begin()->second;
655 }
656 PointF localPoint(globalPoint_.GetX(), globalPoint_.GetY());
657 NGGestureRecognizer::Transform(
658 localPoint, GetAttachedNode(), false, isPostEventResult_, touchPoint.postEventNodeId);
659 info.SetRawGlobalLocation(GetRawGlobalLocation(touchPoint.postEventNodeId));
660 info.SetPointerId(touchPoint.id);
661 info.SetTargetDisplayId(touchPoint.targetDisplayId);
662 info.SetIsInterpolated(touchPoint.isInterpolated);
663 info.SetInputXDeltaSlope(touchPoint.inputXDeltaSlope);
664 info.SetInputYDeltaSlope(touchPoint.inputYDeltaSlope);
665 info.SetMainDelta(mainDelta_ / static_cast<double>(touchPoints_.size()));
666 if (inputEventType_ == InputEventType::AXIS) {
667 info.SetScreenLocation(lastAxisEvent_.GetScreenOffset());
668 info.SetSourceTool(lastAxisEvent_.sourceTool);
669 info.SetVerticalAxis(lastAxisEvent_.verticalAxis);
670 info.SetHorizontalAxis(lastAxisEvent_.horizontalAxis);
671 info.SetPressedKeyCodes(lastAxisEvent_.pressedCodes);
672 } else {
673 info.SetScreenLocation(lastTouchEvent_.GetScreenOffset());
674 info.SetSourceTool(lastTouchEvent_.sourceTool);
675 info.SetPressedKeyCodes(lastTouchEvent_.pressedKeyCodes_);
676 }
677 info.SetGlobalPoint(globalPoint_).SetLocalLocation(Offset(localPoint.GetX(), localPoint.GetY()));
678 info.SetTarget(GetEventTarget().value_or(EventTarget()));
679 info.SetInputEventType(inputEventType_);
680 info.SetForce(lastTouchEvent_.force);
681 info.SetTiltX(lastTouchEvent_.tiltX.value_or(0.0));
682 info.SetTiltY(lastTouchEvent_.tiltY.value_or(0.0));
683 info.SetPointerEvent(lastPointEvent_);
684 info.SetIsPostEventResult(isPostEventResult_);
685 info.SetPostEventNodeId(lastTouchEvent_.postEventNodeId);
686 return info;
687 }
688
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & callback)689 void PanRecognizer::SendCallbackMsg(const std::unique_ptr<GestureEventFunc>& callback)
690 {
691 if (callback && *callback && IsEnabled()) {
692 GestureEvent info = GetGestureEventInfo();
693 // callback may be overwritten in its invoke so we copy it first
694 auto callbackFunction = *callback;
695 callbackFunction(info);
696 }
697 }
698
TriggerGestureJudgeCallback()699 GestureJudgeResult PanRecognizer::TriggerGestureJudgeCallback()
700 {
701 auto targetComponent = GetTargetComponent();
702 CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
703 auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
704 auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
705 auto callbackNative = targetComponent->GetOnGestureJudgeNativeBeginCallback();
706 if (!callback && !callbackNative && !sysJudge_ && !gestureRecognizerJudgeFunc) {
707 return GestureJudgeResult::CONTINUE;
708 }
709 auto info = std::make_shared<PanGestureEvent>();
710 UpdateFingerListInfo();
711 info->SetFingerList(fingerList_);
712 info->SetTimeStamp(time_);
713 info->SetDeviceId(deviceId_);
714 info->SetOffsetX((direction_.type & PanDirection::HORIZONTAL) == 0 ? 0.0 : averageDistance_.GetX());
715 info->SetOffsetY((direction_.type & PanDirection::VERTICAL) == 0 ? 0.0 : averageDistance_.GetY());
716 info->SetSourceDevice(deviceType_);
717 if (inputEventType_ == InputEventType::AXIS) {
718 info->SetVelocity(Velocity());
719 info->SetMainVelocity(0.0);
720 info->SetSourceTool(lastAxisEvent_.sourceTool);
721 } else {
722 info->SetVelocity(panVelocity_.GetVelocity());
723 info->SetMainVelocity(panVelocity_.GetMainAxisVelocity());
724 info->SetSourceTool(lastTouchEvent_.sourceTool);
725 }
726 info->SetTarget(GetEventTarget().value_or(EventTarget()));
727 info->SetForce(lastTouchEvent_.force);
728 if (lastTouchEvent_.tiltX.has_value()) {
729 info->SetTiltX(lastTouchEvent_.tiltX.value());
730 }
731 if (lastTouchEvent_.tiltY.has_value()) {
732 info->SetTiltY(lastTouchEvent_.tiltY.value());
733 }
734 if (gestureInfo_) {
735 gestureInfo_->SetInputEventType(inputEventType_);
736 }
737 if (gestureRecognizerJudgeFunc &&
738 gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_) == GestureJudgeResult::REJECT) {
739 return GestureJudgeResult::REJECT;
740 }
741 if (!gestureRecognizerJudgeFunc && callback && callback(gestureInfo_, info) == GestureJudgeResult::REJECT) {
742 // If outer callback exits, prioritize checking outer callback. If outer reject, return reject.
743 return GestureJudgeResult::REJECT;
744 }
745 if (callbackNative && callbackNative(gestureInfo_, info) == GestureJudgeResult::REJECT) {
746 // If outer callback doesn't exit or accept, check inner callback. If inner reject, return reject.
747 return GestureJudgeResult::REJECT;
748 }
749 if (sysJudge_ && sysJudge_(gestureInfo_, info) == GestureJudgeResult::REJECT) {
750 return GestureJudgeResult::REJECT;
751 }
752 return GestureJudgeResult::CONTINUE;
753 }
754
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)755 bool PanRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
756 {
757 RefPtr<PanRecognizer> curr = AceType::DynamicCast<PanRecognizer>(recognizer);
758 if (!curr) {
759 ResetStatus();
760 return false;
761 }
762
763 if (curr->fingers_ != fingers_ || curr->priorityMask_ != priorityMask_) {
764 if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) >= fingers_) {
765 SendCancelMsg();
766 }
767 ResetStatus();
768 return false;
769 }
770
771 direction_.type = curr->direction_.type;
772 newDirection_.type = curr->newDirection_.type;
773 distance_ = curr->distance_;
774 newDistance_ = curr->newDistance_;
775 mouseDistance_ = curr->mouseDistance_;
776
777 onActionStart_ = std::move(curr->onActionStart_);
778 onActionUpdate_ = std::move(curr->onActionUpdate_);
779 onActionEnd_ = std::move(curr->onActionEnd_);
780 onActionCancel_ = std::move(curr->onActionCancel_);
781
782 return true;
783 }
784
GetAxisDirection()785 Axis PanRecognizer::GetAxisDirection()
786 {
787 auto hasHorizontal = direction_.type & PanDirection::HORIZONTAL;
788 auto hasVertical = direction_.type & PanDirection::VERTICAL;
789 if (direction_.type == PanDirection::ALL || (hasHorizontal && hasVertical)) {
790 return Axis::FREE;
791 }
792 if (hasHorizontal) {
793 return Axis::HORIZONTAL;
794 }
795 if (hasVertical) {
796 return Axis::VERTICAL;
797 }
798 return Axis::NONE;
799 }
800
SetDirection(const PanDirection & direction)801 void PanRecognizer::SetDirection(const PanDirection& direction)
802 {
803 ChangeDirection(direction);
804 panVelocity_.SetDirection(direction_.type);
805 panVelocity_.SetDirection(direction_.type);
806 }
807
ChangeFingers(int32_t fingers)808 void PanRecognizer::ChangeFingers(int32_t fingers)
809 {
810 if (fingers_ != fingers) {
811 newFingers_ = fingers;
812 }
813 }
814
ChangeDirection(const PanDirection & direction)815 void PanRecognizer::ChangeDirection(const PanDirection& direction)
816 {
817 if (direction_.type != direction.type) {
818 direction_.type = direction.type;
819 newDirection_.type = direction.type;
820 }
821 }
822
ChangeDistance(double distance)823 void PanRecognizer::ChangeDistance(double distance)
824 {
825 if (distance_ != distance) {
826 if (refereeState_ == RefereeState::READY || refereeState_ == RefereeState::DETECTING) {
827 distance_ = distance;
828 }
829 newDistance_ = distance;
830 mouseDistance_ = distance;
831 }
832 }
833
GetMainAxisDelta()834 double PanRecognizer::GetMainAxisDelta()
835 {
836 switch (direction_.type) {
837 case PanDirection::ALL:
838 return delta_.GetDistance();
839 case PanDirection::HORIZONTAL:
840 return delta_.GetX();
841 case PanDirection::VERTICAL:
842 return delta_.GetY();
843 default:
844 return 0.0;
845 }
846 }
847
Dump() const848 RefPtr<GestureSnapshot> PanRecognizer::Dump() const
849 {
850 RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
851 std::stringstream oss;
852 oss << "direction: " << direction_.type << ", "
853 << "isForDrag: " << isForDrag_ << ", "
854 << "distance: " << distance_ << ", "
855 << "fingers: " << fingers_;
856 info->customInfo = oss.str();
857 return info;
858 }
859
GetDragEventActuator()860 RefPtr<DragEventActuator> PanRecognizer::GetDragEventActuator()
861 {
862 auto targetComponent = GetTargetComponent();
863 CHECK_NULL_RETURN(targetComponent, nullptr);
864 auto uiNode = targetComponent->GetUINode().Upgrade();
865 CHECK_NULL_RETURN(uiNode, nullptr);
866 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
867 CHECK_NULL_RETURN(frameNode, nullptr);
868 auto gestureEventHub = frameNode->GetOrCreateGestureEventHub();
869 CHECK_NULL_RETURN(gestureEventHub, nullptr);
870 return gestureEventHub->GetDragEventActuator();
871 }
872
GetFastestTracker(std::function<double (VelocityTracker &)> && func)873 int32_t PanRecognizer::PanVelocity::GetFastestTracker(std::function<double(VelocityTracker&)>&& func)
874 {
875 int32_t maxId = -1;
876 double maxV = 0.0;
877 for (auto& [id, tracker] : trackerMap_) {
878 double v = std::abs(func(tracker));
879 if (v > maxV) {
880 maxId = id;
881 maxV = v;
882 }
883 }
884 return maxId;
885 }
886
GetVelocity()887 Velocity PanRecognizer::PanVelocity::GetVelocity()
888 {
889 auto&& func = [](VelocityTracker& tracker) { return tracker.GetVelocity().GetVelocityValue(); };
890 int32_t id = GetFastestTracker(func);
891 return (id != -1) ? trackerMap_[id].GetVelocity() : Velocity();
892 }
893
GetMainAxisVelocity()894 double PanRecognizer::PanVelocity::GetMainAxisVelocity()
895 {
896 auto&& func = [axis = axis_](VelocityTracker& tracker) {
897 tracker.SetMainAxis(axis);
898 return tracker.GetMainAxisVelocity();
899 };
900 int32_t id = GetFastestTracker(func);
901 return (id != -1) ? trackerMap_[id].GetMainAxisVelocity() : 0.0;
902 }
903
UpdateTouchPoint(int32_t id,const TouchEvent & event,bool end)904 void PanRecognizer::PanVelocity::UpdateTouchPoint(int32_t id, const TouchEvent& event, bool end)
905 {
906 trackerMap_[id].UpdateTouchPoint(event, end);
907 }
908
Reset(int32_t id)909 void PanRecognizer::PanVelocity::Reset(int32_t id)
910 {
911 trackerMap_.erase(id);
912 }
913
ResetAll()914 void PanRecognizer::PanVelocity::ResetAll()
915 {
916 trackerMap_.clear();
917 }
918
SetDirection(int32_t directionType)919 void PanRecognizer::PanVelocity::SetDirection(int32_t directionType)
920 {
921 auto axis = Axis::FREE;
922 if ((directionType & PanDirection::VERTICAL) == 0) {
923 axis = Axis::HORIZONTAL;
924 } else if ((directionType & PanDirection::HORIZONTAL) == 0) {
925 axis = Axis::VERTICAL;
926 }
927 axis_ = axis;
928 }
929
AddOverTimeTrace()930 void PanRecognizer::AddOverTimeTrace()
931 {
932 int64_t overTime = GetSysTimestamp();
933 int64_t inputTime = overTime;
934 if (firstInputTime_.has_value()) {
935 inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
936 }
937 if (SystemProperties::GetTraceInputEventEnabled()) {
938 ACE_SCOPED_TRACE("UserEvent InputTime:%lld OverTime:%lld InputType:PanGesture",
939 static_cast<long long>(inputTime), static_cast<long long>(overTime));
940 }
941 firstInputTime_.reset();
942 }
943
UpdateTouchEventInfo(const TouchEvent & event)944 void PanRecognizer::UpdateTouchEventInfo(const TouchEvent& event)
945 {
946 globalPoint_ = Point(event.x, event.y);
947 lastTouchEvent_ = event;
948 PointF windowPoint(event.GetOffset().GetX(), event.GetOffset().GetY());
949 PointF windowTouchPoint(touchPoints_[event.id].GetOffset().GetX(), touchPoints_[event.id].GetOffset().GetY());
950 NGGestureRecognizer::Transform(windowPoint, GetAttachedNode(), false,
951 isPostEventResult_, event.postEventNodeId);
952 NGGestureRecognizer::Transform(windowTouchPoint, GetAttachedNode(), false,
953 isPostEventResult_, event.postEventNodeId);
954 delta_ =
955 (Offset(windowPoint.GetX(), windowPoint.GetY()) - Offset(windowTouchPoint.GetX(), windowTouchPoint.GetY()));
956
957 if (SystemProperties::GetDebugEnabled()) {
958 TAG_LOGD(AceLogTag::ACE_GESTURE, "Delta is x %{public}f, y %{public}f ", delta_.GetX(), delta_.GetY());
959 }
960 mainDelta_ = GetMainAxisDelta();
961 averageDistance_ += delta_ / static_cast<double>(touchPoints_.size());
962 touchPoints_[event.id] = event;
963 touchPointsDistance_[event.id] += delta_;
964 time_ = event.time;
965 }
966
DispatchPanStartedToPerf(const TouchEvent & event)967 void PanRecognizer::DispatchPanStartedToPerf(const TouchEvent& event)
968 {
969 int64_t inputTime = event.time.time_since_epoch().count();
970 if (inputTime <= 0 || event.sourceType != SourceType::TOUCH) {
971 return;
972 }
973 PerfMonitor* pMonitor = PerfMonitor::GetPerfMonitor();
974 if (pMonitor == nullptr) {
975 return;
976 }
977 pMonitor->RecordInputEvent(FIRST_MOVE, PERF_TOUCH_EVENT, inputTime);
978 }
979 } // namespace OHOS::Ace::NG
980