Implement a second order integrating VT strategy.

Bug: 6413587
Change-Id: I51bc7b8cbff22b10b728fc84ee15370e9984dd55
diff --git a/include/androidfw/VelocityTracker.h b/include/androidfw/VelocityTracker.h
index 262a51b..3e6436a 100644
--- a/include/androidfw/VelocityTracker.h
+++ b/include/androidfw/VelocityTracker.h
@@ -196,7 +196,8 @@
  */
 class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy {
 public:
-    IntegratingVelocityTrackerStrategy();
+    // Degree must be 1 or 2.
+    IntegratingVelocityTrackerStrategy(uint32_t degree);
     ~IntegratingVelocityTrackerStrategy();
 
     virtual void clear();
@@ -209,18 +210,19 @@
     // Current state estimate for a particular pointer.
     struct State {
         nsecs_t updateTime;
-        bool first;
+        uint32_t degree;
 
-        float xpos, xvel;
-        float ypos, yvel;
+        float xpos, xvel, xaccel;
+        float ypos, yvel, yaccel;
     };
 
+    const uint32_t mDegree;
     BitSet32 mPointerIdBits;
     State mPointerState[MAX_POINTER_ID + 1];
 
-    static void initState(State& state, nsecs_t eventTime, float xpos, float ypos);
-    static void updateState(State& state, nsecs_t eventTime, float xpos, float ypos);
-    static void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator);
+    void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
+    void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
+    void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const;
 };
 
 } // namespace android
diff --git a/libs/androidfw/VelocityTracker.cpp b/libs/androidfw/VelocityTracker.cpp
index 17cefbe..fc75576 100644
--- a/libs/androidfw/VelocityTracker.cpp
+++ b/libs/androidfw/VelocityTracker.cpp
@@ -182,7 +182,13 @@
         // more tolerant of errors.  Like 'lsq1', this strategy tends to underestimate
         // the velocity of a fling but this strategy tends to respond to changes in
         // direction more quickly and accurately.
-        return new IntegratingVelocityTrackerStrategy();
+        return new IntegratingVelocityTrackerStrategy(1);
+    }
+    if (!strcmp("int2", strategy)) {
+        // 2nd order integrating filter.  Quality: EXPERIMENTAL.
+        // For comparison purposes only.  Unlike 'int1' this strategy can compensate
+        // for acceleration but it typically overestimates the effect.
+        return new IntegratingVelocityTrackerStrategy(2);
     }
     return NULL;
 }
@@ -680,7 +686,8 @@
 
 // --- IntegratingVelocityTrackerStrategy ---
 
-IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy() {
+IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) :
+        mDegree(degree) {
 }
 
 IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {
@@ -725,18 +732,20 @@
 }
 
 void IntegratingVelocityTrackerStrategy::initState(State& state,
-        nsecs_t eventTime, float xpos, float ypos) {
+        nsecs_t eventTime, float xpos, float ypos) const {
     state.updateTime = eventTime;
-    state.first = true;
+    state.degree = 0;
 
     state.xpos = xpos;
     state.xvel = 0;
+    state.xaccel = 0;
     state.ypos = ypos;
     state.yvel = 0;
+    state.yaccel = 0;
 }
 
 void IntegratingVelocityTrackerStrategy::updateState(State& state,
-        nsecs_t eventTime, float xpos, float ypos) {
+        nsecs_t eventTime, float xpos, float ypos) const {
     const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS;
     const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
 
@@ -749,28 +758,45 @@
 
     float xvel = (xpos - state.xpos) / dt;
     float yvel = (ypos - state.ypos) / dt;
-    if (state.first) {
+    if (state.degree == 0) {
         state.xvel = xvel;
         state.yvel = yvel;
-        state.first = false;
+        state.degree = 1;
     } else {
         float alpha = dt / (FILTER_TIME_CONSTANT + dt);
-        state.xvel += (xvel - state.xvel) * alpha;
-        state.yvel += (yvel - state.yvel) * alpha;
+        if (mDegree == 1) {
+            state.xvel += (xvel - state.xvel) * alpha;
+            state.yvel += (yvel - state.yvel) * alpha;
+        } else {
+            float xaccel = (xvel - state.xvel) / dt;
+            float yaccel = (yvel - state.yvel) / dt;
+            if (state.degree == 1) {
+                state.xaccel = xaccel;
+                state.yaccel = yaccel;
+                state.degree = 2;
+            } else {
+                state.xaccel += (xaccel - state.xaccel) * alpha;
+                state.yaccel += (yaccel - state.yaccel) * alpha;
+            }
+            state.xvel += (state.xaccel * dt) * alpha;
+            state.yvel += (state.yaccel * dt) * alpha;
+        }
     }
     state.xpos = xpos;
     state.ypos = ypos;
 }
 
 void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
-        VelocityTracker::Estimator* outEstimator) {
+        VelocityTracker::Estimator* outEstimator) const {
     outEstimator->time = state.updateTime;
-    outEstimator->degree = 1;
     outEstimator->confidence = 1.0f;
+    outEstimator->degree = state.degree;
     outEstimator->xCoeff[0] = state.xpos;
     outEstimator->xCoeff[1] = state.xvel;
+    outEstimator->xCoeff[2] = state.xaccel / 2;
     outEstimator->yCoeff[0] = state.ypos;
     outEstimator->yCoeff[1] = state.yvel;
+    outEstimator->yCoeff[2] = state.yaccel / 2;
 }
 
 } // namespace android