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; } }