Reland "Make VelocityTracker 1D" (--try 2)

This fixes a bug where stale velocities were not cleaned up during calls
to get updated velocities.
86f72a3882ab4994dfbb410ebebc9ab3a75b8b16

Topic for the revert which is being rolled-forward: https://googleplex-android-review.git.corp.google.com/q/topic:revert-19762050-generic_vt-XWGGUQUHYR

Bug: 32830165
Test: VelocityTracker_test unaffected (atest libinput_tests)

Change-Id: Ib706e76b9502e262eabfd221bd741e5faaee1ed5
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 4a445de..f8e5052 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -16,9 +16,10 @@
 
 #define LOG_TAG "VelocityTracker_test"
 
+#include <math.h>
 #include <array>
 #include <chrono>
-#include <math.h>
+#include <limits>
 
 #include <android-base/stringprintf.h>
 #include <attestation/HmacKeyManager.h>
@@ -198,25 +199,13 @@
                                     const std::vector<MotionEventEntry>& motions, int32_t axis,
                                     float targetVelocity, uint32_t pointerId = DEFAULT_POINTER_ID) {
     VelocityTracker vt(strategy);
-    float Vx, Vy;
 
     std::vector<MotionEvent> events = createMotionEventStream(motions);
     for (MotionEvent event : events) {
         vt.addMovement(&event);
     }
 
-    vt.getVelocity(pointerId, &Vx, &Vy);
-
-    switch (axis) {
-    case AMOTION_EVENT_AXIS_X:
-        checkVelocity(Vx, targetVelocity);
-        break;
-    case AMOTION_EVENT_AXIS_Y:
-        checkVelocity(Vy, targetVelocity);
-        break;
-    default:
-        FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
-    }
+    checkVelocity(vt.getVelocity(axis, pointerId).value_or(0), targetVelocity);
 }
 
 static void computeAndCheckQuadraticEstimate(const std::vector<MotionEventEntry>& motions,
@@ -226,17 +215,99 @@
     for (MotionEvent event : events) {
         vt.addMovement(&event);
     }
-    VelocityTracker::Estimator estimator;
-    EXPECT_TRUE(vt.getEstimator(0, &estimator));
+    VelocityTracker::Estimator estimatorX;
+    VelocityTracker::Estimator estimatorY;
+    EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_X, 0, &estimatorX));
+    EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_Y, 0, &estimatorY));
     for (size_t i = 0; i< coefficients.size(); i++) {
-        checkCoefficient(estimator.xCoeff[i], coefficients[i]);
-        checkCoefficient(estimator.yCoeff[i], coefficients[i]);
+        checkCoefficient(estimatorX.coeff[i], coefficients[i]);
+        checkCoefficient(estimatorY.coeff[i], coefficients[i]);
     }
 }
 
 /*
  * ================== VelocityTracker tests generated manually =====================================
  */
+TEST_F(VelocityTrackerTest, TestComputedVelocity) {
+    VelocityTracker::ComputedVelocity computedVelocity;
+
+    computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 0 /*id*/, 200 /*velocity*/);
+    computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/, 400 /*velocity*/);
+    computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/, 650 /*velocity*/);
+    computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID, 750 /*velocity*/);
+    computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 0 /*id*/, 1000 /*velocity*/);
+    computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/, 2000 /*velocity*/);
+    computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/, 3000 /*velocity*/);
+    computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID, 4000 /*velocity*/);
+
+    // Check the axes/indices with velocity.
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 0U /*id*/)), 200);
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/)), 400);
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/)), 650);
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID)), 750);
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 0U /*id*/)), 1000);
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/)), 2000);
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/)), 3000);
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID)), 4000);
+    for (uint32_t id = 0; id <= MAX_POINTER_ID; id++) {
+        // Since no data was added for AXIS_SCROLL, expect empty value for the axis for any id.
+        EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, id))
+                << "Empty scroll data expected at id=" << id;
+        if (id == 0 || id == 26U || id == 27U || id == MAX_POINTER_ID) {
+            // Already checked above; continue.
+            continue;
+        }
+        // No data was added to X/Y for this id, expect empty value.
+        EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, id))
+                << "Empty X data expected at id=" << id;
+        EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, id))
+                << "Empty Y data expected at id=" << id;
+    }
+    // Out-of-bounds ids should given empty values.
+    EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, -1));
+    EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID + 1));
+}
+
+TEST_F(VelocityTrackerTest, TestGetComputedVelocity) {
+    std::vector<MotionEventEntry> motions = {
+            {235089067457000ns, {{528.00, 0}}}, {235089084684000ns, {{527.00, 0}}},
+            {235089093349000ns, {{527.00, 0}}}, {235089095677625ns, {{527.00, 0}}},
+            {235089101859000ns, {{527.00, 0}}}, {235089110378000ns, {{528.00, 0}}},
+            {235089112497111ns, {{528.25, 0}}}, {235089118760000ns, {{531.00, 0}}},
+            {235089126686000ns, {{535.00, 0}}}, {235089129316820ns, {{536.33, 0}}},
+            {235089135199000ns, {{540.00, 0}}}, {235089144297000ns, {{546.00, 0}}},
+            {235089146136443ns, {{547.21, 0}}}, {235089152923000ns, {{553.00, 0}}},
+            {235089160784000ns, {{559.00, 0}}}, {235089162955851ns, {{560.66, 0}}},
+            {235089162955851ns, {{560.66, 0}}}, // ACTION_UP
+    };
+    VelocityTracker vt(VelocityTracker::Strategy::IMPULSE);
+    std::vector<MotionEvent> events = createMotionEventStream(motions);
+    for (const MotionEvent& event : events) {
+        vt.addMovement(&event);
+    }
+
+    float maxFloat = std::numeric_limits<float>::max();
+    VelocityTracker::ComputedVelocity computedVelocity;
+    computedVelocity = vt.getComputedVelocity(1000 /* units */, maxFloat);
+    checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)),
+                  764.345703);
+
+    // Expect X velocity to be scaled with respective to provided units.
+    computedVelocity = vt.getComputedVelocity(1000000 /* units */, maxFloat);
+    checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)),
+                  764345.703);
+
+    // Expect X velocity to be clamped by provided max velocity.
+    computedVelocity = vt.getComputedVelocity(1000000 /* units */, 1000);
+    checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)), 1000);
+
+    // All 0 data for Y; expect 0 velocity.
+    EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, DEFAULT_POINTER_ID)), 0);
+
+    // No data for scroll-axis; expect empty velocity.
+    EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, DEFAULT_POINTER_ID));
+}
+
 TEST_F(VelocityTrackerTest, ThreePointsPositiveVelocityTest) {
     // Same coordinate is reported 2 times in a row
     // It is difficult to determine the correct answer here, but at least the direction