1 /*
2  * Copyright (C) 2022 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 #ifndef ACCESSIBILITY_GESTURE_RECOGNIZER_H
17 #define ACCESSIBILITY_GESTURE_RECOGNIZER_H
18 
19 #include <cmath>
20 #include <vector>
21 
22 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
23 #include "accessibility_display_manager.h"
24 #endif
25 #include "accessibility_event_info.h"
26 #include "accessible_ability_manager_service.h"
27 #include "event_handler.h"
28 #include "event_runner.h"
29 #include "pointer_event.h"
30 #include "singleton.h"
31 
32 namespace OHOS {
33 namespace Accessibility {
34 const int64_t GESTURE_STARTED_TIME_THRESHOLD = 300000; // microsecond
35 const int64_t GESTURE_NOT_STARTED_TIME_THRESHOLD = 200000; // microsecond
36 const float DOUBLE_TAP_SLOP = 100.0f;
37 const int64_t MIN_DOUBLE_TAP_TIME = 40000; // microsecond
38 const int64_t DOUBLE_TAP_TIMEOUT = 300000; // microsecond
39 const int64_t LONG_PRESS_TIMEOUT = 300000; // microsecond
40 const int64_t TAP_INTERVAL_TIMEOUT = 100000; // microsecond
41 const float DEGREES_THRESHOLD = 0.0f;
42 const int32_t DIRECTION_NUM = 4;
43 const int64_t US_TO_MS = 1000;
44 const int32_t MM_PER_CM = 10;
45 #define CALCULATION_DIMENSION(xdpi) ((xdpi) * 0.25f)
46 #define MIN_PIXELS(xyDpi) ((xyDpi) * 0.1f)
47 
48 struct Pointer {
49     float px_;
50     float py_;
51 };
52 
53 class AccessibilityGestureRecognizer;
54 class GestureHandler : public AppExecFwk::EventHandler {
55 public:
56     GestureHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner, AccessibilityGestureRecognizer &server);
57     virtual ~GestureHandler() = default;
58     /**
59      * @brief Process the event of install system bundles.
60      * @param event Indicates the event to be processed.
61      */
62     virtual void ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event) override;
63 private:
64     AccessibilityGestureRecognizer &server_;
65 };
66 
67 class AccessibilityGestureRecognizeListener {
68 public:
69     /**
70      * @brief A destructor used to delete the listener instance.
71      */
72     virtual ~AccessibilityGestureRecognizeListener() = default;
73 
74     /**
75      * @brief The callback function when lifted the finger on the second tap of a double tap.
76      *
77      * @param event  the touch event received.
78      * @return true if the event is consumed, else false
79      */
80     virtual bool OnDoubleTap(MMI::PointerEvent &event);
81 
82     /**
83      * @brief The callback function when recognized an event stream as a gesture.
84      * @return true if the event is consumed, else false
85      */
86     virtual bool OnStarted();
87 
88     /**
89      * @brief The callback function when recognized an event stream as a multi finger gesture.
90      * @param isTwoFingerGesture whether the gesture is triggered by two finger.
91      */
92     virtual void MultiFingerGestureOnStarted(bool isTwoFingerGesture);
93 
94     /**
95      * @brief The callback function when decided the event stream is a gesture.
96      * @param gestureId the recognized gesture ID.
97      * @return true if the event is consumed, else false
98      */
99     virtual bool OnCompleted(GestureType gestureId);
100 
101     /**
102      * @brief The callback function when decided the event stream is a multi finger gesture.
103      * @param gestureId the recognized gesture ID.
104      */
105     virtual void MultiFingerGestureOnCompleted(GestureType gestureId);
106 
107     /**
108      * @brief The callback function when decided an event stream doesn't match any known gesture.
109      * @param event the touch event received.
110      * @return true if the event is consumed, else false
111      */
112     virtual bool OnCancelled(MMI::PointerEvent &event);
113 
114     /**
115      * @brief The callback function when decided an event stream doesn't match any known multi finger gesture.
116      * @param isNoDelayFlag whether the gesture recognize process is immediately canceled.
117      */
118     virtual void MultiFingerGestureOnCancelled(const bool isNoDelayFlag);
119 };
120 
121 class AccessibilityGestureRecognizer : public AppExecFwk::EventHandler {
122 public:
123     static constexpr uint32_t LONG_PRESS_MSG = 1;
124     static constexpr uint32_t SINGLE_TAP_MSG = 2;
125 
126     /**
127      * @brief A constructor used to create a accessibilityGestureRecognizer instance.
128      */
129     AccessibilityGestureRecognizer();
130 
131     /**
132      * @brief A destructor used to delete the accessibilityGestureRecognizer instance.
133      */
~AccessibilityGestureRecognizer()134     ~AccessibilityGestureRecognizer() {}
135 
136     /**
137      * @brief Register GestureRecognizeListener.
138      * @param listener the listener from touchguide
139      */
140     void RegisterListener(AccessibilityGestureRecognizeListener& listener);
141 
142     /**
143      * @brief Register GestureRecognizeListener.
144      * @param listener the listener from touchguide
145      */
146     void UnregisterListener();
147 
148     /**
149      * @brief Determine whether a single tap has occurred.
150      * @return true if a single tap has occurred, else false.
151      */
IsfirstTap()152     bool IsfirstTap()
153     {
154         return isFirstTapUp_;
155     }
156 
157     /**
158      * @brief Determine whether a double tap has occurred.
159      * @return true if a double tap has occurred, else false.
160      */
GetIsDoubleTap()161     bool GetIsDoubleTap()
162     {
163         return isDoubleTap_;
164     }
165 
166     /**
167      * @brief Determine whether a longpress has occurred.
168      * @return true if longpress has occurred, else false.
169      */
GetIsLongpress()170     bool GetIsLongpress()
171     {
172         return isLongpress_;
173     }
174 
175     /**
176      * @brief Handle a touch event. If an action is completed, the appropriate callback is called.
177      *
178      * @param event  the touch event to be handled.
179      * @param rawEvent The raw touch event.
180      * @return true if the gesture be recognized, else false
181      */
182     bool OnPointerEvent(MMI::PointerEvent &event);
183 
184     /**
185      * @brief Clear state.
186      */
187     void Clear();
188 
189     /**
190      * @brief Judge whether the double click and long press gesture is recognized.
191      * @param event the touch event from touchguide
192      */
193     void MaybeRecognizeLongPress(MMI::PointerEvent &event);
194 
195     /**
196      * @brief If a single tap completed.
197      */
198     void SingleTapDetected();
199 
200     /**
201      * @brief Set isLongpress_ flag;
202      * @param value set isLongpress_ flag
203      */
SetIsLongpress(bool value)204     void SetIsLongpress (bool value)
205     {
206         isLongpress_ = value;
207     }
208 
209     /**
210      * @brief Get pCurDown_ ptr.
211      */
GetCurDown()212     std::shared_ptr<MMI::PointerEvent> GetCurDown()
213     {
214         return pCurDown_;
215     }
216 
217     /**
218      * @brief Get continueDown_ flag.
219      */
GetContinueDown()220     bool GetContinueDown()
221     {
222         return continueDown_;
223     }
224 
225 private:
226     /**
227      * @brief Recognize the standard gesture.
228      * @param event the touch event from touchguide
229      * @return true if the standard gesture be recognized, else false
230      */
231     bool StandardGestureRecognizer(MMI::PointerEvent &event);
232 
233     /**
234      * @brief A double tap has occurred, call OnDoubleTap callback.
235      * @param event the touch event from touchguide
236      * @return true if the DoubleTap be recognized, else false
237      */
238     bool DoubleTapRecognized(MMI::PointerEvent &event);
239 
240     /**
241      * @brief Recognize gestures based on the sequence of motions.
242      * @param event the touch event from touchguide
243      * @return true if the Direction be recognized, else false
244      */
245     bool recognizeDirectionGesture(MMI::PointerEvent &event);
246 
247     /**
248      * @brief Handle the down event from touchguide.
249      * @param event the touch event from touchguide
250      */
251     void HandleTouchDownEvent(MMI::PointerEvent &event);
252 
253     /**
254      * @brief Handle the move event from touchguide.
255      * @param event the touch event from touchguide
256      */
257     bool HandleTouchMoveEvent(MMI::PointerEvent &event);
258 
259     /**
260      * @brief Handle the up event from touchguide.
261      * @param event the touch event from touchguide
262      */
263     bool HandleTouchUpEvent(MMI::PointerEvent &event);
264 
265     /**
266      * @brief Check if it's double tap.
267      * @param event the touch event from touchguide
268      * @return true if it's double tap, else false
269      */
270     bool isDoubleTap(MMI::PointerEvent &event);
271 
272     /**
273      * @brief Cancel the gesture.
274      */
275     void StandardGestureCanceled();
276 
277     /**
278      * @brief Add position to pointer route.
279      * @param pointerIterm the touch item from touchguide
280      */
281     void AddSwipePosition(MMI::PointerEvent::PointerItem &pointerIterm);
282 
283     /**
284      * @brief Calculate the move threshold for the double tap gesture.
285      * @param densityDpi the physical density
286      */
287     float GetDoubleTapMoveThreshold(float densityDpi);
288 
289     /**
290      * @brief Get pointer path.
291      * @param route all pointer route
292      * @return the vector of PointerPath
293      */
294     std::vector<Pointer> GetPointerPath(std::vector<Pointer> &route);
295 
296     /**
297      * @brief Get swipe direction.
298      * @param firstP the start point
299      * @param secondP the endpoint
300      * @return the type of swipe direction
301      */
302     int32_t GetSwipeDirection(Pointer firstP, Pointer secondP);
303 
304     static constexpr int32_t SWIPE_UP = 0;
305     static constexpr int32_t SWIPE_DOWN = 1;
306     static constexpr int32_t SWIPE_LEFT = 2;
307     static constexpr int32_t SWIPE_RIGHT = 3;
308 
309     static constexpr GestureType GESTURE_DIRECTION[DIRECTION_NUM] = {
310         GestureType::GESTURE_SWIPE_UP,
311         GestureType::GESTURE_SWIPE_DOWN,
312         GestureType::GESTURE_SWIPE_LEFT,
313         GestureType::GESTURE_SWIPE_RIGHT
314     };
315 
316     static constexpr GestureType GESTURE_DIRECTION_TO_ID[DIRECTION_NUM][DIRECTION_NUM] = {
317         {
318             GestureType::GESTURE_SWIPE_UP,
319             GestureType::GESTURE_SWIPE_UP_THEN_DOWN,
320             GestureType::GESTURE_SWIPE_UP_THEN_LEFT,
321             GestureType::GESTURE_SWIPE_UP_THEN_RIGHT,
322         },
323         {
324             GestureType::GESTURE_SWIPE_DOWN_THEN_UP,
325             GestureType::GESTURE_SWIPE_DOWN,
326             GestureType::GESTURE_SWIPE_DOWN_THEN_LEFT,
327             GestureType::GESTURE_SWIPE_DOWN_THEN_RIGHT,
328 
329         },
330         {
331             GestureType::GESTURE_SWIPE_LEFT_THEN_UP,
332             GestureType::GESTURE_SWIPE_LEFT_THEN_DOWN,
333             GestureType::GESTURE_SWIPE_LEFT,
334             GestureType::GESTURE_SWIPE_LEFT_THEN_RIGHT,
335 
336         },
337         {
338             GestureType::GESTURE_SWIPE_RIGHT_THEN_UP,
339             GestureType::GESTURE_SWIPE_RIGHT_THEN_DOWN,
340             GestureType::GESTURE_SWIPE_RIGHT_THEN_LEFT,
341             GestureType::GESTURE_SWIPE_RIGHT
342         }
343     };
344 
345     bool continueDown_ = false;
346     bool isLongpress_ = false;
347     bool isDoubleTapdetecting_ = false;
348     bool isTapDown_ = false;
349     bool isFirstTapUp_ = false;
350     bool isDoubleTap_ = false;
351     bool isRecognizingGesture_ = false;
352     bool isGestureStarted_ = false;
353     int64_t startTime_ = 0; // microsecond
354     float xMinPixels_ = 0;
355     float yMinPixels_ = 0;
356     float threshold_ = 0;
357     int32_t doubleTapScaledSlop_ = 0;
358     MMI::PointerEvent::PointerItem prePointer_ = {};
359     MMI::PointerEvent::PointerItem startPointer_ = {};
360     std::vector<Pointer> pointerRoute_ {};
361     AccessibilityGestureRecognizeListener *listener_ = nullptr;
362     std::unique_ptr<MMI::PointerEvent> pPreUp_ = nullptr;
363     std::shared_ptr<MMI::PointerEvent> pCurDown_ = nullptr;
364     std::shared_ptr<GestureHandler> handler_ = nullptr;
365     std::shared_ptr<AppExecFwk::EventRunner> runner_ = nullptr;
366 };
367 } // namespace Accessibility
368 } // namespace OHOS
369 #endif // ACCESSIBILITY_GESTURE_RECOGNIZER_H