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