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