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/sequenced_recognizer.h"
17
18 #include <iterator>
19 #include <vector>
20
21 #include "base/memory/referenced.h"
22 #include "base/thread/task_executor.h"
23 #include "base/utils/utils.h"
24 #include "core/components_ng/gestures/gesture_referee.h"
25 #include "core/components_ng/gestures/recognizers/gesture_recognizer.h"
26 #include "core/components_ng/gestures/recognizers/multi_fingers_recognizer.h"
27 #include "core/components_ng/gestures/recognizers/recognizer_group.h"
28 #include "core/event/touch_event.h"
29 #include "core/pipeline_ng/pipeline_context.h"
30
31 namespace OHOS::Ace::NG {
32
33 namespace {
34 constexpr int32_t SEQUENCE_GESTURE_TIMEOUT = 300;
35 } // namespace
36
OnAccepted()37 void SequencedRecognizer::OnAccepted()
38 {
39 refereeState_ = RefereeState::SUCCEED;
40
41 auto iter = recognizers_.begin();
42 std::advance(iter, currentIndex_);
43 if (iter != recognizers_.end()) {
44 auto activeRecognizer = *iter;
45 if (activeRecognizer) {
46 activeRecognizer->AboutToAccept();
47 UpdateCurrentIndex();
48 }
49 }
50 }
51
OnRejected()52 void SequencedRecognizer::OnRejected()
53 {
54 refereeState_ = RefereeState::FAIL;
55
56 auto iter = recognizers_.begin();
57 std::advance(iter, currentIndex_);
58
59 while (iter != recognizers_.end()) {
60 auto recognizer = *iter;
61 if (recognizer) {
62 if (recognizer->IsBridgeMode()) {
63 continue;
64 }
65 recognizer->OnRejected();
66 recognizer->OnRejectBridgeObj();
67 }
68 ++iter;
69 }
70
71 if (currentIndex_ != -1) {
72 SendCancelMsg();
73 }
74 }
75
OnPending()76 void SequencedRecognizer::OnPending()
77 {
78 refereeState_ = RefereeState::PENDING;
79 auto iter = recognizers_.begin();
80 std::advance(iter, currentIndex_);
81 if (iter != recognizers_.end()) {
82 auto activeRecognizer = *iter;
83 CHECK_NULL_VOID(activeRecognizer);
84 if (activeRecognizer->GetGestureDisposal() == GestureDisposal::ACCEPT) {
85 activeRecognizer->AboutToAccept();
86 UpdateCurrentIndex();
87 }
88 if (activeRecognizer->GetGestureDisposal() == GestureDisposal::PENDING) {
89 activeRecognizer->OnPending();
90 }
91 }
92 }
93
OnBlocked()94 void SequencedRecognizer::OnBlocked()
95 {
96 RefPtr<NGGestureRecognizer> activeRecognizer;
97 auto iter = recognizers_.begin();
98 std::advance(iter, currentIndex_);
99 if (iter != recognizers_.end()) {
100 activeRecognizer = *iter;
101 }
102 if (disposal_ == GestureDisposal::ACCEPT) {
103 refereeState_ = RefereeState::SUCCEED_BLOCKED;
104 if (activeRecognizer) {
105 activeRecognizer->OnBlocked();
106 }
107 return;
108 }
109 if (disposal_ == GestureDisposal::PENDING) {
110 refereeState_ = RefereeState::PENDING_BLOCKED;
111 if (activeRecognizer) {
112 activeRecognizer->OnBlocked();
113 }
114 }
115 }
116
HandleEvent(const TouchEvent & point)117 bool SequencedRecognizer::HandleEvent(const TouchEvent& point)
118 {
119 if (point.type == TouchType::DOWN || point.type == TouchType::UP) {
120 if (point.sourceType == SourceType::TOUCH) {
121 inputEventType_ = InputEventType::TOUCH_SCREEN;
122 } else {
123 inputEventType_ = InputEventType::MOUSE_BUTTON;
124 }
125 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, sequenced %{public}d type: %{public}d",
126 point.touchEventId, point.id, static_cast<int32_t>(point.type));
127 }
128 auto iter = recognizers_.begin();
129 std::advance(iter, currentIndex_);
130 RefPtr<NGGestureRecognizer> curRecognizer = *iter;
131 if (!curRecognizer) {
132 if (point.type == TouchType::DOWN) {
133 TAG_LOGI(AceLogTag::ACE_GESTURE, "SequencedRecognizer curRecognizer is invalid");
134 }
135 GroupAdjudicate(AceType::Claim(this), GestureDisposal::REJECT);
136 return true;
137 }
138 if (point.type == TouchType::DOWN && !point.childTouchTestList.empty()) {
139 childTouchTestList_ = point.childTouchTestList;
140 }
141 touchPoints_[point.id] = point;
142 // the prevState is ready, need to pase down event to the new coming recognizer.
143 if (curRecognizer && curRecognizer->GetRefereeState() == RefereeState::READY) {
144 if (inputEventType_ != InputEventType::MOUSE_BUTTON || !CheckBetweenTwoLongPressRecognizer(currentIndex_)) {
145 SendTouchEventToNextRecognizer(curRecognizer);
146 }
147 }
148 switch (point.type) {
149 case TouchType::DOWN:
150 if (touchPoints_.size() == 1) {
151 deadlineTimer_.Cancel();
152 }
153 [[fallthrough]];
154 case TouchType::MOVE:
155 case TouchType::UP:
156 case TouchType::CANCEL:
157 curRecognizer->HandleEvent(point);
158 AddGestureProcedure(point, curRecognizer);
159 break;
160 default:
161 break;
162 }
163
164 if ((point.type == TouchType::UP) && (refereeState_ == RefereeState::PENDING)) {
165 DeadlineTimer();
166 }
167 return true;
168 }
169
HandleEvent(const AxisEvent & point)170 bool SequencedRecognizer::HandleEvent(const AxisEvent& point)
171 {
172 if (point.action == AxisAction::BEGIN) {
173 inputEventType_ = InputEventType::AXIS;
174 }
175 auto iter = recognizers_.begin();
176 std::advance(iter, currentIndex_);
177 RefPtr<NGGestureRecognizer> curRecognizer = *iter;
178 if (!curRecognizer) {
179 GroupAdjudicate(AceType::Claim(this), GestureDisposal::REJECT);
180 return true;
181 }
182 lastAxisEvent_ = point;
183 if (currentIndex_ > 0) {
184 auto prevState = curRecognizer->GetRefereeState();
185 if (prevState == RefereeState::READY) {
186 // the prevState is ready, need to pass axis-begin event to the new coming recognizer.
187 SendTouchEventToNextRecognizer(curRecognizer);
188 }
189 }
190 if (point.action != AxisAction::NONE) {
191 curRecognizer->HandleEvent(point);
192 }
193
194 if ((point.action == AxisAction::END) && (refereeState_ == RefereeState::PENDING)) {
195 DeadlineTimer();
196 }
197 return true;
198 }
199
BatchAdjudicate(const RefPtr<NGGestureRecognizer> & recognizer,GestureDisposal disposal)200 void SequencedRecognizer::BatchAdjudicate(const RefPtr<NGGestureRecognizer>& recognizer, GestureDisposal disposal)
201 {
202 if (disposal == GestureDisposal::ACCEPT) {
203 if (recognizer->GetRefereeState() == RefereeState::SUCCEED) {
204 return;
205 }
206 if (currentIndex_ == static_cast<int32_t>((recognizers_.size() - 1))) {
207 GroupAdjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
208 } else {
209 if (refereeState_ == RefereeState::PENDING) {
210 UpdateCurrentIndex();
211 recognizer->AboutToAccept();
212 } else {
213 GroupAdjudicate(AceType::Claim(this), GestureDisposal::PENDING);
214 }
215 }
216 return;
217 }
218 if (disposal == GestureDisposal::REJECT) {
219 if (recognizer->GetRefereeState() == RefereeState::FAIL) {
220 return;
221 }
222 if (refereeState_ == RefereeState::FAIL) {
223 recognizer->OnRejected();
224 } else {
225 GroupAdjudicate(AceType::Claim(this), GestureDisposal::REJECT);
226 }
227 return;
228 }
229
230 if (recognizer->GetRefereeState() == RefereeState::PENDING) {
231 return;
232 }
233
234 if (refereeState_ == RefereeState::PENDING) {
235 recognizer->OnPending();
236 } else {
237 GroupAdjudicate(AceType::Claim(this), GestureDisposal::PENDING);
238 }
239 }
240
UpdateCurrentIndex()241 void SequencedRecognizer::UpdateCurrentIndex()
242 {
243 if (currentIndex_ == static_cast<int32_t>((recognizers_.size() - 1))) {
244 // the last one.
245 return;
246 }
247 currentIndex_++;
248 // if the sequence recognizer between long press recognizer, auto send to next event.
249 if (isEventHandoverNeeded_ ||
250 (inputEventType_ == InputEventType::MOUSE_BUTTON && CheckBetweenTwoLongPressRecognizer(currentIndex_))) {
251 auto duration = 0;
252 auto iter = recognizers_.begin();
253 std::advance(iter, currentIndex_ - 1);
254 RefPtr<NGGestureRecognizer> curRecognizer = *iter;
255 RefPtr<LongPressRecognizer> recognizer = AceType::DynamicCast<LongPressRecognizer>(curRecognizer);
256 if (recognizer) {
257 duration = recognizer->GetDuration();
258 }
259 std::advance(iter, 1);
260 curRecognizer = *iter;
261 SendTouchEventToNextRecognizer(curRecognizer, duration);
262 }
263 }
264
CheckBetweenTwoLongPressRecognizer(int32_t currentIndex)265 bool SequencedRecognizer::CheckBetweenTwoLongPressRecognizer(int32_t currentIndex)
266 {
267 if (currentIndex <= 0 || currentIndex_ > static_cast<int32_t>(recognizers_.size()) - 1) {
268 return false;
269 }
270 auto iterBefore = recognizers_.begin();
271 std::advance(iterBefore, currentIndex - 1);
272 auto iterAfter = recognizers_.begin();
273 std::advance(iterAfter, currentIndex);
274 return AceType::InstanceOf<LongPressRecognizer>(*iterBefore) &&
275 AceType::InstanceOf<LongPressRecognizer>(*iterAfter);
276 }
277
SendTouchEventToNextRecognizer(const RefPtr<NGGestureRecognizer> curRecognizer,int64_t beforeDuration)278 void SequencedRecognizer::SendTouchEventToNextRecognizer(
279 const RefPtr<NGGestureRecognizer> curRecognizer, int64_t beforeDuration)
280 {
281 if (inputEventType_ == InputEventType::AXIS) {
282 auto event = lastAxisEvent_;
283 event.action = AxisAction::BEGIN;
284 curRecognizer->HandleEvent(event);
285 return;
286 }
287 for (auto& item : touchPoints_) {
288 item.second.type = TouchType::DOWN;
289 if (beforeDuration > 0) {
290 std::chrono::microseconds microseconds(
291 static_cast<int64_t>(item.second.time.time_since_epoch().count()) + beforeDuration);
292 TimeStamp time(microseconds);
293 item.second.time = time;
294 }
295 if (!childTouchTestList_.empty()) {
296 item.second.childTouchTestList = childTouchTestList_;
297 }
298 curRecognizer->HandleEvent(item.second);
299 AddGestureProcedure(item.second, curRecognizer);
300 }
301 }
302
OnResetStatus()303 void SequencedRecognizer::OnResetStatus()
304 {
305 RecognizerGroup::OnResetStatus();
306 currentIndex_ = 0;
307 deadlineTimer_.Cancel();
308 childTouchTestList_.clear();
309 }
310
DeadlineTimer()311 void SequencedRecognizer::DeadlineTimer()
312 {
313 auto context = PipelineContext::GetCurrentContext();
314 CHECK_NULL_VOID(context);
315
316 auto callback = [weakPtr = AceType::WeakClaim(this)]() {
317 auto refPtr = weakPtr.Upgrade();
318 if (refPtr) {
319 refPtr->HandleOverdueDeadline();
320 }
321 };
322
323 deadlineTimer_.Reset(callback);
324 auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
325 taskExecutor.PostDelayedTask(deadlineTimer_, SEQUENCE_GESTURE_TIMEOUT, "ArkUIGestureSequencedDeadlineTimer");
326 }
327
HandleOverdueDeadline()328 void SequencedRecognizer::HandleOverdueDeadline()
329 {
330 if (refereeState_ == RefereeState::PENDING) {
331 GroupAdjudicate(AceType::Claim(this), GestureDisposal::REJECT);
332 }
333 }
334
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)335 bool SequencedRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
336 {
337 RefPtr<SequencedRecognizer> curr = AceType::DynamicCast<SequencedRecognizer>(recognizer);
338 if (!curr) {
339 ResetStatus();
340 return false;
341 }
342
343 if (recognizers_.size() != curr->recognizers_.size() || priorityMask_ != curr->priorityMask_) {
344 ResetStatus();
345 return false;
346 }
347
348 auto iter = recognizers_.begin();
349 auto currIter = curr->recognizers_.begin();
350 for (size_t i = 0; i < recognizers_.size(); i++) {
351 auto child = *iter;
352 auto newChild = *currIter;
353 if (!child || !child->ReconcileFrom(newChild)) {
354 ResetStatus();
355 return false;
356 }
357 ++iter;
358 ++currIter;
359 }
360
361 onActionCancel_ = std::move(curr->onActionCancel_);
362
363 return true;
364 }
365
CleanRecognizerState()366 void SequencedRecognizer::CleanRecognizerState()
367 {
368 for (const auto& child : recognizers_) {
369 if (child) {
370 child->CleanRecognizerState();
371 }
372 }
373 if ((refereeState_ == RefereeState::SUCCEED ||
374 refereeState_ == RefereeState::FAIL ||
375 refereeState_ == RefereeState::DETECTING) &&
376 currentFingers_ == 0) {
377 refereeState_ = RefereeState::READY;
378 disposal_ = GestureDisposal::NONE;
379 }
380 currentIndex_ = 0;
381 childTouchTestList_.clear();
382 }
383
ForceCleanRecognizer()384 void SequencedRecognizer::ForceCleanRecognizer()
385 {
386 for (const auto& child : recognizers_) {
387 if (child) {
388 child->ForceCleanRecognizer();
389 }
390 }
391 MultiFingersRecognizer::ForceCleanRecognizer();
392 currentIndex_ = 0;
393 childTouchTestList_.clear();
394 }
395 } // namespace OHOS::Ace::NG
396