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