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 isMultiTap(MotionEvent firstUp, MotionEvent secondUp, 16 int multiTapTimeSlop, int multiTapDistanceSlop) { 17 if (firstUp == null || secondUp == null) return false; 18 return eventsWithinTimeAndDistanceSlop(firstUp, secondUp, multiTapTimeSlop, 19 multiTapDistanceSlop); 20 } 21 22 private static boolean eventsWithinTimeAndDistanceSlop(MotionEvent first, MotionEvent second, 23 int timeout, int distance) { 24 if (isTimedOut(first, second, timeout)) { 25 return false; 26 } 27 final double deltaMove = distance(first, second); 28 if (deltaMove >= distance) { 29 return false; 30 } 31 return true; 32 } 33 34 public static double distance(MotionEvent first, MotionEvent second) { 35 return MathUtils.dist(first.getX(), first.getY(), second.getX(), second.getY()); 36 } 37 38 public static boolean isTimedOut(MotionEvent firstUp, MotionEvent secondUp, int timeout) { 39 final long deltaTime = secondUp.getEventTime() - firstUp.getEventTime(); 40 return (deltaTime >= timeout); 41 } 42 43 /** 44 * Determines whether a two pointer gesture is a dragging one. 45 * 46 * @return True if the gesture is a dragging one. 47 */ 48 public static boolean isDraggingGesture(float firstPtrDownX, float firstPtrDownY, 49 float secondPtrDownX, float secondPtrDownY, float firstPtrX, float firstPtrY, 50 float secondPtrX, float secondPtrY, float maxDraggingAngleCos) { 51 52 // Check if the pointers are moving in the same direction. 53 final float firstDeltaX = firstPtrX - firstPtrDownX; 54 final float firstDeltaY = firstPtrY - firstPtrDownY; 55 56 if (firstDeltaX == 0 && firstDeltaY == 0) { 57 return true; 58 } 59 60 final float firstMagnitude = (float) Math.hypot(firstDeltaX, firstDeltaY); 61 final float firstXNormalized = 62 (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX; 63 final float firstYNormalized = 64 (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY; 65 66 final float secondDeltaX = secondPtrX - secondPtrDownX; 67 final float secondDeltaY = secondPtrY - secondPtrDownY; 68 69 if (secondDeltaX == 0 && secondDeltaY == 0) { 70 return true; 71 } 72 73 final float secondMagnitude = (float) Math.hypot(secondDeltaX, secondDeltaY); 74 final float secondXNormalized = 75 (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX; 76 final float secondYNormalized = 77 (secondMagnitude > 0) ? secondDeltaY / secondMagnitude : secondDeltaY; 78 79 final float angleCos = 80 firstXNormalized * secondXNormalized + firstYNormalized * secondYNormalized; 81 82 if (angleCos < maxDraggingAngleCos) { 83 return false; 84 } 85 86 return true; 87 } 88} 89