/**
   * Compute the current velocity based on the points that have been collected. Only call this when
   * you actually want to retrieve velocity information, as it is relatively expensive. You can then
   * retrieve the velocity with {@link #getXVelocity()} and {@link #getYVelocity()}.
   *
   * @param units The units you would like the velocity in. A value of 1 provides pixels per
   *     millisecond, 1000 provides pixels per second, etc.
   * @param maxVelocity The maximum velocity that can be computed by this method. This value must be
   *     declared in the same unit as the units parameter. This value must be positive.
   */
  public void computeCurrentVelocity(int units, float maxVelocity) {
    final int lastTouchIndex = mLastTouchIndex;

    for (Pointer pointer = mPointerListHead; pointer != null; pointer = pointer.next) {
      final long[] pastTime = pointer.pastTime;

      // Search backwards in time for oldest acceptable time.
      // Stop at the beginning of the trace as indicated by the sentinel time Long.MIN_VALUE.
      int oldestTouchIndex = lastTouchIndex;
      int numTouches = 1;
      final long minTime = pastTime[lastTouchIndex] - MAX_AGE_MILLISECONDS;
      while (numTouches < NUM_PAST) {
        final int nextOldestTouchIndex = (oldestTouchIndex + NUM_PAST - 1) % NUM_PAST;
        final long nextOldestTime = pastTime[nextOldestTouchIndex];
        if (nextOldestTime < minTime) { // also handles end of trace sentinel
          break;
        }
        oldestTouchIndex = nextOldestTouchIndex;
        numTouches += 1;
      }

      // If we have a lot of samples, skip the last received sample since it is
      // probably pretty noisy compared to the sum of all of the traces already acquired.
      if (numTouches > 3) {
        numTouches -= 1;
      }

      // Kind-of stupid.
      final float[] pastX = pointer.pastX;
      final float[] pastY = pointer.pastY;

      final float oldestX = pastX[oldestTouchIndex];
      final float oldestY = pastY[oldestTouchIndex];
      final long oldestTime = pastTime[oldestTouchIndex];

      float accumX = 0;
      float accumY = 0;

      for (int i = 1; i < numTouches; i++) {
        final int touchIndex = (oldestTouchIndex + i) % NUM_PAST;
        final int duration = (int) (pastTime[touchIndex] - oldestTime);

        if (duration == 0) continue;

        float delta = pastX[touchIndex] - oldestX;
        float velocity = (delta / duration) * units; // pixels/frame.
        accumX = (accumX == 0) ? velocity : (accumX + velocity) * .5f;

        delta = pastY[touchIndex] - oldestY;
        velocity = (delta / duration) * units; // pixels/frame.
        accumY = (accumY == 0) ? velocity : (accumY + velocity) * .5f;
      }

      if (accumX < -maxVelocity) {
        accumX = -maxVelocity;
      } else if (accumX > maxVelocity) {
        accumX = maxVelocity;
      }

      if (accumY < -maxVelocity) {
        accumY = -maxVelocity;
      } else if (accumY > maxVelocity) {
        accumY = maxVelocity;
      }

      pointer.xVelocity = accumX;
      pointer.yVelocity = accumY;

      if (localLOGV) {
        Log.v(
            TAG,
            "Pointer "
                + pointer.id
                + ": Y velocity="
                + accumX
                + " X velocity="
                + accumY
                + " N="
                + numTouches);
      }
    }
  }