Skip to content

Commit

Permalink
Make velocity tracker strategy configurable.
Browse files Browse the repository at this point in the history
This change is very useful for testing purposes because it makes it
easy to compare different implementations to see how they behave.

There is no change to the current default strategy.

Bug: 6413587
Change-Id: I4d8567aa4160571ba9fa397ce419882cd9366749
  • Loading branch information
Jeff Brown committed Jun 4, 2012
1 parent 6e8e41a commit 9eb7d86
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 36 deletions.
33 changes: 27 additions & 6 deletions core/java/android/view/VelocityTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public final class VelocityTracker implements Poolable<VelocityTracker> {
private static final Pool<VelocityTracker> sPool = Pools.synchronizedPool(
Pools.finitePool(new PoolableManager<VelocityTracker>() {
public VelocityTracker newInstance() {
return new VelocityTracker();
return new VelocityTracker(null);
}

public void onAcquired(VelocityTracker element) {
Expand All @@ -50,10 +50,12 @@ public void onReleased(VelocityTracker element) {
private static final int ACTIVE_POINTER_ID = -1;

private int mPtr;
private final String mStrategy;

private VelocityTracker mNext;
private boolean mIsPooled;

private static native int nativeInitialize();
private static native int nativeInitialize(String strategy);
private static native void nativeDispose(int ptr);
private static native void nativeClear(int ptr);
private static native void nativeAddMovement(int ptr, MotionEvent event);
Expand All @@ -74,12 +76,30 @@ static public VelocityTracker obtain() {
return sPool.acquire();
}

/**
* Obtains a velocity tracker with the specified strategy.
* For testing and comparison purposes only.
*
* @param strategy The strategy, or null to use the default.
* @return The velocity tracker.
*
* @hide
*/
public static VelocityTracker obtain(String strategy) {
if (strategy == null) {
return obtain();
}
return new VelocityTracker(strategy);
}

/**
* Return a VelocityTracker object back to be re-used by others. You must
* not touch the object after calling this function.
*/
public void recycle() {
sPool.release(this);
if (mStrategy == null) {
sPool.release(this);
}
}

/**
Expand Down Expand Up @@ -110,8 +130,9 @@ public void setPooled(boolean isPooled) {
mIsPooled = isPooled;
}

private VelocityTracker() {
mPtr = nativeInitialize();
private VelocityTracker(String strategy) {
mPtr = nativeInitialize(strategy);
mStrategy = strategy;
}

@Override
Expand Down Expand Up @@ -253,7 +274,7 @@ public boolean getEstimator(int id, Estimator outEstimator) {
*/
public static final class Estimator {
// Must match VelocityTracker::Estimator::MAX_DEGREE
private static final int MAX_DEGREE = 2;
private static final int MAX_DEGREE = 4;

/**
* Polynomial coefficients describing motion in X.
Expand Down
52 changes: 50 additions & 2 deletions core/java/com/android/internal/widget/PointerLocationView.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import android.graphics.Paint.FontMetricsInt;
import android.hardware.input.InputManager;
import android.hardware.input.InputManager.InputDeviceListener;
import android.os.SystemProperties;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;
Expand All @@ -36,7 +37,11 @@

public class PointerLocationView extends View implements InputDeviceListener {
private static final String TAG = "Pointer";


// The system property key used to specify an alternate velocity tracker strategy
// to plot alongside the default one. Useful for testing and comparison purposes.
private static final String ALT_STRATEGY_PROPERY_KEY = "debug.velocitytracker.alt";

public static class PointerState {
// Trace of previous points.
private float[] mTraceX = new float[32];
Expand All @@ -53,9 +58,12 @@ public static class PointerState {
// Most recent velocity.
private float mXVelocity;
private float mYVelocity;
private float mAltXVelocity;
private float mAltYVelocity;

// Position estimator.
private VelocityTracker.Estimator mEstimator = new VelocityTracker.Estimator();
private VelocityTracker.Estimator mAltEstimator = new VelocityTracker.Estimator();

public void clearTrace() {
mTraceCount = 0;
Expand Down Expand Up @@ -103,7 +111,8 @@ public void addTrace(float x, float y) {
private final PointerCoords mTempCoords = new PointerCoords();

private final VelocityTracker mVelocity;

private final VelocityTracker mAltVelocity;

private final FasterStringBuilder mText = new FasterStringBuilder();

private boolean mPrintCoords = true;
Expand Down Expand Up @@ -145,6 +154,14 @@ public PointerLocationView(Context c) {
mActivePointerId = 0;

mVelocity = VelocityTracker.obtain();

String altStrategy = SystemProperties.get(ALT_STRATEGY_PROPERY_KEY);
if (altStrategy.length() != 0) {
Log.d(TAG, "Comparing default velocity tracker strategy with " + altStrategy);
mAltVelocity = VelocityTracker.obtain(altStrategy);
} else {
mAltVelocity = null;
}
}

public void setPrintCoords(boolean state) {
Expand Down Expand Up @@ -296,6 +313,25 @@ protected void onDraw(Canvas canvas) {
float xVel = ps.mXVelocity * (1000 / 60);
float yVel = ps.mYVelocity * (1000 / 60);
canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint);

// Draw alternate estimate.
if (mAltVelocity != null) {
mPaint.setARGB(128, 0, 128, 128);
lx = ps.mAltEstimator.estimateX(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL);
ly = ps.mAltEstimator.estimateY(-ESTIMATE_PAST_POINTS * ESTIMATE_INTERVAL);
for (int i = -ESTIMATE_PAST_POINTS + 1; i <= ESTIMATE_FUTURE_POINTS; i++) {
float x = ps.mAltEstimator.estimateX(i * ESTIMATE_INTERVAL);
float y = ps.mAltEstimator.estimateY(i * ESTIMATE_INTERVAL);
canvas.drawLine(lx, ly, x, y, mPaint);
lx = x;
ly = y;
}

mPaint.setARGB(255, 64, 255, 128);
xVel = ps.mAltXVelocity * (1000 / 60);
yVel = ps.mAltYVelocity * (1000 / 60);
canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint);
}
}

if (mCurDown && ps.mCurDown) {
Expand Down Expand Up @@ -470,6 +506,9 @@ public void addPointerEvent(MotionEvent event) {
mCurNumPointers = 0;
mMaxNumPointers = 0;
mVelocity.clear();
if (mAltVelocity != null) {
mAltVelocity.clear();
}
}

mCurNumPointers += 1;
Expand Down Expand Up @@ -497,6 +536,10 @@ public void addPointerEvent(MotionEvent event) {

mVelocity.addMovement(event);
mVelocity.computeCurrentVelocity(1);
if (mAltVelocity != null) {
mAltVelocity.addMovement(event);
mAltVelocity.computeCurrentVelocity(1);
}

final int N = event.getHistorySize();
for (int historyPos = 0; historyPos < N; historyPos++) {
Expand Down Expand Up @@ -528,6 +571,11 @@ public void addPointerEvent(MotionEvent event) {
ps.mXVelocity = mVelocity.getXVelocity(id);
ps.mYVelocity = mVelocity.getYVelocity(id);
mVelocity.getEstimator(id, ps.mEstimator);
if (mAltVelocity != null) {
ps.mAltXVelocity = mAltVelocity.getXVelocity(id);
ps.mAltYVelocity = mAltVelocity.getYVelocity(id);
mAltVelocity.getEstimator(id, ps.mAltEstimator);
}
ps.mToolType = event.getToolType(i);
}
}
Expand Down
18 changes: 13 additions & 5 deletions core/jni/android_view_VelocityTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <androidfw/VelocityTracker.h>
#include "android_view_MotionEvent.h"

#include <ScopedUtfChars.h>


namespace android {

Expand All @@ -42,7 +44,7 @@ static struct {

class VelocityTrackerState {
public:
VelocityTrackerState();
VelocityTrackerState(const char* strategy);

void clear();
void addMovement(const MotionEvent* event);
Expand All @@ -61,7 +63,8 @@ class VelocityTrackerState {
Velocity mCalculatedVelocity[MAX_POINTERS];
};

VelocityTrackerState::VelocityTrackerState() : mActivePointerId(-1) {
VelocityTrackerState::VelocityTrackerState(const char* strategy) :
mVelocityTracker(strategy), mActivePointerId(-1) {
}

void VelocityTrackerState::clear() {
Expand Down Expand Up @@ -135,8 +138,13 @@ bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator*

// --- JNI Methods ---

static jint android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz) {
return reinterpret_cast<jint>(new VelocityTrackerState());
static jint android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz,
jstring strategyStr) {
if (strategyStr) {
ScopedUtfChars strategy(env, strategyStr);
return reinterpret_cast<jint>(new VelocityTrackerState(strategy.c_str()));
}
return reinterpret_cast<jint>(new VelocityTrackerState(NULL));
}

static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jint ptr) {
Expand Down Expand Up @@ -209,7 +217,7 @@ static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jcl
static JNINativeMethod gVelocityTrackerMethods[] = {
/* name, signature, funcPtr */
{ "nativeInitialize",
"()I",
"(Ljava/lang/String;)I",
(void*)android_view_VelocityTracker_nativeInitialize },
{ "nativeDispose",
"(I)V",
Expand Down
20 changes: 14 additions & 6 deletions include/androidfw/VelocityTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class VelocityTracker {
};

struct Estimator {
static const size_t MAX_DEGREE = 2;
static const size_t MAX_DEGREE = 4;

// Estimator time base.
nsecs_t time;
Expand All @@ -61,7 +61,10 @@ class VelocityTracker {
}
};

VelocityTracker();
// Creates a velocity tracker using the specified strategy.
// If strategy is NULL, uses the default strategy for the platform.
VelocityTracker(const char* strategy = NULL);

~VelocityTracker();

// Resets the velocity tracker state.
Expand Down Expand Up @@ -99,10 +102,16 @@ class VelocityTracker {
inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }

private:
static const char* DEFAULT_STRATEGY;

nsecs_t mLastEventTime;
BitSet32 mCurrentPointerIdBits;
int32_t mActivePointerId;
VelocityTrackerStrategy* mStrategy;

bool configureStrategy(const char* strategy);

static VelocityTrackerStrategy* createStrategy(const char* strategy);
};


Expand All @@ -129,7 +138,8 @@ class VelocityTrackerStrategy {
*/
class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
public:
LeastSquaresVelocityTrackerStrategy();
// Degree must be no greater than Estimator::MAX_DEGREE.
LeastSquaresVelocityTrackerStrategy(uint32_t degree);
virtual ~LeastSquaresVelocityTrackerStrategy();

virtual void clear();
Expand All @@ -139,9 +149,6 @@ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;

private:
// Polynomial degree. Must be less than or equal to Estimator::MAX_DEGREE.
static const uint32_t DEGREE = 2;

// Sample horizon.
// We don't use too much history by default since we want to react to quick
// changes in direction.
Expand All @@ -160,6 +167,7 @@ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
}
};

const uint32_t mDegree;
uint32_t mIndex;
Movement mMovements[HISTORY_SIZE];
};
Expand Down
Loading

0 comments on commit 9eb7d86

Please sign in to comment.