1package com.android.server.accessibility;
2
3import android.util.MathUtils;
4import android.view.MotionEvent;
5
6/**
7 * Some helper functions for gesture detection.
8 */
9final class GestureUtils {
10
11    private GestureUtils() {
12        /* cannot be instantiated */
13    }
14
15    public static boolean isTap(MotionEvent down, MotionEvent up, int tapTimeSlop,
16            int tapDistanceSlop, int actionIndex) {
17        return eventsWithinTimeAndDistanceSlop(down, up, tapTimeSlop, tapDistanceSlop, actionIndex);
18    }
19
20    public static boolean isMultiTap(MotionEvent firstUp, MotionEvent secondUp,
21            int multiTapTimeSlop, int multiTapDistanceSlop, int actionIndex) {
22        return eventsWithinTimeAndDistanceSlop(firstUp, secondUp, multiTapTimeSlop,
23                multiTapDistanceSlop, actionIndex);
24    }
25
26    private static boolean eventsWithinTimeAndDistanceSlop(MotionEvent first, MotionEvent second,
27            int timeout, int distance, int actionIndex) {
28        if (isTimedOut(first, second, timeout)) {
29            return false;
30        }
31        final double deltaMove = computeDistance(first, second, actionIndex);
32        if (deltaMove >= distance) {
33            return false;
34        }
35        return true;
36    }
37
38    public static double computeDistance(MotionEvent first, MotionEvent second, int pointerIndex) {
39         return MathUtils.dist(first.getX(pointerIndex), first.getY(pointerIndex),
40                 second.getX(pointerIndex), second.getY(pointerIndex));
41    }
42
43    public static boolean isTimedOut(MotionEvent firstUp, MotionEvent secondUp, int timeout) {
44        final long deltaTime = secondUp.getEventTime() - firstUp.getEventTime();
45        return (deltaTime >= timeout);
46    }
47
48    public static boolean isSamePointerContext(MotionEvent first, MotionEvent second) {
49        return (first.getPointerIdBits() == second.getPointerIdBits()
50                && first.getPointerId(first.getActionIndex())
51                        == second.getPointerId(second.getActionIndex()));
52    }
53
54    /**
55     * Determines whether a two pointer gesture is a dragging one.
56     *
57     * @param event The event with the pointer data.
58     * @return True if the gesture is a dragging one.
59     */
60    public static boolean isDraggingGesture(float firstPtrDownX, float firstPtrDownY,
61            float secondPtrDownX, float secondPtrDownY, float firstPtrX, float firstPtrY,
62            float secondPtrX, float secondPtrY, float maxDraggingAngleCos) {
63
64        // Check if the pointers are moving in the same direction.
65        final float firstDeltaX = firstPtrX - firstPtrDownX;
66        final float firstDeltaY = firstPtrY - firstPtrDownY;
67
68        if (firstDeltaX == 0 && firstDeltaY == 0) {
69            return true;
70        }
71
72        final float firstMagnitude =
73            (float) Math.sqrt(firstDeltaX * firstDeltaX + firstDeltaY * firstDeltaY);
74        final float firstXNormalized =
75            (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX;
76        final float firstYNormalized =
77            (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY;
78
79        final float secondDeltaX = secondPtrX - secondPtrDownX;
80        final float secondDeltaY = secondPtrY - secondPtrDownY;
81
82        if (secondDeltaX == 0 && secondDeltaY == 0) {
83            return true;
84        }
85
86        final float secondMagnitude =
87            (float) Math.sqrt(secondDeltaX * secondDeltaX + secondDeltaY * secondDeltaY);
88        final float secondXNormalized =
89            (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX;
90        final float secondYNormalized =
91            (secondMagnitude > 0) ? secondDeltaY / secondMagnitude : secondDeltaY;
92
93        final float angleCos =
94            firstXNormalized * secondXNormalized + firstYNormalized * secondYNormalized;
95
96        if (angleCos < maxDraggingAngleCos) {
97            return false;
98        }
99
100        return true;
101    }
102}
103