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
GetCurrentRecognizer()117 RefPtr<NGGestureRecognizer> SequencedRecognizer::GetCurrentRecognizer()
118 {
119 auto iter = recognizers_.begin();
120 std::advance(iter, currentIndex_);
121 RefPtr<NGGestureRecognizer> curRecognizer = *iter;
122 return curRecognizer;
123 }
124
CheckGroupState()125 bool SequencedRecognizer::CheckGroupState()
126 {
127 if (currentIndex_ < 0 || refereeState_ != RefereeState::PENDING) {
128 return false;
129 }
130 auto curRecognizer = GetCurrentRecognizer();
131 if (!AceType::InstanceOf<RecognizerGroup>(curRecognizer)) {
132 return curRecognizer->GetRefereeState() != RefereeState::SUCCEED_BLOCKED &&
133 curRecognizer->GetRefereeState() != RefereeState::SUCCEED &&
134 curRecognizer->GetRefereeState() != RefereeState::FAIL;
135 }
136 auto group = AceType::DynamicCast<RecognizerGroup>(curRecognizer);
137 return group && group->CheckGroupState();
138 }
139
CheckStates(size_t touchId)140 RefereeState SequencedRecognizer::CheckStates(size_t touchId)
141 {
142 int count = 0;
143 if (currentIndex_ < 0 || refereeState_ != RefereeState::PENDING) {
144 return RefereeState::READY;
145 }
146 auto curRecognizer = GetCurrentRecognizer();
147 if (!AceType::InstanceOf<RecognizerGroup>(curRecognizer)) {
148 if (curRecognizer->GetRefereeState() != RefereeState::SUCCEED_BLOCKED &&
149 curRecognizer->GetRefereeState() != RefereeState::SUCCEED &&
150 curRecognizer->GetRefereeState() != RefereeState::FAIL) {
151 count++;
152 }
153 } else {
154 auto group = AceType::DynamicCast<RecognizerGroup>(curRecognizer);
155 if (group) {
156 auto state = group->CheckStates(touchId);
157 if (state == RefereeState::PENDING) {
158 count++;
159 }
160 }
161 }
162 if (count > 0) {
163 return RefereeState::PENDING;
164 } else {
165 return RefereeState::READY;
166 }
167 }
168
NeedStartDeadlineTimerInner(const RefPtr<NGGestureRecognizer> curRecognizer,SourceTool sourceTool)169 bool SequencedRecognizer::NeedStartDeadlineTimerInner(
170 const RefPtr<NGGestureRecognizer> curRecognizer, SourceTool sourceTool)
171 {
172 if (currentIndex_ <= 0) {
173 return curRecognizer->IsAllowedType(sourceTool);
174 }
175 auto iter = recognizers_.begin();
176 std::advance(iter, currentIndex_ - 1);
177 RefPtr<NGGestureRecognizer> lastRecognizer = *iter;
178 return (lastRecognizer->GetRefereeState() == RefereeState::SUCCEED && lastRecognizer->IsAllowedType(sourceTool)) ||
179 curRecognizer->IsAllowedType(sourceTool);
180 }
181
HandleEvent(const TouchEvent & point)182 bool SequencedRecognizer::HandleEvent(const TouchEvent& point)
183 {
184 if (point.type == TouchType::DOWN || point.type == TouchType::UP) {
185 inputEventType_ = point.sourceType == SourceType::TOUCH ? InputEventType::TOUCH_SCREEN :
186 InputEventType::MOUSE_BUTTON;
187 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, sequenced %{public}d type: %{public}d",
188 point.touchEventId, point.id, static_cast<int32_t>(point.type));
189 }
190 auto iter = recognizers_.begin();
191 std::advance(iter, currentIndex_);
192 RefPtr<NGGestureRecognizer> curRecognizer = *iter;
193 if (!curRecognizer) {
194 if (point.type == TouchType::DOWN) {
195 TAG_LOGI(AceLogTag::ACE_GESTURE, "SequencedRecognizer curRecognizer is invalid");
196 }
197 GroupAdjudicate(AceType::Claim(this), GestureDisposal::REJECT);
198 return true;
199 }
200 if (point.type == TouchType::DOWN && !point.childTouchTestList.empty()) {
201 childTouchTestList_ = point.childTouchTestList;
202 }
203 touchPoints_[point.id] = point;
204 // the prevState is ready, need to pase down event to the new coming recognizer.
205 if (currentIndex_ > 0 && curRecognizer->GetRefereeState() == RefereeState::READY) {
206 if (inputEventType_ != InputEventType::MOUSE_BUTTON || !CheckBetweenTwoLongPressRecognizer(currentIndex_)) {
207 SendTouchEventToNextRecognizer(curRecognizer);
208 }
209 }
210 switch (point.type) {
211 case TouchType::DOWN:
212 if (touchPoints_.size() == 1 && curRecognizer->IsAllowedType(point.sourceTool)) {
213 deadlineTimer_.Cancel();
214 }
215 [[fallthrough]];
216 case TouchType::MOVE:
217 case TouchType::UP:
218 case TouchType::CANCEL:
219 curRecognizer->HandleEvent(point);
220 AddGestureProcedure(point, curRecognizer);
221 break;
222 default:
223 break;
224 }
225
226 if ((point.type == TouchType::UP) && (refereeState_ == RefereeState::PENDING) &&
227 NeedStartDeadlineTimerInner(curRecognizer, point.sourceTool)) {
228 DeadlineTimer();
229 }
230 return true;
231 }
232
HandleEvent(const AxisEvent & point)233 bool SequencedRecognizer::HandleEvent(const AxisEvent& point)
234 {
235 if (point.action == AxisAction::BEGIN) {
236 inputEventType_ = InputEventType::AXIS;
237 }
238 auto iter = recognizers_.begin();
239 std::advance(iter, currentIndex_);
240 RefPtr<NGGestureRecognizer> curRecognizer = *iter;
241 if (!curRecognizer) {
242 GroupAdjudicate(AceType::Claim(this), GestureDisposal::REJECT);
243 return true;
244 }
245 lastAxisEvent_ = point;
246 if (currentIndex_ > 0) {
247 auto prevState = curRecognizer->GetRefereeState();
248 if (prevState == RefereeState::READY) {
249 // the prevState is ready, need to pass axis-begin event to the new coming recognizer.
250 SendTouchEventToNextRecognizer(curRecognizer);
251 }
252 }
253 if (point.action != AxisAction::NONE) {
254 curRecognizer->HandleEvent(point);
255 }
256
257 if ((point.action == AxisAction::END) && (refereeState_ == RefereeState::PENDING) &&
258 NeedStartDeadlineTimerInner(curRecognizer, point.sourceTool)) {
259 DeadlineTimer();
260 }
261 return true;
262 }
263
BatchAdjudicate(const RefPtr<NGGestureRecognizer> & recognizer,GestureDisposal disposal)264 void SequencedRecognizer::BatchAdjudicate(const RefPtr<NGGestureRecognizer>& recognizer, GestureDisposal disposal)
265 {
266 if (disposal == GestureDisposal::ACCEPT) {
267 if (recognizer->GetRefereeState() == RefereeState::SUCCEED) {
268 return;
269 }
270 if (currentIndex_ == static_cast<int32_t>((recognizers_.size() - 1))) {
271 GroupAdjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
272 } else {
273 if (refereeState_ == RefereeState::PENDING) {
274 UpdateCurrentIndex();
275 recognizer->AboutToAccept();
276 } else {
277 GroupAdjudicate(AceType::Claim(this), GestureDisposal::PENDING);
278 }
279 }
280 return;
281 }
282 if (disposal == GestureDisposal::REJECT) {
283 if (recognizer->GetRefereeState() == RefereeState::FAIL) {
284 return;
285 }
286 if (refereeState_ == RefereeState::FAIL) {
287 recognizer->OnRejected();
288 } else {
289 GroupAdjudicate(AceType::Claim(this), GestureDisposal::REJECT);
290 }
291 return;
292 }
293
294 if (recognizer->GetRefereeState() == RefereeState::PENDING) {
295 return;
296 }
297
298 if (refereeState_ == RefereeState::PENDING) {
299 recognizer->OnPending();
300 } else {
301 GroupAdjudicate(AceType::Claim(this), GestureDisposal::PENDING);
302 }
303 }
304
UpdateCurrentIndex()305 void SequencedRecognizer::UpdateCurrentIndex()
306 {
307 if (currentIndex_ == static_cast<int32_t>((recognizers_.size() - 1))) {
308 // the last one.
309 return;
310 }
311 currentIndex_++;
312 // if the sequence recognizer between long press recognizer, auto send to next event.
313 if (isEventHandoverNeeded_ ||
314 (inputEventType_ == InputEventType::MOUSE_BUTTON && CheckBetweenTwoLongPressRecognizer(currentIndex_))) {
315 auto duration = 0;
316 auto iter = recognizers_.begin();
317 std::advance(iter, currentIndex_ - 1);
318 RefPtr<NGGestureRecognizer> curRecognizer = *iter;
319 RefPtr<LongPressRecognizer> recognizer = AceType::DynamicCast<LongPressRecognizer>(curRecognizer);
320 if (recognizer) {
321 duration = recognizer->GetDuration();
322 }
323 std::advance(iter, 1);
324 curRecognizer = *iter;
325 SendTouchEventToNextRecognizer(curRecognizer, duration);
326 }
327 }
328
CheckBetweenTwoLongPressRecognizer(int32_t currentIndex)329 bool SequencedRecognizer::CheckBetweenTwoLongPressRecognizer(int32_t currentIndex)
330 {
331 if (currentIndex <= 0 || currentIndex_ > static_cast<int32_t>(recognizers_.size()) - 1) {
332 return false;
333 }
334 auto iterBefore = recognizers_.begin();
335 std::advance(iterBefore, currentIndex - 1);
336 auto iterAfter = recognizers_.begin();
337 std::advance(iterAfter, currentIndex);
338 return AceType::InstanceOf<LongPressRecognizer>(*iterBefore) &&
339 AceType::InstanceOf<LongPressRecognizer>(*iterAfter);
340 }
341
SendTouchEventToNextRecognizer(const RefPtr<NGGestureRecognizer> curRecognizer,int64_t beforeDuration)342 void SequencedRecognizer::SendTouchEventToNextRecognizer(
343 const RefPtr<NGGestureRecognizer> curRecognizer, int64_t beforeDuration)
344 {
345 if (inputEventType_ == InputEventType::AXIS) {
346 auto event = lastAxisEvent_;
347 event.action = AxisAction::BEGIN;
348 curRecognizer->HandleEvent(event);
349 return;
350 }
351 for (auto& item : touchPoints_) {
352 item.second.type = TouchType::DOWN;
353 if (beforeDuration > 0) {
354 std::chrono::microseconds microseconds(
355 static_cast<int64_t>(item.second.time.time_since_epoch().count()) + beforeDuration);
356 TimeStamp time(microseconds);
357 item.second.time = time;
358 }
359 if (!childTouchTestList_.empty()) {
360 item.second.childTouchTestList = childTouchTestList_;
361 }
362 curRecognizer->HandleEvent(item.second);
363 AddGestureProcedure(item.second, curRecognizer);
364 }
365 }
366
OnResetStatus()367 void SequencedRecognizer::OnResetStatus()
368 {
369 RecognizerGroup::OnResetStatus();
370 currentIndex_ = 0;
371 deadlineTimer_.Cancel();
372 childTouchTestList_.clear();
373 }
374
DeadlineTimer()375 void SequencedRecognizer::DeadlineTimer()
376 {
377 auto context = PipelineContext::GetCurrentContext();
378 CHECK_NULL_VOID(context);
379
380 auto callback = [weakPtr = AceType::WeakClaim(this)]() {
381 auto refPtr = weakPtr.Upgrade();
382 if (refPtr) {
383 refPtr->HandleOverdueDeadline();
384 }
385 };
386
387 deadlineTimer_.Reset(callback);
388 auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
389 taskExecutor.PostDelayedTask(deadlineTimer_, SEQUENCE_GESTURE_TIMEOUT, "ArkUIGestureSequencedDeadlineTimer");
390 }
391
HandleOverdueDeadline()392 void SequencedRecognizer::HandleOverdueDeadline()
393 {
394 if (refereeState_ == RefereeState::PENDING) {
395 GroupAdjudicate(AceType::Claim(this), GestureDisposal::REJECT);
396 }
397 }
398
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)399 bool SequencedRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
400 {
401 RefPtr<SequencedRecognizer> curr = AceType::DynamicCast<SequencedRecognizer>(recognizer);
402 if (!curr) {
403 ResetStatus();
404 return false;
405 }
406
407 if (recognizers_.size() != curr->recognizers_.size() || priorityMask_ != curr->priorityMask_) {
408 ResetStatus();
409 return false;
410 }
411
412 auto iter = recognizers_.begin();
413 auto currIter = curr->recognizers_.begin();
414 for (size_t i = 0; i < recognizers_.size(); i++) {
415 auto child = *iter;
416 auto newChild = *currIter;
417 if (!child || !child->ReconcileFrom(newChild)) {
418 ResetStatus();
419 return false;
420 }
421 ++iter;
422 ++currIter;
423 }
424
425 onActionCancel_ = std::move(curr->onActionCancel_);
426
427 return true;
428 }
429
CleanRecognizerState()430 void SequencedRecognizer::CleanRecognizerState()
431 {
432 for (const auto& child : recognizers_) {
433 if (child) {
434 child->CleanRecognizerState();
435 }
436 }
437 if ((refereeState_ == RefereeState::SUCCEED ||
438 refereeState_ == RefereeState::FAIL ||
439 refereeState_ == RefereeState::DETECTING) &&
440 currentFingers_ == 0) {
441 refereeState_ = RefereeState::READY;
442 disposal_ = GestureDisposal::NONE;
443 }
444 currentIndex_ = 0;
445 childTouchTestList_.clear();
446 }
447
ForceCleanRecognizer()448 void SequencedRecognizer::ForceCleanRecognizer()
449 {
450 for (const auto& child : recognizers_) {
451 if (child) {
452 child->ForceCleanRecognizer();
453 }
454 }
455 MultiFingersRecognizer::ForceCleanRecognizer();
456 currentIndex_ = 0;
457 childTouchTestList_.clear();
458 }
459 } // namespace OHOS::Ace::NG
460