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/exclusive_recognizer.h"
17 
18 #include <vector>
19 
20 #include "base/geometry/offset.h"
21 #include "base/log/log.h"
22 #include "base/memory/ace_type.h"
23 #include "base/memory/referenced.h"
24 #include "base/utils/utils.h"
25 #include "core/components_ng/base/frame_node.h"
26 #include "core/components_ng/gestures/gesture_referee.h"
27 #include "core/components_ng/gestures/recognizers/click_recognizer.h"
28 #include "core/components_ng/gestures/recognizers/gesture_recognizer.h"
29 #include "core/components_ng/gestures/recognizers/multi_fingers_recognizer.h"
30 #include "core/components_ng/gestures/recognizers/recognizer_group.h"
31 
32 namespace OHOS::Ace::NG {
33 
OnAccepted()34 void ExclusiveRecognizer::OnAccepted()
35 {
36     refereeState_ = RefereeState::SUCCEED;
37     if (activeRecognizer_) {
38         activeRecognizer_->AboutToAccept();
39     }
40 
41     for (const auto& recognizer : recognizers_) {
42         if (!recognizer || recognizer == activeRecognizer_) {
43             continue;
44         }
45         if (AceType::InstanceOf<RecognizerGroup>(recognizer)) {
46             auto group = AceType::DynamicCast<RecognizerGroup>(recognizer);
47             group->ForceReject();
48             continue;
49         }
50         if (recognizer->IsBridgeMode()) {
51             continue;
52         }
53         recognizer->OnRejected();
54         recognizer->OnRejectBridgeObj();
55     }
56 }
57 
OnRejected()58 void ExclusiveRecognizer::OnRejected()
59 {
60     if (refereeState_ == RefereeState::SUCCEED) {
61         return;
62     }
63     refereeState_ = RefereeState::FAIL;
64     for (const auto& recognizer : recognizers_) {
65         if (!recognizer) {
66             continue;
67         }
68         if (AceType::InstanceOf<RecognizerGroup>(recognizer)) {
69             auto group = AceType::DynamicCast<RecognizerGroup>(recognizer);
70             group->ForceReject();
71         } else {
72             if (recognizer->IsBridgeMode()) {
73                 continue;
74             }
75             recognizer->OnRejected();
76             recognizer->OnRejectBridgeObj();
77         }
78     }
79 }
80 
OnPending()81 void ExclusiveRecognizer::OnPending()
82 {
83     refereeState_ = RefereeState::PENDING;
84     if (activeRecognizer_) {
85         activeRecognizer_->OnPending();
86     }
87 }
88 
OnBlocked()89 void ExclusiveRecognizer::OnBlocked()
90 {
91     if (disposal_ == GestureDisposal::ACCEPT) {
92         refereeState_ = RefereeState::SUCCEED_BLOCKED;
93         if (activeRecognizer_) {
94             activeRecognizer_->OnBlocked();
95         }
96         return;
97     }
98     if (disposal_ == GestureDisposal::PENDING) {
99         refereeState_ = RefereeState::PENDING_BLOCKED;
100         if (activeRecognizer_) {
101             activeRecognizer_->OnBlocked();
102         }
103     }
104 }
105 
HandleEvent(const TouchEvent & point)106 bool ExclusiveRecognizer::HandleEvent(const TouchEvent& point)
107 {
108     if (point.type == TouchType::DOWN || point.type == TouchType::UP) {
109         TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, exclusive %{public}d type: %{public}d",
110             point.touchEventId, point.id, static_cast<int32_t>(point.type));
111     }
112     switch (point.type) {
113         case TouchType::MOVE:
114         case TouchType::DOWN: {
115             if (activeRecognizer_ && activeRecognizer_->CheckTouchId(point.id)) {
116                 DispatchEventToActiveRecognizers(point);
117             } else {
118                 DispatchEventToAllRecognizers(point);
119             }
120             break;
121         }
122         case TouchType::UP:
123         case TouchType::CANCEL: {
124             DispatchEventToAllRecognizers(point);
125             break;
126         }
127         default:
128             break;
129     }
130 
131     return true;
132 }
133 
HandleEvent(const AxisEvent & event)134 bool ExclusiveRecognizer::HandleEvent(const AxisEvent& event)
135 {
136     switch (event.action) {
137         case AxisAction::BEGIN:
138         case AxisAction::UPDATE:
139         case AxisAction::END:
140         case AxisAction::CANCEL:
141         case AxisAction::NONE: {
142             if (activeRecognizer_) {
143                 activeRecognizer_->HandleEvent(event);
144             } else {
145                 auto copyRecognizers = recognizers_;
146                 for (const auto& recognizer : copyRecognizers) {
147                     if (recognizer) {
148                         recognizer->HandleEvent(event);
149                     }
150                 }
151             }
152             break;
153         }
154         default:
155             break;
156     }
157 
158     return true;
159 }
160 
CheckNeedBlocked(const RefPtr<NGGestureRecognizer> & recognizer)161 bool ExclusiveRecognizer::CheckNeedBlocked(const RefPtr<NGGestureRecognizer>& recognizer)
162 {
163     for (const auto& child : recognizers_) {
164         if (child == recognizer) {
165             return false;
166         }
167 
168         if (child && child->GetRefereeState() == RefereeState::PENDING) {
169             return true;
170         }
171     }
172     return false;
173 }
174 
UnBlockGesture()175 RefPtr<NGGestureRecognizer> ExclusiveRecognizer::UnBlockGesture()
176 {
177     auto iter =
178         std::find_if(std::begin(recognizers_), std::end(recognizers_), [](const RefPtr<NGGestureRecognizer>& member) {
179             return member && ((member->GetRefereeState() == RefereeState::PENDING_BLOCKED) ||
180                                  (member->GetRefereeState() == RefereeState::SUCCEED_BLOCKED));
181         });
182     if (iter == recognizers_.end()) {
183         return nullptr;
184     }
185     return *iter;
186 }
187 
BatchAdjudicate(const RefPtr<NGGestureRecognizer> & recognizer,GestureDisposal disposal)188 void ExclusiveRecognizer::BatchAdjudicate(const RefPtr<NGGestureRecognizer>& recognizer, GestureDisposal disposal)
189 {
190     CHECK_NULL_VOID(recognizer);
191 
192     if (IsRefereeFinished()) {
193         recognizer->OnRejected();
194         return;
195     }
196 
197     switch (disposal) {
198         case GestureDisposal::ACCEPT:
199             HandleAcceptDisposal(recognizer);
200             break;
201         case GestureDisposal::PENDING:
202             HandlePendingDisposal(recognizer);
203             break;
204         case GestureDisposal::REJECT:
205             HandleRejectDisposal(recognizer);
206             break;
207         default:
208             break;
209     }
210 }
211 
HandleAcceptDisposal(const RefPtr<NGGestureRecognizer> & recognizer)212 void ExclusiveRecognizer::HandleAcceptDisposal(const RefPtr<NGGestureRecognizer>& recognizer)
213 {
214     CHECK_NULL_VOID(recognizer);
215 
216     if (recognizer->GetRefereeState() == RefereeState::SUCCEED) {
217         return;
218     }
219 
220     if (recognizer->GetRefereeState() != RefereeState::PENDING && CheckNeedBlocked(recognizer)) {
221         recognizer->OnBlocked();
222         auto multiFingerRecognizer = AceType::DynamicCast<MultiFingersRecognizer>(recognizer);
223         if (multiFingerRecognizer) {
224             multiFingerRecognizer->SetTouchPointsForSucceedBlock();
225         }
226         return;
227     }
228     activeRecognizer_ = recognizer;
229     GroupAdjudicate(Claim(this), GestureDisposal::ACCEPT);
230 }
231 
HandlePendingDisposal(const RefPtr<NGGestureRecognizer> & recognizer)232 void ExclusiveRecognizer::HandlePendingDisposal(const RefPtr<NGGestureRecognizer>& recognizer)
233 {
234     CHECK_NULL_VOID(recognizer);
235 
236     if (recognizer->GetRefereeState() == RefereeState::PENDING) {
237         return;
238     }
239 
240     if (CheckNeedBlocked(recognizer)) {
241         recognizer->OnBlocked();
242         return;
243     }
244     activeRecognizer_ = recognizer;
245     GroupAdjudicate(Claim(this), GestureDisposal::PENDING);
246 }
247 
HandleRejectDisposal(const RefPtr<NGGestureRecognizer> & recognizer)248 void ExclusiveRecognizer::HandleRejectDisposal(const RefPtr<NGGestureRecognizer>& recognizer)
249 {
250     CHECK_NULL_VOID(recognizer);
251 
252     if (recognizer->GetRefereeState() == RefereeState::FAIL) {
253         return;
254     }
255 
256     auto prevState = recognizer->GetRefereeState();
257     recognizer->OnRejected();
258     if ((prevState == RefereeState::PENDING) && (refereeState_ == RefereeState::PENDING)) {
259         auto newBlockRecognizer = UnBlockGesture();
260         if (!newBlockRecognizer) {
261             // ask parent or global referee to unlock pending.
262             GroupAdjudicate(Claim(this), GestureDisposal::REJECT);
263             return;
264         }
265         activeRecognizer_ = newBlockRecognizer;
266         if (newBlockRecognizer->GetRefereeState() == RefereeState::PENDING_BLOCKED) {
267             // current exclusive recognizer is pending, no need to ask referee again.
268             newBlockRecognizer->OnPending();
269             return;
270         }
271         if (newBlockRecognizer->GetRefereeState() == RefereeState::SUCCEED_BLOCKED) {
272             // ask parent or global referee to unlock pending.
273             GroupAdjudicate(Claim(this), GestureDisposal::ACCEPT);
274         }
275     } else {
276         if (CheckAllFailed()) {
277             GroupAdjudicate(Claim(this), GestureDisposal::REJECT);
278         }
279     }
280 }
281 
OnResetStatus()282 void ExclusiveRecognizer::OnResetStatus()
283 {
284     RecognizerGroup::OnResetStatus();
285     activeRecognizer_ = nullptr;
286 }
287 
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)288 bool ExclusiveRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
289 {
290     auto curr = AceType::DynamicCast<ExclusiveRecognizer>(recognizer);
291     if (!curr) {
292         ResetStatus();
293         return false;
294     }
295 
296     if (recognizers_.size() != curr->recognizers_.size() || curr->priorityMask_ != priorityMask_) {
297         ResetStatus();
298         return false;
299     }
300 
301     auto currIter = curr->recognizers_.begin();
302 
303     for (auto iter = recognizers_.begin(); iter != recognizers_.end(); iter++, currIter++) {
304         auto child = *iter;
305         auto newChild = *currIter;
306         if (!child || !child->ReconcileFrom(newChild)) {
307             ResetStatus();
308             return false;
309         }
310     }
311 
312     return true;
313 }
314 
CleanRecognizerState()315 void ExclusiveRecognizer::CleanRecognizerState()
316 {
317     for (const auto& child : recognizers_) {
318         if (child) {
319             child->CleanRecognizerState();
320         }
321     }
322     if ((refereeState_ == RefereeState::SUCCEED ||
323         refereeState_ == RefereeState::FAIL ||
324         refereeState_ == RefereeState::DETECTING) &&
325         currentFingers_ == 0) {
326         refereeState_ = RefereeState::READY;
327         disposal_ = GestureDisposal::NONE;
328     }
329     activeRecognizer_ = nullptr;
330 }
331 
ForceCleanRecognizer()332 void ExclusiveRecognizer::ForceCleanRecognizer()
333 {
334     for (const auto& child : recognizers_) {
335         if (child) {
336             child->ForceCleanRecognizer();
337         }
338     }
339     MultiFingersRecognizer::ForceCleanRecognizer();
340     activeRecognizer_ = nullptr;
341 }
342 
DispatchEventToActiveRecognizers(const TouchEvent & point)343 void ExclusiveRecognizer::DispatchEventToActiveRecognizers(const TouchEvent& point)
344 {
345     if (point.type == TouchType::DOWN) {
346         auto node = activeRecognizer_->GetAttachedNode().Upgrade();
347         TAG_LOGI(AceLogTag::ACE_GESTURE,
348             "ExclusiveRecognizer receive down event has activeRecognizer, type: %{public}s, refereeState: "
349             "%{public}d, node tag = %{public}s, id = " SEC_PLD(%{public}s) ".",
350             AceType::TypeName(activeRecognizer_), activeRecognizer_->GetRefereeState(),
351             node ? node->GetTag().c_str() : "null",
352             SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
353     }
354     auto saveRecognizer = activeRecognizer_;
355     activeRecognizer_->SetEventImportGestureGroup(WeakClaim(this));
356     activeRecognizer_->HandleEvent(point);
357     AddGestureProcedure(point, saveRecognizer);
358     int32_t count = 0;
359     // if activeRecognizer_ change to another recognizer, call the handleEvent function of the new
360     // recognizer.
361     while (activeRecognizer_ && saveRecognizer != activeRecognizer_ &&
362             activeRecognizer_->CheckTouchId(point.id) &&
363             count < static_cast<int32_t>(recognizers_.size()) - 1) {
364         saveRecognizer = activeRecognizer_;
365         activeRecognizer_->SetEventImportGestureGroup(WeakClaim(this));
366         activeRecognizer_->HandleEvent(point);
367         AddGestureProcedure(point, saveRecognizer);
368         count++;
369     }
370     // if activeRecognizer_ has changed or be empty, do not dispatch to other recognizers
371     if (count > 0) {
372         return;
373     }
374     auto blockRecognizer = UnBlockGesture();
375     // ensure do not dispatch same recognizer twice
376     if (!blockRecognizer || blockRecognizer == saveRecognizer ||
377         !blockRecognizer->CheckTouchId(point.id)) {
378         return;
379     }
380     blockRecognizer->SetEventImportGestureGroup(WeakClaim(this));
381     blockRecognizer->HandleEvent(point);
382     AddGestureProcedure(point, blockRecognizer);
383     return;
384 }
385 
DispatchEventToAllRecognizers(const TouchEvent & point)386 void ExclusiveRecognizer::DispatchEventToAllRecognizers(const TouchEvent& point)
387 {
388     auto copyRecognizers = recognizers_;
389     for (const auto& recognizer : copyRecognizers) {
390         if (recognizer && recognizer->CheckTouchId(point.id)) {
391             auto saveRecognizer = recognizer;
392             recognizer->SetEventImportGestureGroup(WeakClaim(this));
393             recognizer->HandleEvent(point);
394             AddGestureProcedure(point, saveRecognizer);
395         } else if (!recognizer) {
396             if (point.type == TouchType::DOWN) {
397                 TAG_LOGI(AceLogTag::ACE_GESTURE,
398                     "ExclusiveRecognizer receive down event has no activeRecognizer recognizer is invalid");
399             }
400         } else {
401             if (point.type == TouchType::DOWN) {
402                 auto node = recognizer->GetAttachedNode().Upgrade();
403                 TAG_LOGI(AceLogTag::ACE_GESTURE,
404                     "ExclusiveRecognizer receive down event has no activeRecognizer recognizer is not in id: "
405                     "%{public}d touchTestResult, node tag = %{public}s",
406                     point.id, node ? node->GetTag().c_str() : "null");
407             }
408         }
409     }
410 }
411 } // namespace OHOS::Ace::NG
412