package com.WazaBe.HoloEverywhere.widget; import android.view.MotionEvent; import com.WazaBe.HoloEverywhere.util.Pool; import com.WazaBe.HoloEverywhere.util.Poolable; import com.WazaBe.HoloEverywhere.util.PoolableManager; import com.WazaBe.HoloEverywhere.util.Pools; public final class VelocityTracker implements Poolable<VelocityTracker> { public static final class Estimator { private static final int MAX_DEGREE = 4; public float confidence; public int degree; public final float[] xCoeff = new float[MAX_DEGREE + 1]; public final float[] yCoeff = new float[MAX_DEGREE + 1]; private float estimate(float time, float[] c) { float a = 0; float scale = 1; for (int i = 0; i <= degree; i++) { a += c[i] * scale; scale *= time; } return a; } public float estimateX(float time) { return estimate(time, xCoeff); } public float estimateY(float time) { return estimate(time, yCoeff); } public float getXCoeff(int index) { return index <= degree ? xCoeff[index] : 0; } public float getYCoeff(int index) { return index <= degree ? yCoeff[index] : 0; } } private static final int ACTIVE_POINTER_ID = -1; private static final Pool<VelocityTracker> sPool = Pools .synchronizedPool(Pools.finitePool( new PoolableManager<VelocityTracker>() { @Override public VelocityTracker newInstance() { return new VelocityTracker(null); } @Override public void onAcquired(VelocityTracker element) { } @Override public void onReleased(VelocityTracker element) { element.clear(); } }, 2)); private static native void nativeAddMovement(int ptr, MotionEvent event); private static native void nativeClear(int ptr); private static native void nativeComputeCurrentVelocity(int ptr, int units, float maxVelocity); private static native void nativeDispose(int ptr); private static native boolean nativeGetEstimator(int ptr, int id, Estimator outEstimator); private static native float nativeGetXVelocity(int ptr, int id); private static native float nativeGetYVelocity(int ptr, int id); private static native int nativeInitialize(String strategy); static public VelocityTracker obtain() { return sPool.acquire(); } public static VelocityTracker obtain(String strategy) { if (strategy == null) { return obtain(); } return new VelocityTracker(strategy); } private boolean mIsPooled; private VelocityTracker mNext; private int mPtr; private final String mStrategy; private VelocityTracker(String strategy) { mPtr = nativeInitialize(strategy); mStrategy = strategy; } public void addMovement(MotionEvent event) { if (event == null) { throw new IllegalArgumentException("event must not be null"); } nativeAddMovement(mPtr, event); } public void clear() { nativeClear(mPtr); } public void computeCurrentVelocity(int units) { nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE); } public void computeCurrentVelocity(int units, float maxVelocity) { nativeComputeCurrentVelocity(mPtr, units, maxVelocity); } @Override protected void finalize() throws Throwable { try { if (mPtr != 0) { nativeDispose(mPtr); mPtr = 0; } } finally { super.finalize(); } } public boolean getEstimator(int id, Estimator outEstimator) { if (outEstimator == null) { throw new IllegalArgumentException("outEstimator must not be null"); } return nativeGetEstimator(mPtr, id, outEstimator); } @Override public VelocityTracker getNextPoolable() { return mNext; } public float getXVelocity() { return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID); } public float getXVelocity(int id) { return nativeGetXVelocity(mPtr, id); } public float getYVelocity() { return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID); } public float getYVelocity(int id) { return nativeGetYVelocity(mPtr, id); } @Override public boolean isPooled() { return mIsPooled; } public void recycle() { if (mStrategy == null) { sPool.release(this); } } @Override public void setNextPoolable(VelocityTracker element) { mNext = element; } @Override public void setPooled(boolean isPooled) { mIsPooled = isPooled; } }