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