• 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/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