1 /*
2  * Copyright (C) 2023 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 <cfloat>
17 #include "accessibility_multifinger_multitap.h"
18 #include "hilog_wrapper.h"
19 
20 namespace OHOS {
21 namespace Accessibility {
22 namespace {
23     constexpr float SLOP_DELTA = 0.5f;
24     constexpr int32_t POINTER_COUNT_1 = 1;
25     constexpr int32_t POINTER_COUNT_2 = 2;
26     constexpr int32_t POINTER_COUNT_3 = 3;
27     constexpr int32_t POINTER_COUNT_4 = 4;
28     constexpr int32_t MULTI_FINGER_MAX_CONTINUE_TAP_NUM = 3;
29     constexpr float TOUCH_SLOP = 8.0f;
30     constexpr uint32_t MIN_MOVE_POINTER_NUM = 2;
31 } // namespace
32 
MultiFingerGestureHandler(const std::shared_ptr<AppExecFwk::EventRunner> & runner,AccessibilityMultiTapGestureRecognizer & server)33 MultiFingerGestureHandler::MultiFingerGestureHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner,
34     AccessibilityMultiTapGestureRecognizer &server) : AppExecFwk::EventHandler(runner), server_(server)
35 {
36 }
37 
IsTapGesture(const GestureType gestureType)38 bool MultiFingerGestureHandler::IsTapGesture(const GestureType gestureType)
39 {
40     if (gestureType == GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP_AND_HOLD ||
41         gestureType == GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP_AND_HOLD ||
42         gestureType == GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP_AND_HOLD ||
43         gestureType == GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP_AND_HOLD ||
44         gestureType == GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP_AND_HOLD ||
45         gestureType == GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP_AND_HOLD ||
46         gestureType == GestureType::GESTURE_INVALID) {
47         return false;
48     }
49 
50     return true;
51 }
52 
ProcessMultiFingerGestureTypeEvent(const GestureType gestureType)53 void MultiFingerGestureHandler::ProcessMultiFingerGestureTypeEvent(const GestureType gestureType)
54 {
55     HILOG_DEBUG("gesture id: %{public}d", static_cast<int32_t>(gestureType));
56 
57     if (IsTapGesture(gestureType)) {
58         if (server_.GetFingerTouchUpState() == FingerTouchUpState::ALL_FINGER_TOUCH_UP) {
59             server_.GetRecognizeListener()->MultiFingerGestureOnCompleted(gestureType);
60             server_.SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_COMPLETE);
61             server_.Clear();
62         }
63     } else {
64         if (server_.GetFingerTouchUpState() != FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP) {
65             if (gestureType != GestureType::GESTURE_INVALID) {
66                 server_.GetRecognizeListener()->MultiFingerGestureOnCompleted(gestureType);
67             }
68             server_.SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_COMPLETE);
69         }
70         server_.Clear();
71     }
72 }
73 
ProcessMultiFingerGestureEvent(const AppExecFwk::InnerEvent::Pointer & event)74 bool MultiFingerGestureHandler::ProcessMultiFingerGestureEvent(const AppExecFwk::InnerEvent::Pointer &event)
75 {
76     HILOG_DEBUG("Inner Event Id id: %{public}u", static_cast<uint32_t>(event->GetInnerEventId()));
77 
78     static std::map<uint32_t, GestureType> MULTI_GESTURE_TYPE = {
79         {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_SINGLE_TAP_MSG,
80             GestureType::GESTURE_TWO_FINGER_SINGLE_TAP},
81         {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
82         {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_DOUBLE_TAP_MSG,
83             GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP},
84         {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_DOUBLE_TAP_AND_HOLD_MSG,
85             GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP_AND_HOLD},
86         {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_TRIPLE_TAP_MSG,
87             GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP},
88         {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_TRIPLE_TAP_AND_HOLD_MSG,
89             GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP_AND_HOLD},
90         {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_SINGLE_TAP_MSG,
91             GestureType::GESTURE_THREE_FINGER_SINGLE_TAP},
92         {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
93         {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_DOUBLE_TAP_MSG,
94             GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP},
95         {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_DOUBLE_TAP_AND_HOLD_MSG,
96             GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP_AND_HOLD},
97         {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_TRIPLE_TAP_MSG,
98             GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP},
99         {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_TRIPLE_TAP_AND_HOLD_MSG,
100             GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP_AND_HOLD},
101         {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_SINGLE_TAP_MSG,
102             GestureType::GESTURE_FOUR_FINGER_SINGLE_TAP},
103         {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
104         {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_DOUBLE_TAP_MSG,
105             GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP},
106         {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_DOUBLE_TAP_AND_HOLD_MSG,
107             GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP_AND_HOLD},
108         {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_TRIPLE_TAP_MSG,
109             GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP},
110         {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_TRIPLE_TAP_AND_HOLD_MSG,
111             GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP_AND_HOLD}
112     };
113 
114     uint32_t eventId = static_cast<uint32_t>(event->GetInnerEventId());
115     if (MULTI_GESTURE_TYPE.find(eventId) == MULTI_GESTURE_TYPE.end()) {
116         return false;
117     }
118 
119     GestureType gestureType = MULTI_GESTURE_TYPE.at(eventId);
120     ProcessMultiFingerGestureTypeEvent(gestureType);
121 
122     return true;
123 }
124 
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)125 void MultiFingerGestureHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
126 {
127     HILOG_DEBUG();
128 
129     if (!event) {
130         HILOG_ERROR("event is null");
131         return;
132     }
133 
134     if (ProcessMultiFingerGestureEvent(event)) {
135         return;
136     }
137 
138     switch (event->GetInnerEventId()) {
139         case AccessibilityMultiTapGestureRecognizer::WAIT_ANOTHER_FINGER_DOWN_MSG:
140             server_.SetFingerTouchUpState(FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP);
141             break;
142         case AccessibilityMultiTapGestureRecognizer::CANCEL_WAIT_FINGER_DOWN_MSG:
143             server_.SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_NOT_START);
144             break;
145         case AccessibilityMultiTapGestureRecognizer::CANCEL_GESTURE:
146             if (server_.GetFingerTouchUpState() != FingerTouchUpState::ALL_FINGER_TOUCH_UP) {
147                 server_.SetFingerTouchUpState(FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP);
148             }
149             server_.GetRecognizeListener()->MultiFingerGestureOnCancelled(true);
150             server_.SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_CANCLE);
151             server_.Clear();
152             break;
153         default:
154             break;
155     }
156 }
157 
AccessibilityMultiTapGestureRecognizer()158 AccessibilityMultiTapGestureRecognizer::AccessibilityMultiTapGestureRecognizer()
159 {
160     HILOG_DEBUG();
161 
162 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
163     AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
164     auto display = displayMgr.GetDefaultDisplay();
165     if (!display) {
166         HILOG_ERROR("get display is nullptr");
167         return;
168     }
169 
170     float density = display->GetVirtualPixelRatio();
171     int32_t slop = static_cast<int32_t>(density * DOUBLE_TAP_SLOP + SLOP_DELTA);
172     doubleTapOffsetThresh_ = slop;
173     touchSlop_ = TOUCH_SLOP;
174     mMinPixelsBetweenSamplesX_ = MIN_PIXELS(display->GetWidth());
175     mMinPixelsBetweenSamplesY_ = MIN_PIXELS(display->GetHeight());
176 #else
177     HILOG_DEBUG("not support display manager");
178     doubleTapOffsetThresh_ = static_cast<int32_t>(1 * DOUBLE_TAP_SLOP + SLOP_DELTA);
179     touchSlop_ = TOUCH_SLOP;
180     mMinPixelsBetweenSamplesX_ = 1;
181     mMinPixelsBetweenSamplesY_ = 1;
182 #endif
183 
184     runner_ = Singleton<AccessibleAbilityManagerService>::GetInstance().GetMainRunner();
185     if (!runner_) {
186         HILOG_ERROR("get runner failed");
187         return;
188     }
189 
190     handler_ = std::make_shared<MultiFingerGestureHandler>(runner_, *this);
191     if (!handler_) {
192         HILOG_ERROR("create event handler failed");
193         return;
194     }
195 }
196 
RegisterListener(AccessibilityGestureRecognizeListener & listener)197 void AccessibilityMultiTapGestureRecognizer::RegisterListener(AccessibilityGestureRecognizeListener& listener)
198 {
199     HILOG_DEBUG();
200 
201     listener_ = &listener;
202 }
203 
CancelTwoFingerEvent()204 void AccessibilityMultiTapGestureRecognizer::CancelTwoFingerEvent()
205 {
206     HILOG_DEBUG();
207 
208     if (!handler_) {
209         HILOG_ERROR("handler_ is null ptr");
210         return;
211     }
212 
213     handler_->RemoveEvent(TWO_FINGER_SINGLE_TAP_MSG);
214     handler_->RemoveEvent(TWO_FINGER_LONG_PRESS_MSG);
215     handler_->RemoveEvent(TWO_FINGER_DOUBLE_TAP_MSG);
216     handler_->RemoveEvent(TWO_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
217     handler_->RemoveEvent(TWO_FINGER_TRIPLE_TAP_MSG);
218     handler_->RemoveEvent(TWO_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
219 }
220 
CancelThreeFingerEvent()221 void AccessibilityMultiTapGestureRecognizer::CancelThreeFingerEvent()
222 {
223     HILOG_DEBUG();
224 
225     if (!handler_) {
226         HILOG_ERROR("handler_ is null ptr");
227         return;
228     }
229 
230     handler_->RemoveEvent(THREE_FINGER_SINGLE_TAP_MSG);
231     handler_->RemoveEvent(THREE_FINGER_LONG_PRESS_MSG);
232     handler_->RemoveEvent(THREE_FINGER_DOUBLE_TAP_MSG);
233     handler_->RemoveEvent(THREE_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
234     handler_->RemoveEvent(THREE_FINGER_TRIPLE_TAP_MSG);
235     handler_->RemoveEvent(THREE_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
236 }
237 
CancelFourFingerEvent()238 void AccessibilityMultiTapGestureRecognizer::CancelFourFingerEvent()
239 {
240     HILOG_DEBUG();
241 
242     if (!handler_) {
243         HILOG_ERROR("handler_ is null ptr");
244         return;
245     }
246 
247     handler_->RemoveEvent(FOUR_FINGER_SINGLE_TAP_MSG);
248     handler_->RemoveEvent(FOUR_FINGER_LONG_PRESS_MSG);
249     handler_->RemoveEvent(FOUR_FINGER_DOUBLE_TAP_MSG);
250     handler_->RemoveEvent(FOUR_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
251     handler_->RemoveEvent(FOUR_FINGER_TRIPLE_TAP_MSG);
252     handler_->RemoveEvent(FOUR_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
253 }
254 
CancelTapAndHoldGestureEvent(const int32_t fingerNum)255 void AccessibilityMultiTapGestureRecognizer::CancelTapAndHoldGestureEvent(const int32_t fingerNum)
256 {
257     HILOG_DEBUG();
258 
259     switch (fingerNum) {
260         case POINTER_COUNT_2:
261             CancelTwoFingerEvent();
262             break;
263         case POINTER_COUNT_3:
264             CancelThreeFingerEvent();
265             break;
266         case POINTER_COUNT_4:
267             CancelFourFingerEvent();
268             break;
269         default:
270             break;
271     }
272 }
273 
CancelHoldGestureEvent()274 void AccessibilityMultiTapGestureRecognizer::CancelHoldGestureEvent()
275 {
276     HILOG_DEBUG();
277 
278     if (!handler_) {
279         HILOG_ERROR("handler_ is null ptr");
280         return;
281     }
282 
283     handler_->RemoveEvent(TWO_FINGER_LONG_PRESS_MSG);
284     handler_->RemoveEvent(TWO_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
285     handler_->RemoveEvent(TWO_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
286     handler_->RemoveEvent(THREE_FINGER_LONG_PRESS_MSG);
287     handler_->RemoveEvent(THREE_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
288     handler_->RemoveEvent(THREE_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
289     handler_->RemoveEvent(FOUR_FINGER_LONG_PRESS_MSG);
290     handler_->RemoveEvent(FOUR_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
291     handler_->RemoveEvent(FOUR_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
292 }
293 
CancelAllPenddingEvent()294 void AccessibilityMultiTapGestureRecognizer::CancelAllPenddingEvent()
295 {
296     HILOG_DEBUG();
297 
298     if (!handler_) {
299         HILOG_ERROR("handler_ is null ptr");
300         return;
301     }
302 
303     handler_->RemoveEvent(CANCEL_GESTURE);
304     handler_->RemoveEvent(CANCEL_WAIT_FINGER_DOWN_MSG);
305     CancelTwoFingerEvent();
306     CancelThreeFingerEvent();
307     CancelFourFingerEvent();
308 }
309 
Clear()310 void AccessibilityMultiTapGestureRecognizer::Clear()
311 {
312     HILOG_DEBUG();
313 
314     targetFingers_ = -1;
315     addContinueTapNum_ = 0;
316     isMoveGestureRecognizing = 0;
317     moveDirection = -1;
318     firstDownPoint_.clear();
319     lastUpPoint_.clear();
320     currentDownPoint_.clear();
321     preGesturePoint_.clear();
322     pointerRoute_.clear();
323     CancelAllPenddingEvent();
324 }
325 
CancelGesture(bool isNoDelayFlag)326 void AccessibilityMultiTapGestureRecognizer::CancelGesture(bool isNoDelayFlag)
327 {
328     HILOG_DEBUG();
329 
330     SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_CANCLE);
331 
332     if (fingerTouchUpState_ != FingerTouchUpState::ALL_FINGER_TOUCH_UP) {
333         fingerTouchUpState_ = FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP;
334     }
335 
336     if (!listener_) {
337         HILOG_ERROR("listener_ is null ptr");
338         return;
339     }
340 
341     listener_->MultiFingerGestureOnCancelled(isNoDelayFlag);
342     Clear();
343 }
344 
ParamCheck(const int32_t fingerNum)345 bool AccessibilityMultiTapGestureRecognizer::ParamCheck(const int32_t fingerNum)
346 {
347     if (static_cast<int32_t>(lastUpPoint_.size()) < fingerNum ||
348         static_cast<int32_t>(firstDownPoint_.size()) < fingerNum) {
349         HILOG_ERROR("last_up point or first_down point size is less than target fingerNum");
350         return false;
351     }
352 
353     for (int pId = 0; pId < fingerNum; pId++) {
354         if (!lastUpPoint_.count(pId) || !lastUpPoint_[pId]) {
355             HILOG_ERROR("last_up point or first_down point container has wrong value and pId is: %{public}d", pId);
356             return false;
357         }
358     }
359 
360     return true;
361 }
362 
GetLastFirstPointUpTime(const int32_t fingerNum)363 int64_t AccessibilityMultiTapGestureRecognizer::GetLastFirstPointUpTime(const int32_t fingerNum)
364 {
365     HILOG_DEBUG();
366 
367     int64_t timeRst = lastUpPoint_[0]->GetActionTime();
368     for (int32_t pId = 1; pId < fingerNum; pId++) {
369         if (lastUpPoint_[pId]->GetActionTime() < timeRst) {
370             timeRst = lastUpPoint_[pId]->GetActionTime();
371         }
372     }
373     return timeRst;
374 }
375 
IsDoubelTapSlopConditionMatch(const int32_t fingerNum,const std::vector<MMI::PointerEvent::PointerItem> & curPoints,const std::vector<MMI::PointerEvent::PointerItem> & prePoints)376 bool AccessibilityMultiTapGestureRecognizer::IsDoubelTapSlopConditionMatch(const int32_t fingerNum,
377     const std::vector<MMI::PointerEvent::PointerItem> &curPoints,
378     const std::vector<MMI::PointerEvent::PointerItem> &prePoints)
379 {
380     HILOG_DEBUG("doubleTapOffsetThresh_, %{public}d", doubleTapOffsetThresh_);
381 
382     std::vector<int32_t> excludePid(fingerNum, -1);
383     for (auto curPoint : curPoints) {
384         float moveDelta = FLT_MAX;
385         int32_t nearestPid = -1;
386         int32_t curX = curPoint.GetDisplayX();
387         int32_t curY = curPoint.GetDisplayY();
388         for (auto prePoint : prePoints) {
389             int32_t pId = prePoint.GetPointerId();
390             if (std::find(excludePid.begin(), excludePid.end(), pId) != excludePid.end()) {
391                 continue;
392             }
393             int32_t preX = prePoint.GetDisplayX();
394             int32_t preY = prePoint.GetDisplayY();
395             int32_t offsetX = curX - preX;
396             int32_t offsetY = curY - preY;
397             if (offsetX == 0 && offsetY == 0) {
398                 nearestPid = pId;
399                 moveDelta = 0;
400                 break;
401             }
402 
403             float delta = hypot(offsetX, offsetY);
404             if (delta < moveDelta) {
405                 moveDelta = delta;
406                 nearestPid = pId;
407             }
408         }
409         HILOG_DEBUG("moveDelta = %{public}f, right = %{public}d", moveDelta, doubleTapOffsetThresh_ * fingerNum);
410         if (moveDelta < doubleTapOffsetThresh_ * fingerNum) {
411             excludePid.push_back(nearestPid);
412         } else {
413             return false;
414         }
415     }
416 
417     return true;
418 }
419 
GetPointerItemWithFingerNum(int32_t fingerNum,std::vector<MMI::PointerEvent::PointerItem> & curPoints,std::vector<MMI::PointerEvent::PointerItem> & prePoints,MMI::PointerEvent & event,std::map<int32_t,std::shared_ptr<MMI::PointerEvent>> & prePointsEventInfo)420 bool AccessibilityMultiTapGestureRecognizer::GetPointerItemWithFingerNum(int32_t fingerNum,
421     std::vector<MMI::PointerEvent::PointerItem> &curPoints,
422     std::vector<MMI::PointerEvent::PointerItem> &prePoints, MMI::PointerEvent &event,
423     std::map<int32_t, std::shared_ptr<MMI::PointerEvent>> &prePointsEventInfo)
424 {
425     HILOG_DEBUG();
426 
427     std::vector<int32_t> pIds = event.GetPointerIds();
428     for (int32_t pId = 0; pId < fingerNum; pId++) {
429         if (!event.GetPointerItem(pIds[pId], curPoints[pId])) {
430             HILOG_ERROR("curPoint GetPointerItem(%{public}d) failed", pIds[pId]);
431             return false;
432         }
433         if (!prePointsEventInfo[pId]->GetPointerItem(prePointsEventInfo[pId]->GetPointerId(), prePoints[pId])) {
434             HILOG_ERROR("prePoint GetPointerItem(%{public}d) failed", prePointsEventInfo[pId]->GetPointerId());
435             return false;
436         }
437     }
438     return true;
439 }
440 
IsMultiFingerDoubleTap(MMI::PointerEvent & event,const int32_t fingerNum)441 bool AccessibilityMultiTapGestureRecognizer::IsMultiFingerDoubleTap(MMI::PointerEvent &event,
442     const int32_t fingerNum)
443 {
444     HILOG_DEBUG("fingerNum is %{public}d", fingerNum);
445 
446     if (!ParamCheck(fingerNum)) {
447         return false;
448     }
449 
450     // first pointer up time to second pointer down time
451     int64_t firstUpTime = GetLastFirstPointUpTime(fingerNum);
452     int64_t durationTime = event.GetActionTime() - firstUpTime;
453     if (durationTime > DOUBLE_TAP_TIMEOUT || durationTime < MIN_DOUBLE_TAP_TIME) {
454         HILOG_WARN("durationTime[%{public}" PRId64 "] is wrong", durationTime);
455         return false;
456     }
457 
458     std::vector<int32_t> pIds = event.GetPointerIds();
459     if (static_cast<int32_t>(pIds.size()) != fingerNum) {
460         return false;
461     }
462 
463     std::vector<MMI::PointerEvent::PointerItem> curPoints(fingerNum);
464     std::vector<MMI::PointerEvent::PointerItem> prePoints(fingerNum);
465     if (!GetPointerItemWithFingerNum(fingerNum, curPoints, prePoints, event, firstDownPoint_)) {
466         return false;
467     }
468 
469     return IsDoubelTapSlopConditionMatch(fingerNum, curPoints, prePoints);
470 }
471 
HanleFirstTouchDownEvent(MMI::PointerEvent & event)472 void AccessibilityMultiTapGestureRecognizer::HanleFirstTouchDownEvent(MMI::PointerEvent &event)
473 {
474     HILOG_DEBUG("gestureState is %{public}d, touchUpState is %{public}d", multiFingerGestureState_,
475                 fingerTouchUpState_);
476 
477     if (multiFingerGestureState_ == MultiFingerGestureState::GESTURE_WAIT) {
478         if (event.GetPointerId() == 0) {
479             fingerTouchUpState_ = FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP;
480             Clear();
481             return;
482         } else if (!handler_->HasInnerEvent(WAIT_ANOTHER_FINGER_DOWN_MSG)) {
483             HILOG_DEBUG("do not have WAIT_ANOTHER_FINGER_DOWN_MSG");
484             SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_NOT_START);
485         }
486     }
487 
488     // NOT_ALL_FINGER_TOUCH_UP state can not revice touch down event
489     if (fingerTouchUpState_ == FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP) {
490         Clear();
491         return;
492     }
493 
494     // start touch down, change fingerTouchUpState_ to TOUCH_DOWN_AFTER_ALL_FINGER_TOUCH_UP state
495     fingerTouchUpState_ = FingerTouchUpState::TOUCH_DOWN_AFTER_ALL_FINGER_TOUCH_UP;
496     firstDownPoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
497     handler_->SendEvent(WAIT_ANOTHER_FINGER_DOWN_MSG, 0, TAP_INTERVAL_TIMEOUT / US_TO_MS);
498     if (event.GetPointerIds().size() == POINTER_COUNT_1) {
499         SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_WAIT);
500     } else if (event.GetPointerIds().size() == POINTER_COUNT_2) {
501         listener_->MultiFingerGestureOnStarted(true);
502         SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_START);
503         handler_->SendEvent(TWO_FINGER_SINGLE_TAP_MSG, 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
504         handler_->SendEvent(TWO_FINGER_LONG_PRESS_MSG, 0, LONG_PRESS_TIMEOUT / US_TO_MS);
505     } else if (event.GetPointerIds().size() == POINTER_COUNT_3) {
506         listener_->MultiFingerGestureOnStarted(false);
507         handler_->SendEvent(THREE_FINGER_SINGLE_TAP_MSG, 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
508         handler_->SendEvent(THREE_FINGER_LONG_PRESS_MSG, 0, LONG_PRESS_TIMEOUT / US_TO_MS);
509     } else if (event.GetPointerIds().size() == POINTER_COUNT_4) {
510         handler_->SendEvent(FOUR_FINGER_SINGLE_TAP_MSG, 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
511         handler_->SendEvent(FOUR_FINGER_LONG_PRESS_MSG, 0, LONG_PRESS_TIMEOUT / US_TO_MS);
512     } else {
513         CancelGesture(true);
514     }
515 }
516 
HandleMultiTapEvent(MMI::PointerEvent & event,const int32_t fingerNum)517 void AccessibilityMultiTapGestureRecognizer::HandleMultiTapEvent(MMI::PointerEvent &event, const int32_t fingerNum)
518 {
519     HILOG_DEBUG("fingerNum is %{public}d", fingerNum);
520 
521     // check is double tap
522     if (static_cast<int32_t>(firstDownPoint_.size()) == fingerNum &&
523         static_cast<int32_t>(lastUpPoint_.size()) == fingerNum &&
524         IsMultiFingerDoubleTap(event, fingerNum)) {
525         addContinueTapNum_ = addContinueTapNum_ + 1;
526         HILOG_DEBUG("two finger Double tap is recognized, addContinueTapNum %{public}d", addContinueTapNum_);
527     } else {
528         addContinueTapNum_ = 0;
529     }
530     if (fingerNum < POINTER_COUNT_2 || fingerNum > POINTER_COUNT_4) {
531         HILOG_ERROR("fingerNum: %{public}d is wrong", fingerNum);
532         return;
533     }
534     if (addContinueTapNum_ >= MULTI_FINGER_MAX_CONTINUE_TAP_NUM) {
535         HILOG_ERROR("continue tap times: %{public}u is wrong", addContinueTapNum_);
536         CancelGesture(true);
537         return;
538     }
539     uint32_t fingerNumIndex = static_cast<uint32_t>(fingerNum - 2);
540     handler_->SendEvent(GESTURE_TAP_MSG[addContinueTapNum_][fingerNumIndex], 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
541     handler_->SendEvent(GESTURE_HOLD_MSG[addContinueTapNum_][fingerNumIndex], 0, LONG_PRESS_TIMEOUT / US_TO_MS);
542 }
543 
HandleContinueTouchDownEvent(MMI::PointerEvent & event)544 void AccessibilityMultiTapGestureRecognizer::HandleContinueTouchDownEvent(MMI::PointerEvent &event)
545 {
546     HILOG_DEBUG("fingerNum is %{public}d, gestureState is %{public}d, touchUpstate is %{public}d",
547         targetFingers_, multiFingerGestureState_, fingerTouchUpState_);
548 
549     if (targetFingers_ == POINTER_COUNT_1) {
550         return;
551     }
552 
553     if (multiFingerGestureState_ != MultiFingerGestureState::GESTURE_START) {
554         CancelGesture(true);
555         return;
556     }
557 
558     if (fingerTouchUpState_ == FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP) {
559         CancelGesture(true);
560         return;
561     }
562 
563     fingerTouchUpState_ = FingerTouchUpState::TOUCH_DOWN_AFTER_ALL_FINGER_TOUCH_UP;
564     int32_t pointerSize = static_cast<int32_t>(event.GetPointerIds().size());
565     if (pointerSize < targetFingers_) {
566         handler_->SendEvent(CANCEL_GESTURE, 0, TAP_INTERVAL_TIMEOUT / US_TO_MS);
567     } else if (pointerSize == targetFingers_) {
568         HandleMultiTapEvent(event, targetFingers_);
569     } else {
570         HILOG_DEBUG("current fingers is more than last touch down finger nums");
571         CancelGesture(true);
572     }
573 }
574 
storeBaseDownPoint()575 void AccessibilityMultiTapGestureRecognizer::storeBaseDownPoint()
576 {
577     HILOG_DEBUG();
578 
579     for (auto iter : currentDownPoint_) {
580         Pointer mp;
581         MMI::PointerEvent::PointerItem pointerIterm;
582         std::vector<Pointer> mpVec;
583         int32_t pId = iter.first;
584 
585         if (!iter.second->GetPointerItem(pId, pointerIterm)) {
586             HILOG_ERROR("get GetPointerItem(%{public}d) failed", pId);
587             return;
588         }
589 
590         mp.px_ = static_cast<float>(pointerIterm.GetDisplayX());
591         mp.py_ = static_cast<float>(pointerIterm.GetDisplayY());
592         mpVec.push_back(mp);
593         pointerRoute_.insert(std::make_pair(pId, mpVec));
594     }
595 }
596 
GetSwipeDirection(const int32_t dx,const int32_t dy)597 int32_t AccessibilityMultiTapGestureRecognizer::GetSwipeDirection(const int32_t dx, const int32_t dy)
598 {
599     HILOG_DEBUG();
600 
601     if (abs(dx) > abs(dy)) {
602         return (dx < 0) ? MoveGirectionType::SWIPE_LEFT : MoveGirectionType::SWIPE_RIGHT;
603     } else {
604         return (dy < 0) ? MoveGirectionType::SWIPE_UP : MoveGirectionType::SWIPE_DOWN;
605     }
606 }
607 
SaveMoveGesturePointerInfo(MMI::PointerEvent & event,const int32_t pId,const MMI::PointerEvent::PointerItem & pointerIterm,const int32_t dx,const int32_t dy)608 void AccessibilityMultiTapGestureRecognizer::SaveMoveGesturePointerInfo(MMI::PointerEvent &event,
609     const int32_t pId, const MMI::PointerEvent::PointerItem &pointerIterm, const int32_t dx, const int32_t dy)
610 {
611     HILOG_DEBUG();
612 
613     int32_t currentDirection = GetSwipeDirection(dx, dy);
614     if (!isMoveGestureRecognizing) {
615         storeBaseDownPoint();
616         moveDirection = currentDirection;
617         isMoveGestureRecognizing = true;
618         return;
619     }
620 
621     if (moveDirection != currentDirection) {
622         CancelGesture(true);
623         return;
624     }
625     Pointer mp;
626     mp.px_ = static_cast<float>(pointerIterm.GetDisplayX());
627     mp.py_ = static_cast<float>(pointerIterm.GetDisplayY());
628     pointerRoute_[pId].push_back(mp);
629     //update preGesturePoint_
630     preGesturePoint_[pId] = std::make_shared<MMI::PointerEvent>(event);
631 }
632 
GetBasePointItem(MMI::PointerEvent::PointerItem & basePointerIterm,int32_t pId,std::map<int32_t,std::shared_ptr<MMI::PointerEvent>> & pointInfo)633 bool AccessibilityMultiTapGestureRecognizer::GetBasePointItem(MMI::PointerEvent::PointerItem &basePointerIterm,
634     int32_t pId, std::map<int32_t, std::shared_ptr<MMI::PointerEvent>> &pointInfo)
635 {
636     HILOG_DEBUG();
637 
638     if (pointInfo.count(pId) == 0 || !pointInfo[pId]) {
639         return false;
640     }
641     if (!pointInfo[pId]->GetPointerItem(pointInfo[pId]->GetPointerId(), basePointerIterm)) {
642         HILOG_ERROR("base down point get GetPointerItem(%{public}d) failed", pId);
643         return false;
644     }
645 
646     return true;
647 }
648 
HandleMultiFingerMoveEvent(MMI::PointerEvent & event)649 void AccessibilityMultiTapGestureRecognizer::HandleMultiFingerMoveEvent(MMI::PointerEvent &event)
650 {
651     int32_t pIdSize = static_cast<int32_t>(event.GetPointerIds().size());
652     int32_t downPointSize = static_cast<int32_t>(currentDownPoint_.size());
653     int32_t pId = event.GetPointerId();
654     HILOG_DEBUG("pointer num is %{public}d, down pointer size is %{public}d, pointId is %{public}d", pIdSize,
655                 downPointSize, pId);
656 
657     MMI::PointerEvent::PointerItem pointerIterm;
658     if (!event.GetPointerItem(pId, pointerIterm)) {
659         HILOG_ERROR("get GetPointerItem(%{public}d) failed", pId);
660         return;
661     }
662 
663     MMI::PointerEvent::PointerItem basePointerIterm;
664     if (isMoveGestureRecognizing) {
665         if (!GetBasePointItem(basePointerIterm, pId, preGesturePoint_)) {
666             return;
667         }
668     } else {
669         if (!GetBasePointItem(basePointerIterm, pId, currentDownPoint_)) {
670             return;
671         }
672     }
673 
674     int32_t offsetX = pointerIterm.GetDisplayX() - basePointerIterm.GetDisplayX();
675     int32_t offsetY = pointerIterm.GetDisplayY() - basePointerIterm.GetDisplayY();
676     HILOG_DEBUG("current point and first down point: pid %{public}d, %{public}d, %{public}d, %{public}d, %{public}d",
677                 pId, pointerIterm.GetDisplayX(), pointerIterm.GetDisplayY(), basePointerIterm.GetDisplayX(),
678                 basePointerIterm.GetDisplayY());
679 
680     // two finger move will cancel gesture, but three or four finger move will enter move gesture recognize
681     if (!isMoveGestureRecognizing && hypot(offsetX, offsetY) > TOUCH_SLOP * downPointSize) {
682         if (downPointSize == POINTER_COUNT_2) {
683             HILOG_DEBUG("cancel gesture because finger move");
684             CancelGesture(false);
685         } else {
686             CancelThreeFingerEvent();
687             CancelFourFingerEvent();
688             SaveMoveGesturePointerInfo(event, pId, pointerIterm, offsetX, offsetY);
689         }
690     } else if (isMoveGestureRecognizing && (abs(offsetX) >= mMinPixelsBetweenSamplesX_ ||
691         abs(offsetY) >= mMinPixelsBetweenSamplesY_)) {
692         SaveMoveGesturePointerInfo(event, pId, pointerIterm, offsetX, offsetY);
693     }
694 }
695 
StoreUpPointInPointerRoute(MMI::PointerEvent & event)696 void AccessibilityMultiTapGestureRecognizer::StoreUpPointInPointerRoute(MMI::PointerEvent &event)
697 {
698     HILOG_DEBUG();
699 
700     if (!isMoveGestureRecognizing || multiFingerGestureState_ != MultiFingerGestureState::GESTURE_START) {
701         return;
702     }
703 
704     MMI::PointerEvent::PointerItem pointerIterm;
705     int32_t pId = event.GetPointerId();
706     if (!event.GetPointerItem(pId, pointerIterm)) {
707         HILOG_ERROR("get GetPointerItem(%{public}d) failed", pId);
708         return;
709     }
710 
711     MMI::PointerEvent::PointerItem basePointerIterm;
712     if (!GetBasePointItem(basePointerIterm, pId, preGesturePoint_)) {
713         return;
714     }
715 
716     int32_t offsetX = pointerIterm.GetDisplayX() - basePointerIterm.GetDisplayX();
717     int32_t offsetY = pointerIterm.GetDisplayY() - basePointerIterm.GetDisplayY();
718     if (abs(offsetX) > mMinPixelsBetweenSamplesX_ || abs(offsetY) > mMinPixelsBetweenSamplesY_) {
719         SaveMoveGesturePointerInfo(event, pId, pointerIterm, offsetX, offsetY);
720     }
721 }
722 
recognizeGesturePath(const std::vector<Pointer> & path)723 bool AccessibilityMultiTapGestureRecognizer::recognizeGesturePath(const std::vector<Pointer> &path)
724 {
725     HILOG_DEBUG();
726     if (path.size() < MIN_MOVE_POINTER_NUM) {
727         return false;
728     }
729 
730     int pathSize = static_cast<int>(path.size() - 1);
731     for (int routerIndex = 0; routerIndex < pathSize; routerIndex++) {
732         int32_t dx = static_cast<int32_t>(path[routerIndex + 1].px_ - path[routerIndex].px_);
733         int32_t dy = static_cast<int32_t>(path[routerIndex + 1].py_ - path[routerIndex].py_);
734         if (GetSwipeDirection(dx, dy) != moveDirection) {
735             return false;
736         }
737     }
738     return true;
739 }
740 
GetMoveGestureId()741 GestureType AccessibilityMultiTapGestureRecognizer::GetMoveGestureId()
742 {
743     HILOG_DEBUG();
744 
745     int32_t downPointSize = static_cast<int32_t>(currentDownPoint_.size());
746     if (downPointSize == POINTER_COUNT_3) {
747         switch (moveDirection) {
748             case MoveGirectionType::SWIPE_LEFT:
749                 return GestureType::GESTURE_THREE_FINGER_SWIPE_LEFT;
750             case MoveGirectionType::SWIPE_RIGHT:
751                 return GestureType::GESTURE_THREE_FINGER_SWIPE_RIGHT;
752             case MoveGirectionType::SWIPE_UP:
753                 return GestureType::GESTURE_THREE_FINGER_SWIPE_UP;
754             case MoveGirectionType::SWIPE_DOWN:
755                 return GestureType::GESTURE_THREE_FINGER_SWIPE_DOWN;
756             default:
757                 return GestureType::GESTURE_INVALID;
758         }
759     } else if (downPointSize == POINTER_COUNT_4) {
760         switch (moveDirection) {
761             case MoveGirectionType::SWIPE_LEFT:
762                 return GestureType::GESTURE_FOUR_FINGER_SWIPE_LEFT;
763             case MoveGirectionType::SWIPE_RIGHT:
764                 return GestureType::GESTURE_FOUR_FINGER_SWIPE_RIGHT;
765             case MoveGirectionType::SWIPE_UP:
766                 return GestureType::GESTURE_FOUR_FINGER_SWIPE_UP;
767             case MoveGirectionType::SWIPE_DOWN:
768                 return GestureType::GESTURE_FOUR_FINGER_SWIPE_DOWN;
769             default:
770                 return GestureType::GESTURE_INVALID;
771         }
772     }
773     return GestureType::GESTURE_INVALID;
774 }
775 
IsMoveGestureRecognize()776 bool AccessibilityMultiTapGestureRecognizer::IsMoveGestureRecognize()
777 {
778     HILOG_DEBUG();
779 
780     if (!isMoveGestureRecognizing || multiFingerGestureState_ != MultiFingerGestureState::GESTURE_START) {
781         return false;
782     }
783 
784     int32_t downPointSize = static_cast<int32_t>(currentDownPoint_.size());
785     if (static_cast<int32_t>(pointerRoute_.size()) != downPointSize) {
786         return false;
787     }
788 
789     for (int32_t pIndex = 0; pIndex < downPointSize; pIndex++) {
790         if (pointerRoute_.count(pIndex) == 0 || pointerRoute_[pIndex].size() < MIN_MOVE_POINTER_NUM) {
791             return false;
792         }
793         if (!recognizeGesturePath(pointerRoute_[pIndex])) {
794             return false;
795         }
796     }
797 
798     GestureType gestureId = GetMoveGestureId();
799     listener_->MultiFingerGestureOnCompleted(gestureId);
800 
801     return true;
802 }
803 
HandleMultiFingerTouchUpEvent(MMI::PointerEvent & event)804 void AccessibilityMultiTapGestureRecognizer::HandleMultiFingerTouchUpEvent(MMI::PointerEvent &event)
805 {
806     HILOG_DEBUG("gestureState is %{public}d, isFirstUp is %{public}d, target finger num is %{public}d",
807         multiFingerGestureState_, isFirstUp_, targetFingers_);
808 
809     handler_->RemoveEvent(WAIT_ANOTHER_FINGER_DOWN_MSG);
810     CancelHoldGestureEvent();
811 
812     if (multiFingerGestureState_ == MultiFingerGestureState::GESTURE_WAIT) {
813         handler_->SendEvent(CANCEL_WAIT_FINGER_DOWN_MSG, event.GetPointerIds().size(), DOUBLE_TAP_TIMEOUT / US_TO_MS);
814     }
815 
816     StoreUpPointInPointerRoute(event);
817     if (event.GetPointerIds().size() == POINTER_COUNT_1) {
818         if (IsMoveGestureRecognize()) {
819             SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_COMPLETE);
820             fingerTouchUpState_ = FingerTouchUpState::ALL_FINGER_TOUCH_UP;
821             Clear();
822             return;
823         }
824         fingerTouchUpState_ = FingerTouchUpState::ALL_FINGER_TOUCH_UP;
825         currentDownPoint_.clear();
826         preGesturePoint_.clear();
827         pointerRoute_.clear();
828         moveDirection = -1;
829         isMoveGestureRecognizing = false;
830     } else {
831         fingerTouchUpState_ = FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP;
832     }
833 
834     if (isFirstUp_) {
835         isFirstUp_ = false;
836         if (targetFingers_ != -1 && static_cast<int32_t>(event.GetPointerIds().size()) != targetFingers_) {
837             CancelGesture(true);
838             return;
839         }
840     }
841 
842     lastUpPoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
843     if (targetFingers_ == -1 && multiFingerGestureState_ == MultiFingerGestureState::GESTURE_START) {
844         targetFingers_ = static_cast<int32_t>(event.GetPointerIds().size());
845     }
846 }
847 
OnPointerEvent(MMI::PointerEvent & event)848 void AccessibilityMultiTapGestureRecognizer::OnPointerEvent(MMI::PointerEvent &event)
849 {
850     HILOG_DEBUG("gestureState is %{public}d", multiFingerGestureState_);
851 
852     switch (event.GetPointerAction()) {
853         case MMI::PointerEvent::POINTER_ACTION_DOWN:
854             // cancel last cancel event when recevie a new down event
855             CancelAllPenddingEvent();
856             isFirstUp_ = true;
857             currentDownPoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
858             preGesturePoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
859             if (targetFingers_ == -1) {
860                 HanleFirstTouchDownEvent(event);
861             } else {
862                 HandleContinueTouchDownEvent(event);
863             }
864             break;
865         case MMI::PointerEvent::POINTER_ACTION_MOVE:
866             if (multiFingerGestureState_ != MultiFingerGestureState::GESTURE_START) {
867                 return;
868             }
869             HandleMultiFingerMoveEvent(event);
870             break;
871         case MMI::PointerEvent::POINTER_ACTION_UP:
872             HandleMultiFingerTouchUpEvent(event);
873             break;
874         default:
875             break;
876     }
877     return;
878 }
879 } // namespace Accessibility
880 } // namespace OHOS
881