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