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