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