1 /*
2 * Copyright (c) 2021 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 #include "core/gestures/gesture_referee.h"
16
17 #include "core/gestures/gesture_recognizer.h"
18
19 namespace OHOS::Ace {
20
AddMember(const RefPtr<GestureRecognizer> & recognizer)21 void GestureScope::AddMember(const RefPtr<GestureRecognizer>& recognizer)
22 {
23 if (!recognizer) {
24 LOGE("gesture recognizer is null, AddMember failed.");
25 return;
26 }
27
28 if (Existed(recognizer)) {
29 LOGW("gesture recognizer has already been added.");
30 return;
31 }
32
33 recognizer->SetRefereeState(RefereeState::DETECTING);
34
35 switch (recognizer->GetPriority()) {
36 case GesturePriority::Parallel:
37 parallelRecognizers_.emplace_back(recognizer);
38 break;
39 case GesturePriority::High:
40 highRecognizers_.emplace_back(recognizer);
41 break;
42 case GesturePriority::Low:
43 lowRecognizers_.emplace_back(recognizer);
44 break;
45 default:
46 LOGW("Add unknown type member %{public}d to referee", recognizer->GetPriority());
47 break;
48 }
49 }
50
DelMember(const RefPtr<GestureRecognizer> & recognizer)51 void GestureScope::DelMember(const RefPtr<GestureRecognizer>& recognizer)
52 {
53 if (!recognizer) {
54 LOGI("gesture recognizer is null, DelMember finish.");
55 return;
56 }
57
58 if (!Existed(recognizer)) {
59 LOGI("gesture recognizer is not existed when deleted.");
60 return;
61 }
62
63 RefereeState prevState = recognizer->GetRefereeState();
64 recognizer->SetRefereeState(RefereeState::DETECTING);
65
66 if (recognizer->GetPriority() == GesturePriority::Parallel) {
67 parallelRecognizers_.remove(recognizer);
68 return;
69 }
70
71 RemoveAndUnBlockGesture(prevState == RefereeState::PENDING, recognizer);
72 }
73
HandleGestureDisposal(const RefPtr<GestureRecognizer> & recognizer,const GestureDisposal disposal)74 void GestureScope::HandleGestureDisposal(const RefPtr<GestureRecognizer>& recognizer, const GestureDisposal disposal)
75 {
76 if (!Existed(recognizer)) {
77 LOGE("can not find the recognizer");
78 return;
79 }
80
81 GesturePriority priority = recognizer->GetPriority();
82 if (priority == GesturePriority::Parallel) {
83 HandleParallelDisposal(recognizer, disposal);
84 return;
85 }
86
87 switch (disposal) {
88 case GestureDisposal::ACCEPT:
89 HandleAcceptDisposal(recognizer);
90 break;
91 case GestureDisposal::PENDING:
92 HandlePendingDisposal(recognizer);
93 break;
94 case GestureDisposal::REJECT:
95 HandleRejectDisposal(recognizer);
96 break;
97 default:
98 LOGW("handle known gesture disposal %{public}d", disposal);
99 break;
100 }
101 }
102
HandleParallelDisposal(const RefPtr<GestureRecognizer> & recognizer,GestureDisposal disposal)103 void GestureScope::HandleParallelDisposal(const RefPtr<GestureRecognizer>& recognizer, GestureDisposal disposal)
104 {
105 if (disposal == GestureDisposal::REJECT) {
106 parallelRecognizers_.remove(recognizer);
107 recognizer->SetRefereeState(RefereeState::FAIL);
108 recognizer->OnRejected(touchId_);
109 } else if (disposal == GestureDisposal::ACCEPT) {
110 parallelRecognizers_.remove(recognizer);
111 recognizer->SetRefereeState(RefereeState::SUCCEED);
112 recognizer->OnAccepted(touchId_);
113 } else if (disposal == GestureDisposal::PENDING) {
114 recognizer->SetRefereeState(RefereeState::PENDING);
115 recognizer->OnPending(touchId_);
116 }
117 }
118
HandleAcceptDisposal(const RefPtr<GestureRecognizer> & recognizer)119 void GestureScope::HandleAcceptDisposal(const RefPtr<GestureRecognizer>& recognizer)
120 {
121 if (queryStateFunc_ && queryStateFunc_(touchId_)) {
122 LOGI("gesture has accepted in NG.");
123 recognizer->SetRefereeState(RefereeState::FAIL);
124 return;
125 }
126
127 if (CheckNeedBlocked(recognizer)) {
128 LOGI("gesture referee ready to notify block for %{public}s", AceType::TypeName(recognizer));
129 recognizer->SetRefereeState(RefereeState::BLOCKED);
130 return;
131 }
132
133 LOGI("gesture referee accept %{public}s of id %{public}zu", AceType::TypeName(recognizer), touchId_);
134 AcceptGesture(recognizer);
135 }
136
HandlePendingDisposal(const RefPtr<GestureRecognizer> & recognizer)137 void GestureScope::HandlePendingDisposal(const RefPtr<GestureRecognizer>& recognizer)
138 {
139 if (queryStateFunc_ && queryStateFunc_(touchId_)) {
140 LOGI("gesture has accepted in NG.");
141 recognizer->SetRefereeState(RefereeState::FAIL);
142 return;
143 }
144
145 if (CheckNeedBlocked(recognizer)) {
146 LOGI("gesture referee ready to notify block for %{public}s", AceType::TypeName(recognizer));
147 recognizer->SetRefereeState(RefereeState::BLOCKED);
148 return;
149 }
150
151 LOGI("gesture referee ready to notify pending for %{public}s", AceType::TypeName(recognizer));
152 recognizer->SetRefereeState(RefereeState::PENDING);
153 recognizer->OnPending(touchId_);
154 }
155
HandleRejectDisposal(const RefPtr<GestureRecognizer> & recognizer)156 void GestureScope::HandleRejectDisposal(const RefPtr<GestureRecognizer>& recognizer)
157 {
158 LOGI("gesture referee ready to notify reject for %{public}s", AceType::TypeName(recognizer));
159 RefereeState prevState = recognizer->GetRefereeState();
160 recognizer->SetRefereeState(RefereeState::FAIL);
161 recognizer->OnRejected(touchId_);
162 RemoveAndUnBlockGesture(prevState == RefereeState::PENDING, recognizer);
163 }
164
RemoveAndUnBlockGesture(bool isPrevPending,const WeakPtr<GestureRecognizer> & weakRecognizer)165 void GestureScope::RemoveAndUnBlockGesture(bool isPrevPending, const WeakPtr<GestureRecognizer>& weakRecognizer)
166 {
167 auto recognizer = weakRecognizer.Upgrade();
168 if (!recognizer) {
169 return;
170 }
171 if (recognizer->GetPriority() == GesturePriority::High) {
172 highRecognizers_.remove(recognizer);
173 if (highRecognizers_.empty()) {
174 UnBlockGesture(lowRecognizers_);
175 return;
176 }
177
178 if (isPrevPending) {
179 UnBlockGesture(highRecognizers_);
180 }
181 } else {
182 lowRecognizers_.remove(recognizer);
183 if (isPrevPending) {
184 UnBlockGesture(lowRecognizers_);
185 }
186 }
187 }
188
Existed(const RefPtr<GestureRecognizer> & recognizer)189 bool GestureScope::Existed(const RefPtr<GestureRecognizer>& recognizer)
190 {
191 if (!recognizer) {
192 LOGE("recognizer is null, AddGestureRecognizer failed.");
193 return false;
194 }
195
196 std::list<WeakPtr<GestureRecognizer>> members = GetMembersByRecognizer(recognizer);
197 if (members.empty()) {
198 return false;
199 }
200
201 auto result = std::find(members.cbegin(), members.cend(), recognizer);
202 return result != members.cend();
203 }
204
GetMembersByRecognizer(const RefPtr<GestureRecognizer> & recognizer)205 const std::list<WeakPtr<GestureRecognizer>>& GestureScope::GetMembersByRecognizer(
206 const RefPtr<GestureRecognizer>& recognizer)
207 {
208 switch (recognizer->GetPriority()) {
209 case GesturePriority::Low:
210 return lowRecognizers_;
211 case GesturePriority::High:
212 return highRecognizers_;
213 case GesturePriority::Parallel:
214 return parallelRecognizers_;
215 default:
216 return lowRecognizers_;
217 }
218 }
219
CheckNeedBlocked(const RefPtr<GestureRecognizer> & recognizer)220 bool GestureScope::CheckNeedBlocked(const RefPtr<GestureRecognizer>& recognizer)
221 {
222 if (recognizer->GetPriority() == GesturePriority::Low && !highRecognizers_.empty()) {
223 return true;
224 }
225
226 std::list<WeakPtr<GestureRecognizer>> members = GetMembersByRecognizer(recognizer);
227 for (const auto& member : members) {
228 if (member == recognizer) {
229 return false;
230 }
231
232 if (member.Upgrade() && member.Upgrade()->GetRefereeState() == RefereeState::PENDING) {
233 return true;
234 }
235 }
236
237 return false;
238 }
239
AcceptGesture(const RefPtr<GestureRecognizer> & recognizer)240 void GestureScope::AcceptGesture(const RefPtr<GestureRecognizer>& recognizer)
241 {
242 if (recognizer->GetPriority() == GesturePriority::Low) {
243 for (const auto& rejectedItem : lowRecognizers_) {
244 if (rejectedItem == recognizer) {
245 continue;
246 }
247 auto strongItem = rejectedItem.Upgrade();
248 if (strongItem) {
249 strongItem->OnRejected(touchId_);
250 strongItem->SetRefereeState(RefereeState::FAIL);
251 }
252 }
253 } else {
254 for (const auto& rejectedItem : highRecognizers_) {
255 if (rejectedItem == recognizer) {
256 continue;
257 }
258 auto strongItem = rejectedItem.Upgrade();
259 if (strongItem) {
260 strongItem->OnRejected(touchId_);
261 strongItem->SetRefereeState(RefereeState::FAIL);
262 }
263 }
264
265 for (const auto& rejectedItem : lowRecognizers_) {
266 if (rejectedItem == recognizer) {
267 continue;
268 }
269 auto strongItem = rejectedItem.Upgrade();
270 if (strongItem) {
271 strongItem->OnRejected(touchId_);
272 strongItem->SetRefereeState(RefereeState::FAIL);
273 }
274 }
275 }
276
277 recognizer->SetRefereeState(RefereeState::SUCCEED);
278 recognizer->OnAccepted(touchId_);
279 if (recognizer->GetPriority() == GesturePriority::Low) {
280 lowRecognizers_.clear();
281 } else {
282 highRecognizers_.clear();
283 lowRecognizers_.clear();
284 }
285 }
286
UnBlockGesture(std::list<WeakPtr<GestureRecognizer>> & members)287 void GestureScope::UnBlockGesture(std::list<WeakPtr<GestureRecognizer>>& members)
288 {
289 auto weakBlockedMember =
290 std::find_if(std::begin(members), std::end(members), [](const WeakPtr<GestureRecognizer>& member) {
291 return member.Upgrade() && member.Upgrade()->GetRefereeState() == RefereeState::BLOCKED;
292 });
293 if (weakBlockedMember == members.end()) {
294 return;
295 }
296 auto blockedMember = (*weakBlockedMember).Upgrade();
297 if (!blockedMember) {
298 LOGW("BlockedMember not exists.");
299 return;
300 }
301
302 if ((blockedMember)->GetDetectState() == DetectState::DETECTED) {
303 AcceptGesture(blockedMember);
304 return;
305 }
306
307 (blockedMember)->SetRefereeState(RefereeState::PENDING);
308 (blockedMember)->OnPending(touchId_);
309 }
310
ForceClose()311 void GestureScope::ForceClose()
312 {
313 for (const auto& weakRejectedItem : lowRecognizers_) {
314 auto rejectedItem = weakRejectedItem.Upgrade();
315 if (rejectedItem) {
316 rejectedItem->OnRejected(touchId_);
317 }
318 }
319 lowRecognizers_.clear();
320
321 for (const auto& weakRejectedItem : highRecognizers_) {
322 auto rejectedItem = weakRejectedItem.Upgrade();
323 if (rejectedItem) {
324 rejectedItem->OnRejected(touchId_);
325 }
326 }
327 highRecognizers_.clear();
328
329 for (const auto& weakRejectedItem : parallelRecognizers_) {
330 auto rejectedItem = weakRejectedItem.Upgrade();
331 if (rejectedItem) {
332 rejectedItem->OnRejected(touchId_);
333 }
334 }
335 parallelRecognizers_.clear();
336 }
337
IsPending() const338 bool GestureScope::IsPending() const
339 {
340 auto pendingMember = std::find_if(
341 std::begin(lowRecognizers_), std::end(lowRecognizers_), [](const WeakPtr<GestureRecognizer>& member) {
342 return member.Upgrade() && member.Upgrade()->GetRefereeState() == RefereeState::PENDING;
343 });
344 if (pendingMember != lowRecognizers_.end()) {
345 return true;
346 }
347
348 pendingMember = std::find_if(
349 std::begin(highRecognizers_), std::end(highRecognizers_), [](const WeakPtr<GestureRecognizer>& member) {
350 return member.Upgrade() && member.Upgrade()->GetRefereeState() == RefereeState::PENDING;
351 });
352 if (pendingMember != highRecognizers_.end()) {
353 return true;
354 }
355
356 pendingMember = std::find_if(
357 std::begin(parallelRecognizers_), std::end(parallelRecognizers_), [](const WeakPtr<GestureRecognizer>& member) {
358 return member.Upgrade() && member.Upgrade()->GetRefereeState() == RefereeState::PENDING;
359 });
360 return pendingMember != parallelRecognizers_.end();
361 }
362
AddGestureRecognizer(size_t touchId,const RefPtr<GestureRecognizer> & recognizer)363 void GestureReferee::AddGestureRecognizer(size_t touchId, const RefPtr<GestureRecognizer>& recognizer)
364 {
365 if (!recognizer) {
366 LOGE("recognizer is null, AddGestureRecognizer failed.");
367 return;
368 }
369 const auto iter = gestureScopes_.find(touchId);
370 if (iter != gestureScopes_.end()) {
371 iter->second.AddMember(recognizer);
372 } else {
373 GestureScope gestureScope(touchId);
374 gestureScope.AddMember(recognizer);
375 gestureScope.SetQueryStateFunc(queryStateFunc_);
376 gestureScopes_.try_emplace(touchId, std::move(gestureScope));
377 }
378 }
379
DelGestureRecognizer(size_t touchId,const RefPtr<GestureRecognizer> & recognizer)380 void GestureReferee::DelGestureRecognizer(size_t touchId, const RefPtr<GestureRecognizer>& recognizer)
381 {
382 if (!recognizer) {
383 LOGE("recognizer is null, DelGestureRecognizer failed.");
384 return;
385 }
386 const auto iter = gestureScopes_.find(touchId);
387 if (iter == gestureScopes_.end()) {
388 return;
389 }
390
391 iter->second.DelMember(recognizer);
392 }
393
CleanGestureScope(size_t touchId)394 void GestureReferee::CleanGestureScope(size_t touchId)
395 {
396 const auto iter = gestureScopes_.find(touchId);
397 if (iter != gestureScopes_.end()) {
398 if (iter->second.IsPending()) {
399 LOGE("gesture scope of touch id %{public}zu is pending, do not clean this.", touchId);
400 return;
401 }
402
403 if (!iter->second.IsEmpty()) {
404 iter->second.ForceClose();
405 }
406 gestureScopes_.erase(iter);
407 }
408 }
409
Adjudicate(size_t touchId,const RefPtr<GestureRecognizer> & recognizer,GestureDisposal disposal)410 void GestureReferee::Adjudicate(size_t touchId, const RefPtr<GestureRecognizer>& recognizer, GestureDisposal disposal)
411 {
412 if (!recognizer) {
413 LOGE("recognizer is null, Adjudicate failed.");
414 return;
415 }
416
417 const auto iter = gestureScopes_.find(touchId);
418 if (iter != gestureScopes_.end()) {
419 iter->second.HandleGestureDisposal(recognizer, disposal);
420 if (iter->second.IsEmpty()) {
421 gestureScopes_.erase(iter);
422 }
423 } else {
424 LOGE("fail to find the gesture scope for %{public}zu session id", touchId);
425 }
426 }
427
428 } // namespace OHOS::Ace
429