• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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