• 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/gestures/drag_recognizer.h"
17 
18 #include <cmath>
19 
20 #include "base/log/log.h"
21 #include "core/gestures/gesture_referee.h"
22 
23 namespace OHOS::Ace {
24 namespace {
25 
26 #ifndef WEARABLE_PRODUCT
27 constexpr double DELTA_DURATION = 3.0;
28 #else
29 constexpr double DELTA_DURATION = 15.0;
30 #endif
31 
32 } // namespace
33 
OnAccepted(size_t touchId)34 void DragRecognizer::OnAccepted(size_t touchId)
35 {
36     LOGD("drag gesture has been accepted! the touch id is %{public}zu", touchId);
37     auto iter = dragFingers_.find(touchId);
38     if (iter == dragFingers_.end()) {
39         LOGE("the dragFingers_ is not ready to receive accepted, id is %{public}zu", touchId);
40         return;
41     }
42 
43     auto& dragInfo = iter->second;
44     dragInfo.states_ = DetectState::DETECTED;
45     if (onDragStart_) {
46         const auto& firstPoint = dragInfo.velocityTracker_.GetFirstTrackPoint();
47         DragStartInfo startInfo(firstPoint.id);
48         startInfo.SetGlobalLocation(firstPoint.GetOffset())
49             .SetLocalLocation(firstPoint.GetOffset() - coordinateOffset_);
50         startInfo.SetTimeStamp(firstPoint.time);
51         AsyncCallback(onDragStart_, startInfo);
52     }
53     if (onDragUpdate_) {
54         const auto& currentPoint = dragInfo.velocityTracker_.GetCurrentTrackPoint();
55         const auto dragOffsetInMainAxis =
56             axis_ == Axis::VERTICAL ? dragInfo.dragOffset_.GetY() : dragInfo.dragOffset_.GetX();
57         DragUpdateInfo updateInfo(currentPoint.id);
58         updateInfo.SetDelta(dragInfo.dragOffset_)
59             .SetMainDelta(dragOffsetInMainAxis)
60             .SetGlobalLocation(currentPoint.GetOffset())
61             .SetLocalLocation(currentPoint.GetOffset() - coordinateOffset_);
62         updateInfo.SetTimeStamp(currentPoint.time);
63         AsyncCallback(onDragUpdate_, updateInfo);
64     }
65 }
66 
OnRejected(size_t touchId)67 void DragRecognizer::OnRejected(size_t touchId)
68 {
69     LOGD("drag gesture has been rejected! the touch id is %{public}zu", touchId);
70     auto iter = dragFingers_.find(touchId);
71     if (iter == dragFingers_.end()) {
72         LOGE("the dragFingers_ is not ready to receive rejected, id is %{public}zu", touchId);
73         return;
74     }
75     // Resets drag state to ready.
76     iter->second.states_ = DetectState::READY;
77 }
78 
HandleTouchDownEvent(const TouchEvent & event)79 void DragRecognizer::HandleTouchDownEvent(const TouchEvent& event)
80 {
81     LOGD("drag recognizer receives touch down event, detecting drag event");
82     if ((touchRestrict_.forbiddenType & TouchRestrict::SWIPE) == TouchRestrict::SWIPE) {
83         LOGD("drag recognizer forbid swipe");
84         return;
85     }
86     if (((touchRestrict_.forbiddenType & TouchRestrict::SWIPE_HORIZONTAL) == TouchRestrict::SWIPE_HORIZONTAL) &&
87         axis_ == Axis::HORIZONTAL) {
88         LOGD("horizontal drag recognizer forbid swipe");
89         return;
90     }
91     if (((touchRestrict_.forbiddenType & TouchRestrict::SWIPE_VERTICAL) == TouchRestrict::SWIPE_VERTICAL) &&
92         axis_ == Axis::VERTICAL) {
93         LOGD("vertical drag recognizer forbid swipe");
94         return;
95     }
96     DragFingersInfo dragFingerInfo(axis_);
97     auto result = dragFingers_.insert_or_assign(event.id, dragFingerInfo);
98 
99     auto& dragInfo = result.first->second;
100     if (dragInfo.states_ == DetectState::READY) {
101         AddToReferee(event.id, Claim(this));
102         dragInfo.dragOffset_.Reset();
103         dragInfo.velocityTracker_.Reset();
104         dragInfo.velocityTracker_.UpdateTouchPoint(event);
105         dragInfo.states_ = DetectState::DETECTING;
106     } else {
107         LOGE("the state is not ready to receive touch down event, state is %{public}d, id is %{public}d",
108             dragInfo.states_, event.id);
109     }
110 }
111 
HandleTouchMoveEvent(const TouchEvent & event)112 void DragRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
113 {
114     LOGD("drag recognizer receives touch move event");
115     auto iter = dragFingers_.find(event.id);
116     if (iter == dragFingers_.end()) {
117         LOGE("the dragFingers_ is not ready to receive touch move event, id is %{public}d", event.id);
118         return;
119     }
120 
121     auto& dragInfo = iter->second;
122     dragInfo.velocityTracker_.UpdateTouchPoint(event);
123     if (dragInfo.states_ == DetectState::DETECTED) {
124         if (onDragUpdate_) {
125             DragUpdateInfo info(event.id);
126 
127             info.SetDelta(dragInfo.velocityTracker_.GetDelta())
128                 .SetMainDelta(dragInfo.velocityTracker_.GetMainAxisDeltaPos())
129                 .SetGlobalLocation(event.GetOffset())
130                 .SetLocalLocation(event.GetOffset() - coordinateOffset_);
131 
132             info.SetTimeStamp(event.time);
133             onDragUpdate_(info);
134             if (onDragUpdateNotifyCall_) {
135                 onDragUpdateNotifyCall_(event.GetOffset().GetX(), event.GetOffset().GetY(), info);
136             }
137         }
138     } else if (dragInfo.states_ == DetectState::DETECTING) {
139         dragInfo.dragOffset_ += dragInfo.velocityTracker_.GetDelta();
140         double dragOffsetInMainAxis = 0.0;
141         if (axis_ == Axis::FREE) {
142             dragOffsetInMainAxis = dragInfo.dragOffset_.GetDistance();
143         } else if (axis_ == Axis::VERTICAL) {
144             dragOffsetInMainAxis = dragInfo.dragOffset_.GetY();
145         } else {
146             dragOffsetInMainAxis = dragInfo.dragOffset_.GetX();
147         }
148         LOGD("handle move event, the drag offset is %{public}lf, axis is %{public}d", dragOffsetInMainAxis, axis_);
149         if (IsDragGestureAccept(dragOffsetInMainAxis)) {
150             LOGD("this gesture is drag, try to accept it");
151             Accept(event.id);
152         }
153     } else {
154         LOGD("state is ready, need to use touch down event to trigger, state is %{public}d", dragInfo.states_);
155     }
156 }
157 
HandleTouchUpEvent(const TouchEvent & event)158 void DragRecognizer::HandleTouchUpEvent(const TouchEvent& event)
159 {
160     LOGD("drag recognizer receives touch up event");
161     auto iter = dragFingers_.find(event.id);
162     if (iter == dragFingers_.end()) {
163         LOGE("the dragFingers_ is not ready to receive touch up event, id is %{public}d", event.id);
164         return;
165     }
166 
167     auto& dragInfo = iter->second;
168     dragInfo.velocityTracker_.UpdateTouchPoint(event, true);
169     if (dragInfo.states_ == DetectState::DETECTED) {
170         bool upSuccess = true;
171         for (auto entry = dragFingers_.begin(); entry != dragFingers_.end(); ++entry) {
172             if (entry == iter) {
173                 continue;
174             }
175             auto& otherDragInfo = entry->second;
176             if (otherDragInfo.states_ == DetectState::DETECTED) {
177                 upSuccess = false;
178             }
179         }
180         if (upSuccess) {
181             LOGD("use animation to end drag");
182             if (onDragEnd_) {
183                 DragEndInfo endInfo(event.id);
184                 endInfo.SetVelocity(dragInfo.velocityTracker_.GetVelocity())
185                     .SetMainVelocity(dragInfo.velocityTracker_.GetMainAxisVelocity())
186                     .SetGlobalLocation(event.GetOffset())
187                     .SetLocalLocation(event.GetOffset() - coordinateOffset_);
188                 endInfo.SetTimeStamp(event.time);
189                 onDragEnd_(endInfo);
190             }
191         }
192         if (onDragEndNotifyCall_) {
193             DragEndInfo endInfo(event.id);
194 
195             endInfo.SetVelocity(dragInfo.velocityTracker_.GetVelocity())
196                 .SetMainVelocity(dragInfo.velocityTracker_.GetMainAxisVelocity())
197                 .SetGlobalLocation(event.GetOffset())
198                 .SetLocalLocation(event.GetOffset() - coordinateOffset_);
199 
200             endInfo.SetTimeStamp(event.time);
201             onDragEndNotifyCall_(event.GetOffset().GetX(), event.GetOffset().GetY(), endInfo);
202             if (onDragEnd_) {
203                 AsyncCallback(onDragEnd_, endInfo);
204             }
205         }
206     } else if (dragInfo.states_ == DetectState::DETECTING) {
207         LOGD("this gesture is not drag, try to reject it");
208         Reject(event.id);
209     }
210     dragInfo.states_ = DetectState::READY;
211 }
212 
HandleTouchCancelEvent(const TouchEvent & event)213 void DragRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
214 {
215     LOGD("drag recognizer receives touch cancel event");
216     auto iter = dragFingers_.find(event.id);
217     if (iter == dragFingers_.end()) {
218         LOGE("the dragFingers_ is not ready to receive touch cancel event, id is %{public}d", event.id);
219         return;
220     }
221 
222     auto& dragInfo = iter->second;
223     if (dragInfo.states_ == DetectState::DETECTED) {
224         if (onDragCancel_) {
225             AsyncCallback(onDragCancel_);
226         }
227     } else if (dragInfo.states_ == DetectState::DETECTING) {
228         LOGD("cancel drag gesture detect, try to reject it");
229         Reject(event.id);
230     }
231     dragInfo.states_ = DetectState::READY;
232 }
233 
IsDragGestureAccept(double offset) const234 bool DragRecognizer::IsDragGestureAccept(double offset) const
235 {
236     if (std::abs(offset) > DELTA_DURATION) {
237         if (axis_ == Axis::HORIZONTAL) {
238             uint32_t flag = offset > 0 ? TouchRestrict::SWIPE_RIGHT : TouchRestrict::SWIPE_LEFT;
239             if ((touchRestrict_.forbiddenType & flag) != flag) {
240                 return true;
241             }
242         } else if (axis_ == Axis::VERTICAL) {
243             uint32_t flag = offset > 0 ? TouchRestrict::SWIPE_DOWN : TouchRestrict::SWIPE_UP;
244             if ((touchRestrict_.forbiddenType & flag) != flag) {
245                 return true;
246             }
247         } else {
248             return true;
249         }
250     }
251     return false;
252 }
253 
Accept(size_t touchId)254 void DragRecognizer::Accept(size_t touchId)
255 {
256     std::set<size_t> ids;
257     ids.insert(touchId);
258     BatchAdjudicate(ids, Claim(this), GestureDisposal::ACCEPT);
259 }
260 
Reject(size_t touchId)261 void DragRecognizer::Reject(size_t touchId)
262 {
263     std::set<size_t> ids;
264     ids.insert(touchId);
265     BatchAdjudicate(ids, Claim(this), GestureDisposal::REJECT);
266 }
267 } // namespace OHOS::Ace
268