Merge "Detect when pointer has stopped moving." into jb-dev
diff --git a/include/androidfw/VelocityTracker.h b/include/androidfw/VelocityTracker.h
index 6964588..cbb07829 100644
--- a/include/androidfw/VelocityTracker.h
+++ b/include/androidfw/VelocityTracker.h
@@ -37,6 +37,9 @@
     struct Estimator {
         static const size_t MAX_DEGREE = 2;
 
+        // Estimator time base.
+        nsecs_t time;
+
         // Polynomial coefficients describing motion in X and Y.
         float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1];
 
@@ -48,6 +51,7 @@
         float confidence;
 
         inline void clear() {
+            time = 0;
             degree = 0;
             confidence = 0;
             for (size_t i = 0; i <= MAX_DEGREE; i++) {
@@ -58,7 +62,6 @@
     };
 
     VelocityTracker();
-    VelocityTracker(VelocityTrackerStrategy* strategy);
     ~VelocityTracker();
 
     // Resets the velocity tracker state.
@@ -96,6 +99,7 @@
     inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }
 
 private:
+    nsecs_t mLastEventTime;
     BitSet32 mCurrentPointerIdBits;
     int32_t mActivePointerId;
     VelocityTrackerStrategy* mStrategy;
diff --git a/libs/androidfw/VelocityTracker.cpp b/libs/androidfw/VelocityTracker.cpp
index a212948..5dbafd8 100644
--- a/libs/androidfw/VelocityTracker.cpp
+++ b/libs/androidfw/VelocityTracker.cpp
@@ -33,6 +33,16 @@
 
 namespace android {
 
+// Nanoseconds per milliseconds.
+static const nsecs_t NANOS_PER_MS = 1000000;
+
+// Threshold for determining that a pointer has stopped moving.
+// Some input devices do not send ACTION_MOVE events in the case where a pointer has
+// stopped.  We need to detect this case so that we can accurately predict the
+// velocity after the pointer starts moving again.
+static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS;
+
+
 static float vectorDot(const float* a, const float* b, uint32_t m) {
     float r = 0;
     while (m--) {
@@ -89,15 +99,10 @@
 // --- VelocityTracker ---
 
 VelocityTracker::VelocityTracker() :
-        mCurrentPointerIdBits(0), mActivePointerId(-1),
+        mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1),
         mStrategy(new LeastSquaresVelocityTrackerStrategy()) {
 }
 
-VelocityTracker::VelocityTracker(VelocityTrackerStrategy* strategy) :
-        mCurrentPointerIdBits(0), mActivePointerId(-1),
-        mStrategy(strategy) {
-}
-
 VelocityTracker::~VelocityTracker() {
     delete mStrategy;
 }
@@ -125,6 +130,18 @@
         idBits.clearLastMarkedBit();
     }
 
+    if ((mCurrentPointerIdBits.value & idBits.value)
+            && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
+#if DEBUG_VELOCITY
+        ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
+                (eventTime - mLastEventTime) * 0.000001f);
+#endif
+        // We have not received any movements for too long.  Assume that all pointers
+        // have stopped.
+        mStrategy->clear();
+    }
+    mLastEventTime = eventTime;
+
     mCurrentPointerIdBits = idBits;
     if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
         mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit();
@@ -467,6 +484,7 @@
         uint32_t n = degree + 1;
         if (solveLeastSquares(time, x, m, n, outEstimator->xCoeff, &xdet)
                 && solveLeastSquares(time, y, m, n, outEstimator->yCoeff, &ydet)) {
+            outEstimator->time = newestMovement.eventTime;
             outEstimator->degree = degree;
             outEstimator->confidence = xdet * ydet;
 #if DEBUG_LEAST_SQUARES
@@ -483,6 +501,7 @@
     // No velocity data available for this pointer, but we do have its current position.
     outEstimator->xCoeff[0] = x[0];
     outEstimator->yCoeff[0] = y[0];
+    outEstimator->time = newestMovement.eventTime;
     outEstimator->degree = 0;
     outEstimator->confidence = 1;
     return true;