1885b47fbSopenharmony_ci/*
2885b47fbSopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3885b47fbSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4885b47fbSopenharmony_ci * you may not use this file except in compliance with the License.
5885b47fbSopenharmony_ci * You may obtain a copy of the License at
6885b47fbSopenharmony_ci *
7885b47fbSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8885b47fbSopenharmony_ci *
9885b47fbSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10885b47fbSopenharmony_ci * distributed under the License is distributed On an "AS IS" BASIS,
11885b47fbSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12885b47fbSopenharmony_ci * See the License for the specific language governing permissions and
13885b47fbSopenharmony_ci * limitations under the License.
14885b47fbSopenharmony_ci */
15885b47fbSopenharmony_ci
16885b47fbSopenharmony_ci#include "accessibility_gesture_recognizer.h"
17885b47fbSopenharmony_ci#include "hilog_wrapper.h"
18885b47fbSopenharmony_ci#include <cinttypes>
19885b47fbSopenharmony_ci
20885b47fbSopenharmony_cinamespace OHOS {
21885b47fbSopenharmony_cinamespace Accessibility {
22885b47fbSopenharmony_cinamespace {
23885b47fbSopenharmony_ci    constexpr int32_t LIMIT_SIZE_TWO = 2;
24885b47fbSopenharmony_ci    constexpr int32_t LIMIT_SIZE_THREE = 3;
25885b47fbSopenharmony_ci    constexpr int32_t POINTER_COUNT_1 = 1;
26885b47fbSopenharmony_ci    constexpr float EPSINON = 0.0001f;
27885b47fbSopenharmony_ci    constexpr float TOUCH_SLOP = 8.0f;
28885b47fbSopenharmony_ci} // namespace
29885b47fbSopenharmony_ci
30885b47fbSopenharmony_ciGestureHandler::GestureHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner,
31885b47fbSopenharmony_ci    AccessibilityGestureRecognizer &server) : AppExecFwk::EventHandler(runner), server_(server)
32885b47fbSopenharmony_ci{
33885b47fbSopenharmony_ci}
34885b47fbSopenharmony_ci
35885b47fbSopenharmony_civoid GestureHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
36885b47fbSopenharmony_ci{
37885b47fbSopenharmony_ci    HILOG_DEBUG();
38885b47fbSopenharmony_ci    if (!event) {
39885b47fbSopenharmony_ci        HILOG_ERROR("event is null");
40885b47fbSopenharmony_ci        return;
41885b47fbSopenharmony_ci    }
42885b47fbSopenharmony_ci
43885b47fbSopenharmony_ci    switch (event->GetInnerEventId()) {
44885b47fbSopenharmony_ci        case AccessibilityGestureRecognizer::LONG_PRESS_MSG:
45885b47fbSopenharmony_ci            RemoveEvent(AccessibilityGestureRecognizer::SINGLE_TAP_MSG);
46885b47fbSopenharmony_ci            server_.SetIsLongpress(true);
47885b47fbSopenharmony_ci            server_.MaybeRecognizeLongPress(*server_.GetCurDown());
48885b47fbSopenharmony_ci            break;
49885b47fbSopenharmony_ci        case AccessibilityGestureRecognizer::SINGLE_TAP_MSG:
50885b47fbSopenharmony_ci            if (!server_.GetContinueDown()) {
51885b47fbSopenharmony_ci                server_.SingleTapDetected();
52885b47fbSopenharmony_ci            }
53885b47fbSopenharmony_ci            break;
54885b47fbSopenharmony_ci        default:
55885b47fbSopenharmony_ci            break;
56885b47fbSopenharmony_ci    }
57885b47fbSopenharmony_ci}
58885b47fbSopenharmony_ci
59885b47fbSopenharmony_cifloat AccessibilityGestureRecognizer::GetDoubleTapMoveThreshold(float densityDpi)
60885b47fbSopenharmony_ci{
61885b47fbSopenharmony_ci    return densityDpi * (1.0f / 25.4f) * MM_PER_CM;
62885b47fbSopenharmony_ci}
63885b47fbSopenharmony_ci
64885b47fbSopenharmony_ciAccessibilityGestureRecognizer::AccessibilityGestureRecognizer()
65885b47fbSopenharmony_ci{
66885b47fbSopenharmony_ci    HILOG_DEBUG();
67885b47fbSopenharmony_ci#ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
68885b47fbSopenharmony_ci    AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
69885b47fbSopenharmony_ci    auto display = displayMgr.GetDefaultDisplay();
70885b47fbSopenharmony_ci    if (!display) {
71885b47fbSopenharmony_ci        HILOG_ERROR("get display is nullptr");
72885b47fbSopenharmony_ci        return;
73885b47fbSopenharmony_ci    }
74885b47fbSopenharmony_ci
75885b47fbSopenharmony_ci    threshold_ = GetDoubleTapMoveThreshold(display->GetDpi());
76885b47fbSopenharmony_ci    xMinPixels_ = MIN_PIXELS(display->GetWidth());
77885b47fbSopenharmony_ci    yMinPixels_ = MIN_PIXELS(display->GetHeight());
78885b47fbSopenharmony_ci
79885b47fbSopenharmony_ci    float densityPixels = display->GetVirtualPixelRatio();
80885b47fbSopenharmony_ci    int32_t slop = static_cast<int32_t>(densityPixels * DOUBLE_TAP_SLOP + 0.5f);
81885b47fbSopenharmony_ci    doubleTapScaledSlop_ = slop * slop;
82885b47fbSopenharmony_ci#else
83885b47fbSopenharmony_ci    HILOG_DEBUG("not support display manager");
84885b47fbSopenharmony_ci    threshold_ = 1;
85885b47fbSopenharmony_ci    xMinPixels_ = 1;
86885b47fbSopenharmony_ci    yMinPixels_ = 1;
87885b47fbSopenharmony_ci    int32_t slop = static_cast<int32_t>(1 * DOUBLE_TAP_SLOP + 0.5f);
88885b47fbSopenharmony_ci    doubleTapScaledSlop_ = slop * slop;
89885b47fbSopenharmony_ci#endif
90885b47fbSopenharmony_ci
91885b47fbSopenharmony_ci    runner_ = Singleton<AccessibleAbilityManagerService>::GetInstance().GetMainRunner();
92885b47fbSopenharmony_ci    if (!runner_) {
93885b47fbSopenharmony_ci        HILOG_ERROR("get runner failed");
94885b47fbSopenharmony_ci        return;
95885b47fbSopenharmony_ci    }
96885b47fbSopenharmony_ci    handler_ = std::make_shared<GestureHandler>(runner_, *this);
97885b47fbSopenharmony_ci    if (!handler_) {
98885b47fbSopenharmony_ci        HILOG_ERROR("create event handler failed");
99885b47fbSopenharmony_ci        return;
100885b47fbSopenharmony_ci    }
101885b47fbSopenharmony_ci}
102885b47fbSopenharmony_ci
103885b47fbSopenharmony_civoid AccessibilityGestureRecognizer::RegisterListener(AccessibilityGestureRecognizeListener& listener)
104885b47fbSopenharmony_ci{
105885b47fbSopenharmony_ci    HILOG_DEBUG();
106885b47fbSopenharmony_ci
107885b47fbSopenharmony_ci    listener_ = &listener;
108885b47fbSopenharmony_ci}
109885b47fbSopenharmony_ci
110885b47fbSopenharmony_civoid AccessibilityGestureRecognizer::UnregisterListener()
111885b47fbSopenharmony_ci{
112885b47fbSopenharmony_ci    HILOG_DEBUG();
113885b47fbSopenharmony_ci
114885b47fbSopenharmony_ci    listener_ = nullptr;
115885b47fbSopenharmony_ci}
116885b47fbSopenharmony_ci
117885b47fbSopenharmony_cibool AccessibilityGestureRecognizer::OnPointerEvent(MMI::PointerEvent &event)
118885b47fbSopenharmony_ci{
119885b47fbSopenharmony_ci    HILOG_DEBUG();
120885b47fbSopenharmony_ci
121885b47fbSopenharmony_ci    switch (event.GetPointerAction()) {
122885b47fbSopenharmony_ci        case MMI::PointerEvent::POINTER_ACTION_DOWN:
123885b47fbSopenharmony_ci            if (isDoubleTap_ && isLongpress_) {
124885b47fbSopenharmony_ci                HILOG_INFO("isDoubleTap and longpress, on down event");
125885b47fbSopenharmony_ci                return false;
126885b47fbSopenharmony_ci            }
127885b47fbSopenharmony_ci            if (event.GetPointerIds().size() == POINTER_COUNT_1) {
128885b47fbSopenharmony_ci                HandleTouchDownEvent(event);
129885b47fbSopenharmony_ci            } else {
130885b47fbSopenharmony_ci                Clear();
131885b47fbSopenharmony_ci                isRecognizingGesture_ = false;
132885b47fbSopenharmony_ci                isGestureStarted_ = false;
133885b47fbSopenharmony_ci                pointerRoute_.clear();
134885b47fbSopenharmony_ci            }
135885b47fbSopenharmony_ci            break;
136885b47fbSopenharmony_ci        case MMI::PointerEvent::POINTER_ACTION_MOVE:
137885b47fbSopenharmony_ci            if (isDoubleTap_ && isLongpress_) {
138885b47fbSopenharmony_ci                HILOG_DEBUG("isDoubleTap and isLongpress, send move event to Multimodel.");
139885b47fbSopenharmony_ci                return false;
140885b47fbSopenharmony_ci            }
141885b47fbSopenharmony_ci            return HandleTouchMoveEvent(event);
142885b47fbSopenharmony_ci        case MMI::PointerEvent::POINTER_ACTION_UP:
143885b47fbSopenharmony_ci            if (event.GetPointerIds().size() == POINTER_COUNT_1) {
144885b47fbSopenharmony_ci                return HandleTouchUpEvent(event);
145885b47fbSopenharmony_ci            }
146885b47fbSopenharmony_ci            break;
147885b47fbSopenharmony_ci        case MMI::PointerEvent::POINTER_ACTION_CANCEL:
148885b47fbSopenharmony_ci            Clear();
149885b47fbSopenharmony_ci            break;
150885b47fbSopenharmony_ci        default:
151885b47fbSopenharmony_ci            break;
152885b47fbSopenharmony_ci    }
153885b47fbSopenharmony_ci    if (!isRecognizingGesture_) {
154885b47fbSopenharmony_ci        return false;
155885b47fbSopenharmony_ci    }
156885b47fbSopenharmony_ci    return StandardGestureRecognizer(event);
157885b47fbSopenharmony_ci}
158885b47fbSopenharmony_ci
159885b47fbSopenharmony_civoid AccessibilityGestureRecognizer::Clear()
160885b47fbSopenharmony_ci{
161885b47fbSopenharmony_ci    HILOG_DEBUG();
162885b47fbSopenharmony_ci
163885b47fbSopenharmony_ci    isFirstTapUp_ = false;
164885b47fbSopenharmony_ci    isDoubleTap_ = false;
165885b47fbSopenharmony_ci    isGestureStarted_ = false;
166885b47fbSopenharmony_ci    isRecognizingGesture_ = false;
167885b47fbSopenharmony_ci    pointerRoute_.clear();
168885b47fbSopenharmony_ci    continueDown_ = false;
169885b47fbSopenharmony_ci    StandardGestureCanceled();
170885b47fbSopenharmony_ci}
171885b47fbSopenharmony_ci
172885b47fbSopenharmony_civoid AccessibilityGestureRecognizer::HandleTouchDownEvent(MMI::PointerEvent &event)
173885b47fbSopenharmony_ci{
174885b47fbSopenharmony_ci    HILOG_DEBUG();
175885b47fbSopenharmony_ci
176885b47fbSopenharmony_ci    Pointer mp;
177885b47fbSopenharmony_ci    MMI::PointerEvent::PointerItem pointerIterm;
178885b47fbSopenharmony_ci    if (!event.GetPointerItem(event.GetPointerId(), pointerIterm)) {
179885b47fbSopenharmony_ci        HILOG_WARN("get GetPointerItem(%{public}d) failed", event.GetPointerId());
180885b47fbSopenharmony_ci    }
181885b47fbSopenharmony_ci    mp.px_ = static_cast<float>(pointerIterm.GetDisplayX());
182885b47fbSopenharmony_ci    mp.py_ = static_cast<float>(pointerIterm.GetDisplayY());
183885b47fbSopenharmony_ci    isDoubleTap_ = false;
184885b47fbSopenharmony_ci    isRecognizingGesture_ = true;
185885b47fbSopenharmony_ci    isGestureStarted_ = false;
186885b47fbSopenharmony_ci    pointerRoute_.clear();
187885b47fbSopenharmony_ci    pointerRoute_.push_back(mp);
188885b47fbSopenharmony_ci    prePointer_ = pointerIterm;
189885b47fbSopenharmony_ci    startPointer_ = pointerIterm;
190885b47fbSopenharmony_ci    startTime_ = event.GetActionTime();
191885b47fbSopenharmony_ci}
192885b47fbSopenharmony_ci
193885b47fbSopenharmony_civoid AccessibilityGestureRecognizer::AddSwipePosition(MMI::PointerEvent::PointerItem &pointerIterm)
194885b47fbSopenharmony_ci{
195885b47fbSopenharmony_ci    HILOG_DEBUG();
196885b47fbSopenharmony_ci
197885b47fbSopenharmony_ci    Pointer mp;
198885b47fbSopenharmony_ci    prePointer_ = pointerIterm;
199885b47fbSopenharmony_ci    mp.px_ = pointerIterm.GetDisplayX();
200885b47fbSopenharmony_ci    mp.py_ = pointerIterm.GetDisplayY();
201885b47fbSopenharmony_ci    pointerRoute_.push_back(mp);
202885b47fbSopenharmony_ci}
203885b47fbSopenharmony_ci
204885b47fbSopenharmony_cibool AccessibilityGestureRecognizer::HandleTouchMoveEvent(MMI::PointerEvent &event)
205885b47fbSopenharmony_ci{
206885b47fbSopenharmony_ci    HILOG_DEBUG();
207885b47fbSopenharmony_ci
208885b47fbSopenharmony_ci    MMI::PointerEvent::PointerItem pointerIterm;
209885b47fbSopenharmony_ci    if (!event.GetPointerItem(event.GetPointerId(), pointerIterm)) {
210885b47fbSopenharmony_ci        HILOG_ERROR("get GetPointerItem(%{public}d) failed", event.GetPointerId());
211885b47fbSopenharmony_ci        return false;
212885b47fbSopenharmony_ci    }
213885b47fbSopenharmony_ci    int64_t eventTime = event.GetActionTime();
214885b47fbSopenharmony_ci    float offsetX = startPointer_.GetDisplayX() - pointerIterm.GetDisplayX();
215885b47fbSopenharmony_ci    float offsetY = startPointer_.GetDisplayY() - pointerIterm.GetDisplayY();
216885b47fbSopenharmony_ci    double duration = hypot(offsetX, offsetY);
217885b47fbSopenharmony_ci    if (isRecognizingGesture_) {
218885b47fbSopenharmony_ci        if (isDoubleTap_ && duration > TOUCH_SLOP) {
219885b47fbSopenharmony_ci            HILOG_DEBUG("Cancel double tap event because the finger moves beyond preset slop.");
220885b47fbSopenharmony_ci            isRecognizingGesture_ = false;
221885b47fbSopenharmony_ci            isDoubleTap_ = false;
222885b47fbSopenharmony_ci            return listener_->OnCancelled(event);
223885b47fbSopenharmony_ci        } else if (duration > threshold_) {
224885b47fbSopenharmony_ci            startPointer_ = pointerIterm;
225885b47fbSopenharmony_ci            startTime_ = eventTime;
226885b47fbSopenharmony_ci            isFirstTapUp_ = false;
227885b47fbSopenharmony_ci            isDoubleTap_ = false;
228885b47fbSopenharmony_ci            if (!isGestureStarted_) {
229885b47fbSopenharmony_ci                isGestureStarted_ = true;
230885b47fbSopenharmony_ci                listener_->OnStarted();
231885b47fbSopenharmony_ci                return false;
232885b47fbSopenharmony_ci            }
233885b47fbSopenharmony_ci        } else if (!isFirstTapUp_) {
234885b47fbSopenharmony_ci            int64_t durationTime = eventTime - startTime_;
235885b47fbSopenharmony_ci            int64_t thresholdTime = isGestureStarted_ ?
236885b47fbSopenharmony_ci                GESTURE_STARTED_TIME_THRESHOLD : GESTURE_NOT_STARTED_TIME_THRESHOLD;
237885b47fbSopenharmony_ci            if (durationTime > thresholdTime) {
238885b47fbSopenharmony_ci                isRecognizingGesture_ = false;
239885b47fbSopenharmony_ci                isGestureStarted_ = false;
240885b47fbSopenharmony_ci                pointerRoute_.clear();
241885b47fbSopenharmony_ci                return listener_->OnCancelled(event);
242885b47fbSopenharmony_ci            }
243885b47fbSopenharmony_ci        }
244885b47fbSopenharmony_ci        if ((abs(pointerIterm.GetDisplayX() - prePointer_.GetDisplayX())) >= xMinPixels_ ||
245885b47fbSopenharmony_ci            (abs(pointerIterm.GetDisplayY() - prePointer_.GetDisplayY())) >= yMinPixels_) {
246885b47fbSopenharmony_ci            AddSwipePosition(pointerIterm);
247885b47fbSopenharmony_ci        }
248885b47fbSopenharmony_ci    }
249885b47fbSopenharmony_ci    if (!isRecognizingGesture_) {
250885b47fbSopenharmony_ci        return false;
251885b47fbSopenharmony_ci    }
252885b47fbSopenharmony_ci
253885b47fbSopenharmony_ci    return StandardGestureRecognizer(event);
254885b47fbSopenharmony_ci}
255885b47fbSopenharmony_ci
256885b47fbSopenharmony_cibool AccessibilityGestureRecognizer::HandleTouchUpEvent(MMI::PointerEvent &event)
257885b47fbSopenharmony_ci{
258885b47fbSopenharmony_ci    HILOG_DEBUG();
259885b47fbSopenharmony_ci
260885b47fbSopenharmony_ci    Pointer mp;
261885b47fbSopenharmony_ci    MMI::PointerEvent::PointerItem pointerIterm;
262885b47fbSopenharmony_ci    if (!event.GetPointerItem(event.GetPointerId(), pointerIterm)) {
263885b47fbSopenharmony_ci        HILOG_WARN("get GetPointerItem(%{public}d) failed", event.GetPointerId());
264885b47fbSopenharmony_ci    }
265885b47fbSopenharmony_ci
266885b47fbSopenharmony_ci    if (isDoubleTap_) {
267885b47fbSopenharmony_ci        if (isLongpress_) {
268885b47fbSopenharmony_ci            HILOG_DEBUG("up event, isDoubleTap and longpress.");
269885b47fbSopenharmony_ci            return false;
270885b47fbSopenharmony_ci        } else {
271885b47fbSopenharmony_ci            HILOG_DEBUG();
272885b47fbSopenharmony_ci            return DoubleTapRecognized(event);
273885b47fbSopenharmony_ci        }
274885b47fbSopenharmony_ci    }
275885b47fbSopenharmony_ci    if (isGestureStarted_) {
276885b47fbSopenharmony_ci        if ((abs(pointerIterm.GetDisplayX() - prePointer_.GetDisplayX())) >= xMinPixels_ ||
277885b47fbSopenharmony_ci            (abs(pointerIterm.GetDisplayY() - prePointer_.GetDisplayY())) >= yMinPixels_) {
278885b47fbSopenharmony_ci            HILOG_DEBUG("Add position to pointer route.");
279885b47fbSopenharmony_ci            mp.px_ = pointerIterm.GetDisplayX();
280885b47fbSopenharmony_ci            mp.py_ = pointerIterm.GetDisplayY();
281885b47fbSopenharmony_ci            pointerRoute_.push_back(mp);
282885b47fbSopenharmony_ci        }
283885b47fbSopenharmony_ci        return recognizeDirectionGesture(event);
284885b47fbSopenharmony_ci    }
285885b47fbSopenharmony_ci    if (!isRecognizingGesture_) {
286885b47fbSopenharmony_ci        return false;
287885b47fbSopenharmony_ci    }
288885b47fbSopenharmony_ci    return StandardGestureRecognizer(event);
289885b47fbSopenharmony_ci}
290885b47fbSopenharmony_ci
291885b47fbSopenharmony_cibool AccessibilityGestureRecognizer::StandardGestureRecognizer(MMI::PointerEvent &event)
292885b47fbSopenharmony_ci{
293885b47fbSopenharmony_ci    HILOG_DEBUG();
294885b47fbSopenharmony_ci
295885b47fbSopenharmony_ci    switch (event.GetPointerAction()) {
296885b47fbSopenharmony_ci        case MMI::PointerEvent::POINTER_ACTION_DOWN:
297885b47fbSopenharmony_ci            if (event.GetPointerIds().size() == POINTER_COUNT_1) {
298885b47fbSopenharmony_ci                if (pCurDown_ && pPreUp_ && isDoubleTap(event)) {
299885b47fbSopenharmony_ci                    HILOG_DEBUG("Double tap is recognized");
300885b47fbSopenharmony_ci                    isDoubleTapdetecting_ = true;
301885b47fbSopenharmony_ci                    isDoubleTap_ = true;
302885b47fbSopenharmony_ci                } else {
303885b47fbSopenharmony_ci                    handler_->SendEvent(SINGLE_TAP_MSG, 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
304885b47fbSopenharmony_ci                }
305885b47fbSopenharmony_ci                pCurDown_ = std::make_shared<MMI::PointerEvent>(event);
306885b47fbSopenharmony_ci                isTapDown_ = true;
307885b47fbSopenharmony_ci                continueDown_ = true;
308885b47fbSopenharmony_ci                isLongpress_ = false;
309885b47fbSopenharmony_ci                handler_->RemoveEvent(LONG_PRESS_MSG);
310885b47fbSopenharmony_ci                handler_->SendEvent(LONG_PRESS_MSG, 0, LONG_PRESS_TIMEOUT / US_TO_MS);
311885b47fbSopenharmony_ci            } else {
312885b47fbSopenharmony_ci                StandardGestureCanceled();
313885b47fbSopenharmony_ci            }
314885b47fbSopenharmony_ci            break;
315885b47fbSopenharmony_ci        case MMI::PointerEvent::POINTER_ACTION_UP:
316885b47fbSopenharmony_ci            if (event.GetPointerIds().size() == POINTER_COUNT_1) {
317885b47fbSopenharmony_ci                continueDown_ = false;
318885b47fbSopenharmony_ci                if (isLongpress_) {
319885b47fbSopenharmony_ci                    handler_->RemoveEvent(SINGLE_TAP_MSG);
320885b47fbSopenharmony_ci                    isLongpress_ = false;
321885b47fbSopenharmony_ci                } else if (!isDoubleTapdetecting_ && isTapDown_) {
322885b47fbSopenharmony_ci                    isFirstTapUp_ = true;
323885b47fbSopenharmony_ci                }
324885b47fbSopenharmony_ci                pPreUp_ = std::make_unique<MMI::PointerEvent>(event);
325885b47fbSopenharmony_ci                isDoubleTapdetecting_ = false;
326885b47fbSopenharmony_ci                handler_->RemoveEvent(LONG_PRESS_MSG);
327885b47fbSopenharmony_ci            }
328885b47fbSopenharmony_ci            break;
329885b47fbSopenharmony_ci        default:
330885b47fbSopenharmony_ci            break;
331885b47fbSopenharmony_ci    }
332885b47fbSopenharmony_ci    return false;
333885b47fbSopenharmony_ci}
334885b47fbSopenharmony_ci
335885b47fbSopenharmony_civoid AccessibilityGestureRecognizer::StandardGestureCanceled()
336885b47fbSopenharmony_ci{
337885b47fbSopenharmony_ci    HILOG_DEBUG();
338885b47fbSopenharmony_ci
339885b47fbSopenharmony_ci    handler_->RemoveEvent(LONG_PRESS_MSG);
340885b47fbSopenharmony_ci    handler_->RemoveEvent(SINGLE_TAP_MSG);
341885b47fbSopenharmony_ci    isLongpress_ = false;
342885b47fbSopenharmony_ci    isDoubleTapdetecting_ = false;
343885b47fbSopenharmony_ci    isTapDown_ = false;
344885b47fbSopenharmony_ci    isDoubleTap_ = false;
345885b47fbSopenharmony_ci}
346885b47fbSopenharmony_ci
347885b47fbSopenharmony_civoid AccessibilityGestureRecognizer::SingleTapDetected()
348885b47fbSopenharmony_ci{
349885b47fbSopenharmony_ci    HILOG_DEBUG();
350885b47fbSopenharmony_ci
351885b47fbSopenharmony_ci    Clear();
352885b47fbSopenharmony_ci}
353885b47fbSopenharmony_ci
354885b47fbSopenharmony_civoid AccessibilityGestureRecognizer::MaybeRecognizeLongPress(MMI::PointerEvent &event)
355885b47fbSopenharmony_ci{
356885b47fbSopenharmony_ci    HILOG_DEBUG();
357885b47fbSopenharmony_ci}
358885b47fbSopenharmony_ci
359885b47fbSopenharmony_cibool AccessibilityGestureRecognizer::DoubleTapRecognized(MMI::PointerEvent &event)
360885b47fbSopenharmony_ci{
361885b47fbSopenharmony_ci    HILOG_DEBUG();
362885b47fbSopenharmony_ci
363885b47fbSopenharmony_ci    Clear();
364885b47fbSopenharmony_ci    return listener_->OnDoubleTap(event);
365885b47fbSopenharmony_ci}
366885b47fbSopenharmony_ci
367885b47fbSopenharmony_cibool AccessibilityGestureRecognizer::recognizeDirectionGesture(MMI::PointerEvent &event)
368885b47fbSopenharmony_ci{
369885b47fbSopenharmony_ci    HILOG_DEBUG();
370885b47fbSopenharmony_ci    if (!listener_) {
371885b47fbSopenharmony_ci        HILOG_ERROR("listener_ is nullptr.");
372885b47fbSopenharmony_ci        return false;
373885b47fbSopenharmony_ci    }
374885b47fbSopenharmony_ci
375885b47fbSopenharmony_ci    if (pointerRoute_.size() < LIMIT_SIZE_TWO) {
376885b47fbSopenharmony_ci        return listener_->OnCancelled(event);
377885b47fbSopenharmony_ci    }
378885b47fbSopenharmony_ci
379885b47fbSopenharmony_ci    // Check the angle of the most recent motion vector versus the preceding motion vector,
380885b47fbSopenharmony_ci    // segment the line if the angle is about 90 degrees.
381885b47fbSopenharmony_ci    std::vector<Pointer> pointerPath = GetPointerPath(pointerRoute_);
382885b47fbSopenharmony_ci
383885b47fbSopenharmony_ci    if (pointerPath.size() == LIMIT_SIZE_TWO) {
384885b47fbSopenharmony_ci        int32_t swipeDirection = GetSwipeDirection(pointerPath[0], pointerPath[1]);
385885b47fbSopenharmony_ci        return listener_->OnCompleted(GESTURE_DIRECTION[swipeDirection]);
386885b47fbSopenharmony_ci    } else if (pointerPath.size() == LIMIT_SIZE_THREE) {
387885b47fbSopenharmony_ci        int32_t swipeDirectionH = GetSwipeDirection(pointerPath[0], pointerPath[1]);
388885b47fbSopenharmony_ci        int32_t swipeDirectionHV = GetSwipeDirection(pointerPath[1], pointerPath[2]);
389885b47fbSopenharmony_ci        return listener_->OnCompleted(GESTURE_DIRECTION_TO_ID[swipeDirectionH][swipeDirectionHV]);
390885b47fbSopenharmony_ci    }
391885b47fbSopenharmony_ci    return listener_->OnCancelled(event);
392885b47fbSopenharmony_ci}
393885b47fbSopenharmony_ci
394885b47fbSopenharmony_ciint32_t AccessibilityGestureRecognizer::GetSwipeDirection(Pointer firstP, Pointer secondP)
395885b47fbSopenharmony_ci{
396885b47fbSopenharmony_ci    float offsetX = secondP.px_ - firstP.px_;
397885b47fbSopenharmony_ci    float offsetY = secondP.py_ - firstP.py_;
398885b47fbSopenharmony_ci    if (abs(offsetX) > abs(offsetY)) {
399885b47fbSopenharmony_ci        return offsetX > EPSINON ? SWIPE_RIGHT : SWIPE_LEFT;
400885b47fbSopenharmony_ci    } else {
401885b47fbSopenharmony_ci        return offsetY < EPSINON ? SWIPE_UP : SWIPE_DOWN;
402885b47fbSopenharmony_ci    }
403885b47fbSopenharmony_ci}
404885b47fbSopenharmony_ci
405885b47fbSopenharmony_cistd::vector<Pointer> AccessibilityGestureRecognizer::GetPointerPath(std::vector<Pointer> &route)
406885b47fbSopenharmony_ci{
407885b47fbSopenharmony_ci    HILOG_DEBUG();
408885b47fbSopenharmony_ci
409885b47fbSopenharmony_ci    std::vector<Pointer> pointerPath;
410885b47fbSopenharmony_ci    Pointer firstSeparation = route[0];
411885b47fbSopenharmony_ci    Pointer nextPoint;
412885b47fbSopenharmony_ci    Pointer newSeparation;
413885b47fbSopenharmony_ci    float xUnitVector = 0;
414885b47fbSopenharmony_ci    float yUnitVector = 0;
415885b47fbSopenharmony_ci    float xVector = 0;
416885b47fbSopenharmony_ci    float yVector = 0;
417885b47fbSopenharmony_ci    float vectorLength = 0;
418885b47fbSopenharmony_ci    int32_t numSinceFirstSep = 0;
419885b47fbSopenharmony_ci
420885b47fbSopenharmony_ci    pointerPath.push_back(firstSeparation);
421885b47fbSopenharmony_ci    for (size_t i = 1; i < route.size(); i++) {
422885b47fbSopenharmony_ci        nextPoint = route[i];
423885b47fbSopenharmony_ci        if (numSinceFirstSep > 0) {
424885b47fbSopenharmony_ci            xVector = xUnitVector / numSinceFirstSep;
425885b47fbSopenharmony_ci            yVector = yUnitVector / numSinceFirstSep;
426885b47fbSopenharmony_ci            newSeparation.px_ = vectorLength * xVector + firstSeparation.px_;
427885b47fbSopenharmony_ci            newSeparation.py_ = vectorLength * yVector + firstSeparation.py_;
428885b47fbSopenharmony_ci
429885b47fbSopenharmony_ci            float xNextUnitVector = nextPoint.px_ - newSeparation.px_;
430885b47fbSopenharmony_ci            float yNextUnitVector = nextPoint.py_ - newSeparation.py_;
431885b47fbSopenharmony_ci            float nextVectorLength = hypot(xNextUnitVector, yNextUnitVector);
432885b47fbSopenharmony_ci            if (nextVectorLength > EPSINON) {
433885b47fbSopenharmony_ci                xNextUnitVector /= nextVectorLength;
434885b47fbSopenharmony_ci                yNextUnitVector /= nextVectorLength;
435885b47fbSopenharmony_ci            }
436885b47fbSopenharmony_ci
437885b47fbSopenharmony_ci            if ((xVector * xNextUnitVector + yVector * yNextUnitVector) < DEGREES_THRESHOLD) {
438885b47fbSopenharmony_ci                pointerPath.push_back(newSeparation);
439885b47fbSopenharmony_ci                firstSeparation = newSeparation;
440885b47fbSopenharmony_ci                xUnitVector = 0;
441885b47fbSopenharmony_ci                yUnitVector = 0;
442885b47fbSopenharmony_ci                numSinceFirstSep = 0;
443885b47fbSopenharmony_ci            }
444885b47fbSopenharmony_ci        }
445885b47fbSopenharmony_ci        xVector = nextPoint.px_ - firstSeparation.px_;
446885b47fbSopenharmony_ci        yVector = nextPoint.py_ - firstSeparation.py_;
447885b47fbSopenharmony_ci        vectorLength = hypot(xVector, yVector);
448885b47fbSopenharmony_ci        numSinceFirstSep += 1;
449885b47fbSopenharmony_ci        if (vectorLength > EPSINON) {
450885b47fbSopenharmony_ci            xUnitVector += xVector / vectorLength;
451885b47fbSopenharmony_ci            yUnitVector += yVector / vectorLength;
452885b47fbSopenharmony_ci        }
453885b47fbSopenharmony_ci    }
454885b47fbSopenharmony_ci    pointerPath.push_back(nextPoint);
455885b47fbSopenharmony_ci    return pointerPath;
456885b47fbSopenharmony_ci}
457885b47fbSopenharmony_ci
458885b47fbSopenharmony_cibool AccessibilityGestureRecognizer::isDoubleTap(MMI::PointerEvent &event)
459885b47fbSopenharmony_ci{
460885b47fbSopenharmony_ci    HILOG_DEBUG();
461885b47fbSopenharmony_ci    int64_t durationTime = event.GetActionTime() - pPreUp_->GetActionTime();
462885b47fbSopenharmony_ci    if (!(durationTime <= DOUBLE_TAP_TIMEOUT)) {
463885b47fbSopenharmony_ci        HILOG_WARN("durationTime[%{public}" PRId64 "] is wrong", durationTime);
464885b47fbSopenharmony_ci        return false;
465885b47fbSopenharmony_ci    }
466885b47fbSopenharmony_ci
467885b47fbSopenharmony_ci    MMI::PointerEvent::PointerItem curPI;
468885b47fbSopenharmony_ci    if (!event.GetPointerItem(event.GetPointerId(), curPI)) {
469885b47fbSopenharmony_ci        HILOG_WARN("get GetPointerItem(%{public}d) failed", event.GetPointerId());
470885b47fbSopenharmony_ci    }
471885b47fbSopenharmony_ci
472885b47fbSopenharmony_ci    MMI::PointerEvent::PointerItem firstPI;
473885b47fbSopenharmony_ci    pCurDown_->GetPointerItem(pCurDown_->GetPointerId(), firstPI);
474885b47fbSopenharmony_ci    int32_t durationX = firstPI.GetDisplayX() - curPI.GetDisplayX();
475885b47fbSopenharmony_ci    int32_t durationY = firstPI.GetDisplayY() - curPI.GetDisplayY();
476885b47fbSopenharmony_ci
477885b47fbSopenharmony_ci    return (durationX * durationX + durationY * durationY < doubleTapScaledSlop_);
478885b47fbSopenharmony_ci}
479885b47fbSopenharmony_ci} // namespace Accessibility
480885b47fbSopenharmony_ci} // namespace OHOS
481