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