content: package com.android.server.accessibility;
  
  import android.util.MathUtils;
  import android.view.MotionEvent;
  
  /**
   * Some helper functions for gesture detection.
   */
  final class GestureUtils {
  
      private GestureUtils() {
          /* cannot be instantiated */
      }
  
      public static boolean isMultiTap(MotionEvent firstUp, MotionEvent secondUp,
              int multiTapTimeSlop, int multiTapDistanceSlop) {
          if (firstUp == null || secondUp == null) return false;
          return eventsWithinTimeAndDistanceSlop(firstUp, secondUp, multiTapTimeSlop,
                  multiTapDistanceSlop);
      }
  
      private static boolean eventsWithinTimeAndDistanceSlop(MotionEvent first, MotionEvent second,
              int timeout, int distance) {
          if (isTimedOut(first, second, timeout)) {
              return false;
          }
          final double deltaMove = distance(first, second);
          if (deltaMove >= distance) {
              return false;
          }
          return true;
      }
  
      public static double distance(MotionEvent first, MotionEvent second) {
          return MathUtils.dist(first.getX(), first.getY(), second.getX(), second.getY());
      }
  
      public static boolean isTimedOut(MotionEvent firstUp, MotionEvent secondUp, int timeout) {
          final long deltaTime = secondUp.getEventTime() - firstUp.getEventTime();
          return (deltaTime >= timeout);
      }
  
      /**
       * Determines whether a two pointer gesture is a dragging one.
       *
       * @return True if the gesture is a dragging one.
       */
      public static boolean isDraggingGesture(float firstPtrDownX, float firstPtrDownY,
              float secondPtrDownX, float secondPtrDownY, float firstPtrX, float firstPtrY,
              float secondPtrX, float secondPtrY, float maxDraggingAngleCos) {
  
          // Check if the pointers are moving in the same direction.
          final float firstDeltaX = firstPtrX - firstPtrDownX;
          final float firstDeltaY = firstPtrY - firstPtrDownY;
  
          if (firstDeltaX == 0 && firstDeltaY == 0) {
              return true;
          }
  
          final float firstMagnitude = (float) Math.hypot(firstDeltaX, firstDeltaY);
          final float firstXNormalized =
              (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX;
          final float firstYNormalized =
              (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY;
  
          final float secondDeltaX = secondPtrX - secondPtrDownX;
          final float secondDeltaY = secondPtrY - secondPtrDownY;
  
          if (secondDeltaX == 0 && secondDeltaY == 0) {
              return true;
          }
  
          final float secondMagnitude = (float) Math.hypot(secondDeltaX, secondDeltaY);
          final float secondXNormalized =
              (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX;
          final float secondYNormalized =
              (secondMagnitude > 0) ? secondDeltaY / secondMagnitude : secondDeltaY;
  
          final float angleCos =
              firstXNormalized * secondXNormalized + firstYNormalized * secondYNormalized;
  
          if (angleCos < maxDraggingAngleCos) {
              return false;
          }
  
          return true;
      }
  }
  