private static final void releasePointerList(Pointer pointer) {
    if (pointer != null) {
      synchronized (sPool) {
        int count = sRecycledPointerCount;
        if (count >= POINTER_POOL_CAPACITY) {
          return;
        }

        Pointer tail = pointer;
        for (; ; ) {
          count += 1;
          if (count >= POINTER_POOL_CAPACITY) {
            break;
          }

          Pointer next = tail.next;
          if (next == null) {
            break;
          }
          tail = next;
        }

        tail.next = sRecycledPointerListHead;
        sRecycledPointerCount = count;
        sRecycledPointerListHead = pointer;
      }
    }
  }
 private static final void releasePointer(Pointer pointer) {
   synchronized (sPool) {
     if (sRecycledPointerCount < POINTER_POOL_CAPACITY) {
       pointer.next = sRecycledPointerListHead;
       sRecycledPointerCount += 1;
       sRecycledPointerListHead = pointer;
     }
   }
 }
 private static final Pointer obtainPointer() {
   synchronized (sPool) {
     if (sRecycledPointerCount != 0) {
       Pointer element = sRecycledPointerListHead;
       sRecycledPointerCount -= 1;
       sRecycledPointerListHead = element.next;
       element.next = null;
       return element;
     }
   }
   return new Pointer();
 }
  /**
   * Add a user's movement to the tracker. You should call this for the initial {@link
   * MotionEvent#ACTION_DOWN}, the following {@link MotionEvent#ACTION_MOVE} events that you
   * receive, and the final {@link MotionEvent#ACTION_UP}. You can, however, call this for whichever
   * events you desire.
   *
   * @param ev The MotionEvent you received and would like to track.
   */
  public void addMovement(MotionEvent ev) {
    final int historySize = ev.getHistorySize();
    final int pointerCount = ev.getPointerCount();
    final int lastTouchIndex = mLastTouchIndex;
    final int nextTouchIndex = (lastTouchIndex + 1) % NUM_PAST;
    final int finalTouchIndex = (nextTouchIndex + historySize) % NUM_PAST;
    final int generation = mGeneration++;

    mLastTouchIndex = finalTouchIndex;

    // Update pointer data.
    Pointer previousPointer = null;
    for (int i = 0; i < pointerCount; i++) {
      final int pointerId = ev.getPointerId(i);

      // Find the pointer data for this pointer id.
      // This loop is optimized for the common case where pointer ids in the event
      // are in sorted order.  However, we check for this case explicitly and
      // perform a full linear scan from the start if needed.
      Pointer nextPointer;
      if (previousPointer == null || pointerId < previousPointer.id) {
        previousPointer = null;
        nextPointer = mPointerListHead;
      } else {
        nextPointer = previousPointer.next;
      }

      final Pointer pointer;
      for (; ; ) {
        if (nextPointer != null) {
          final int nextPointerId = nextPointer.id;
          if (nextPointerId == pointerId) {
            pointer = nextPointer;
            break;
          }
          if (nextPointerId < pointerId) {
            nextPointer = nextPointer.next;
            continue;
          }
        }

        // Pointer went down.  Add it to the list.
        // Write a sentinel at the end of the pastTime trace so we will be able to
        // tell when the trace started.
        pointer = obtainPointer();
        pointer.id = pointerId;
        pointer.pastTime[lastTouchIndex] = Long.MIN_VALUE;
        pointer.next = nextPointer;
        if (previousPointer == null) {
          mPointerListHead = pointer;
        } else {
          previousPointer.next = pointer;
        }
        break;
      }

      pointer.generation = generation;
      previousPointer = pointer;

      final float[] pastX = pointer.pastX;
      final float[] pastY = pointer.pastY;
      final long[] pastTime = pointer.pastTime;

      for (int j = 0; j < historySize; j++) {
        final int touchIndex = (nextTouchIndex + j) % NUM_PAST;
        pastX[touchIndex] = ev.getHistoricalX(i, j);
        pastY[touchIndex] = ev.getHistoricalY(i, j);
        pastTime[touchIndex] = ev.getHistoricalEventTime(j);
      }
      pastX[finalTouchIndex] = ev.getX(i);
      pastY[finalTouchIndex] = ev.getY(i);
      pastTime[finalTouchIndex] = ev.getEventTime();
    }

    // Find removed pointers.
    previousPointer = null;
    for (Pointer pointer = mPointerListHead; pointer != null; ) {
      final Pointer nextPointer = pointer.next;
      if (pointer.generation != generation) {
        // Pointer went up.  Remove it from the list.
        if (previousPointer == null) {
          mPointerListHead = nextPointer;
        } else {
          previousPointer.next = nextPointer;
        }
        releasePointer(pointer);
      } else {
        previousPointer = pointer;
      }
      pointer = nextPointer;
    }
  }