1 package com.android.server.accessibility; 2 3 import android.util.MathUtils; 4 import android.view.MotionEvent; 5 6 /** 7 * Some helper functions for gesture detection. 8 */ 9 final 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