Allow use of fake timestamps in gesture library

There are cases when touchpad timestamp deltas will not be reliable,
such as for bluetooth touchpads.  For example the timestamp delta may be
very small for several reports, then jump a lot to catch up.

In order to improve finger velocity tracking for these touchpads, we
ignore the timestamp delta reported by the device, and add a fake
timestamp delta based on the device's report rate.

BUG=b:117569252
TEST=Deploy to nocturne and test using bluetooth touchpad, with
CL 1274705

Change-Id: Ica2ff004553c997fd0334219767372f82d2ccac8
Reviewed-on: https://chromium-review.googlesource.com/1274765
Commit-Ready: Sean O'Brien <seobrien@chromium.org>
Tested-by: Andrew de los Reyes <adlr@chromium.org>
Reviewed-by: Andrew de los Reyes <adlr@chromium.org>
diff --git a/include/timestamp_filter_interpreter.h b/include/timestamp_filter_interpreter.h
index d4fbf25..f9df057 100644
--- a/include/timestamp_filter_interpreter.h
+++ b/include/timestamp_filter_interpreter.h
@@ -2,47 +2,78 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <gtest/gtest.h>  // for FRIEND_TEST
+
 #include "gestures/include/filter_interpreter.h"
 #include "gestures/include/gestures.h"
+#include "gestures/include/prop_registry.h"
 #include "gestures/include/tracer.h"
 
 #ifndef GESTURES_TIMESTAMP_FILTER_INTERPRETER_H_
 #define GESTURES_TIMESTAMP_FILTER_INTERPRETER_H_
 
-// This class fixes up the timestamp of the hardware state.
-// Before this filter is applied, there are two possibilities:
-//   1) hwstate->timestamp == CLOCK_MONOTONIC &&
-//      hwstate->msc_timestamp == 0.0
-//        - No changes are needed in this case
-//   2) hwstate->timestamp == CLOCK_MONOTONIC &&
-//      hwstate->msc_timestamp == MSC_TIMESTAMP
-//        - MSC_TIMESTAMP will be more accurate than CLOCK_MONOTONIC, so we want
-//          to use it for time deltas in the gesture library.  However,
-//          MSC_TIMESTAMP will reset to 0.0 if there are no touch events for at
-//          least 1 second. So whenever MSC_TIMESTAMP resets, we record the
-//          offset between CLOCK_MONOTONIC and MSC_TIMESTAMP and add this offset
-//          to subsequent events.
-// After this filter is applied:
-//   - hwstate->timestamp uses CLOCK_MONOTONIC as the time base, possibly with
-//     fine tuning provided by MSC_TIMESTAMP.
-//   - hwstate->msc_timestamp should not be used.
+// This class fixes up the timestamp of the hardware state. There are three
+// possibilities:
+//   1) hwstate->timestamp is reliable.
+//   2) hwstate->timestamp may be unreliable, but a reliable
+//      hwstate->msc_timestamp has been provided.
+//   3) hwstate->timestamp and hwstate->msc_timestamp are both unreliable.
+// ComputeTimestampDefault handles the first two cases, and
+// ComputeTimestampUsingFake handles the third case.
 
 namespace gestures {
 
 class TimestampFilterInterpreter : public FilterInterpreter {
+  FRIEND_TEST(TimestampFilterInterpreterTest, FakeTimestampTest);
+  FRIEND_TEST(TimestampFilterInterpreterTest, FakeTimestampJumpForwardTest);
+  FRIEND_TEST(TimestampFilterInterpreterTest, FakeTimestampFallBackwardTest);
  public:
   // Takes ownership of |next|:
-  explicit TimestampFilterInterpreter(Interpreter* next, Tracer* tracer);
+  explicit TimestampFilterInterpreter(PropRegistry* prop_reg,
+                                      Interpreter* next,
+                                      Tracer* tracer);
   virtual ~TimestampFilterInterpreter() {}
 
  protected:
   virtual void SyncInterpretImpl(HardwareState* hwstate, stime_t* timeout);
 
  private:
+
+  // Before this function is applied, there are two possibilities:
+  //   1) hwstate->timestamp == CLOCK_MONOTONIC &&
+  //      hwstate->msc_timestamp == 0.0
+  //        - No changes are needed in this case
+  //   2) hwstate->timestamp == CLOCK_MONOTONIC &&
+  //      hwstate->msc_timestamp == MSC_TIMESTAMP
+  //        - MSC_TIMESTAMP will be more accurate than CLOCK_MONOTONIC, so we
+  //          want to use it for time deltas in the gesture library.  However,
+  //          MSC_TIMESTAMP will reset to 0.0 if there are no touch events for
+  //          at least 1 second. So whenever MSC_TIMESTAMP resets, we record the
+  //          offset between CLOCK_MONOTONIC and MSC_TIMESTAMP and add this
+  //          offset to subsequent events.
+  // After this function is applied:
+  //   - hwstate->timestamp uses CLOCK_MONOTONIC as the time base, possibly with
+  //     fine tuning provided by MSC_TIMESTAMP.
+  //   - hwstate->msc_timestamp should not be used.
+  void ChangeTimestampDefault(HardwareState* hwstate);
+
+  // If neither hwstate->timestamp nor hwstate->msc_timestamp has reliable
+  // deltas, we use fake_timestamp_delta_ as the delta between consecutive
+  // reports, but don't allow our faked timestamp to diverge too far from
+  // hwstate->timestamp.
+  void ChangeTimestampUsingFake(HardwareState* hwstate);
+
   stime_t prev_msc_timestamp_;
 
   // Difference between msc_timestamp and timestamp as of last timestamp reset.
   stime_t msc_timestamp_offset_;
+
+  // If we are using fake timestamps, this holds the most recent fake
+  stime_t fake_timestamp_;
+  // If we don't have a reliable timestamp, we use this as the timestamp delta.
+  DoubleProperty fake_timestamp_delta_;
+  // Maximum we let fake_timestamp_ diverge from hwstate->timestamp
+  stime_t fake_timestamp_max_divergence_;
 };
 
 }  // namespace gestures
diff --git a/src/gestures.cc b/src/gestures.cc
index d2e6c63..ce69363 100644
--- a/src/gestures.cc
+++ b/src/gestures.cc
@@ -550,7 +550,7 @@
                                              tracer_.get());
   temp = new NonLinearityFilterInterpreter(prop_reg_.get(), temp,
                                            tracer_.get());
-  temp = new TimestampFilterInterpreter(temp, tracer_.get());
+  temp = new TimestampFilterInterpreter(prop_reg_.get(), temp, tracer_.get());
   temp = loggingFilter_ = new LoggingFilterInterpreter(prop_reg_.get(), temp,
                                                        tracer_.get());
   interpreter_.reset(temp);
@@ -576,7 +576,7 @@
                                       GESTURES_DEVCLASS_TOUCHPAD);
   temp = new FingerMergeFilterInterpreter(prop_reg_.get(), temp, tracer_.get());
   temp = new StuckButtonInhibitorFilterInterpreter(temp, tracer_.get());
-  temp = new TimestampFilterInterpreter(temp, tracer_.get());
+  temp = new TimestampFilterInterpreter(prop_reg_.get(), temp, tracer_.get());
   temp = loggingFilter_ = new LoggingFilterInterpreter(prop_reg_.get(), temp,
                                                        tracer_.get());
   interpreter_.reset(temp);
diff --git a/src/timestamp_filter_interpreter.cc b/src/timestamp_filter_interpreter.cc
index 046f9da..d1159bd 100644
--- a/src/timestamp_filter_interpreter.cc
+++ b/src/timestamp_filter_interpreter.cc
@@ -4,22 +4,35 @@
 
 #include "gestures/include/timestamp_filter_interpreter.h"
 
+#include <math.h>
+
 #include "gestures/include/logging.h"
 #include "gestures/include/tracer.h"
 
 namespace gestures {
 
 TimestampFilterInterpreter::TimestampFilterInterpreter(
-    Interpreter* next, Tracer* tracer)
+    PropRegistry* prop_reg, Interpreter* next, Tracer* tracer)
     : FilterInterpreter(NULL, next, tracer, false),
       prev_msc_timestamp_(-1.0),
-      msc_timestamp_offset_(-1.0) {
+      msc_timestamp_offset_(-1.0),
+      fake_timestamp_(-1.0),
+      fake_timestamp_delta_(prop_reg, "Fake Timestamp Delta", 0.0),
+      fake_timestamp_max_divergence_(0.1) {
   InitName();
 }
 
 void TimestampFilterInterpreter::SyncInterpretImpl(
     HardwareState* hwstate, stime_t* timeout) {
+  if (fake_timestamp_delta_.val_ == 0.0)
+    ChangeTimestampDefault(hwstate);
+  else
+    ChangeTimestampUsingFake(hwstate);
+  next_->SyncInterpret(hwstate, timeout);
+}
 
+void TimestampFilterInterpreter::ChangeTimestampDefault(
+    HardwareState* hwstate) {
   // Check if this is the first event or there has been a jump backwards.
   if (prev_msc_timestamp_ < 0.0 ||
       hwstate->msc_timestamp == 0.0 ||
@@ -29,7 +42,15 @@
   prev_msc_timestamp_ = hwstate->msc_timestamp;
   hwstate->timestamp = hwstate->msc_timestamp + msc_timestamp_offset_;
   hwstate->msc_timestamp = 0.0;
-  next_->SyncInterpret(hwstate, timeout);
+}
+
+void TimestampFilterInterpreter::ChangeTimestampUsingFake(
+    HardwareState* hwstate) {
+  fake_timestamp_ += fake_timestamp_delta_.val_;
+  if (fabs(fake_timestamp_ - hwstate->timestamp) >
+      fake_timestamp_max_divergence_)
+    fake_timestamp_ = hwstate->timestamp;
+  hwstate->timestamp = fake_timestamp_;
 }
 
 }  // namespace gestures
diff --git a/src/timestamp_filter_interpreter_unittest.cc b/src/timestamp_filter_interpreter_unittest.cc
index 9c02f3e..1d2995c 100644
--- a/src/timestamp_filter_interpreter_unittest.cc
+++ b/src/timestamp_filter_interpreter_unittest.cc
@@ -7,6 +7,7 @@
 #include "gestures/include/gestures.h"
 #include "gestures/include/timestamp_filter_interpreter.h"
 #include "gestures/include/unittest_util.h"
+#include "gestures/include/util.h"
 
 namespace gestures {
 
@@ -21,7 +22,7 @@
 TEST(TimestampFilterInterpreterTest, SimpleTest) {
   TimestampFilterInterpreterTestInterpreter* base_interpreter =
       new TimestampFilterInterpreterTestInterpreter;
-  TimestampFilterInterpreter interpreter(base_interpreter, NULL);
+  TimestampFilterInterpreter interpreter(NULL, base_interpreter, NULL);
   TestInterpreterWrapper wrapper(&interpreter);
 
   HardwareState hs[] = {
@@ -42,7 +43,7 @@
 TEST(TimestampFilterInterpreterTest, NoMscTimestampTest) {
   TimestampFilterInterpreterTestInterpreter* base_interpreter =
       new TimestampFilterInterpreterTestInterpreter;
-  TimestampFilterInterpreter interpreter(base_interpreter, NULL);
+  TimestampFilterInterpreter interpreter(NULL, base_interpreter, NULL);
   TestInterpreterWrapper wrapper(&interpreter);
 
   HardwareState hs[] = {
@@ -62,7 +63,7 @@
 TEST(TimestampFilterInterpreterTest, MscTimestampResetTest) {
   TimestampFilterInterpreterTestInterpreter* base_interpreter =
       new TimestampFilterInterpreterTestInterpreter;
-  TimestampFilterInterpreter interpreter(base_interpreter, NULL);
+  TimestampFilterInterpreter interpreter(NULL, base_interpreter, NULL);
   TestInterpreterWrapper wrapper(&interpreter);
 
   HardwareState hs[] = {
@@ -86,4 +87,88 @@
     EXPECT_EQ(hs[i].timestamp, expected_timestamps[i]);
   }
 }
+
+TEST(TimestampFilterInterpreterTest, FakeTimestampTest) {
+  TimestampFilterInterpreterTestInterpreter* base_interpreter =
+      new TimestampFilterInterpreterTestInterpreter;
+  TimestampFilterInterpreter interpreter(NULL, base_interpreter, NULL);
+  TestInterpreterWrapper wrapper(&interpreter);
+
+  interpreter.fake_timestamp_delta_.val_ = 0.010;
+
+  HardwareState hs[] = {
+    { 1.000, 0, 1, 1, NULL, 0, 0, 0, 0, 0.002 },
+    { 1.002, 0, 1, 1, NULL, 0, 0, 0, 0, 6.553 },
+    { 1.008, 0, 1, 1, NULL, 0, 0, 0, 0, 0.001 },
+    { 1.031, 0, 1, 1, NULL, 0, 0, 0, 0, 0.001 }
+  };
+
+  stime_t expected_timestamps[] = { 1.000, 1.010, 1.020, 1.030 };
+
+  for (size_t i = 0; i < arraysize(hs); i++) {
+    wrapper.SyncInterpret(&hs[i], NULL);
+    EXPECT_TRUE(DoubleEq(hs[i].timestamp, expected_timestamps[i]));
+  }
+}
+
+TEST(TimestampFilterInterpreterTest, FakeTimestampJumpForwardTest) {
+  TimestampFilterInterpreterTestInterpreter* base_interpreter =
+      new TimestampFilterInterpreterTestInterpreter;
+  TimestampFilterInterpreter interpreter(NULL, base_interpreter, NULL);
+  TestInterpreterWrapper wrapper(&interpreter);
+
+  interpreter.fake_timestamp_delta_.val_ = 0.010;
+
+  HardwareState hs[] = {
+    { 1.000, 0, 1, 1, NULL, 0, 0, 0, 0, 0.002 },
+    { 1.002, 0, 1, 1, NULL, 0, 0, 0, 0, 6.553 },
+    { 1.008, 0, 1, 1, NULL, 0, 0, 0, 0, 0.001 },
+    { 1.031, 0, 1, 1, NULL, 0, 0, 0, 0, 0.001 },
+    { 2.000, 0, 1, 1, NULL, 0, 0, 0, 0, 6.552 },
+    { 2.002, 0, 1, 1, NULL, 0, 0, 0, 0, 6.553 },
+    { 2.008, 0, 1, 1, NULL, 0, 0, 0, 0, 0.002 },
+    { 2.031, 0, 1, 1, NULL, 0, 0, 0, 0, 0.001 }
+  };
+
+  stime_t expected_timestamps[] = {
+    1.000, 1.010, 1.020, 1.030,
+    2.000, 2.010, 2.020, 2.030
+  };
+
+  for (size_t i = 0; i < arraysize(hs); i++) {
+    wrapper.SyncInterpret(&hs[i], NULL);
+    EXPECT_TRUE(DoubleEq(hs[i].timestamp, expected_timestamps[i]));
+  }
+}
+
+TEST(TimestampFilterInterpreterTest, FakeTimestampFallBackwardTest) {
+  TimestampFilterInterpreterTestInterpreter* base_interpreter =
+      new TimestampFilterInterpreterTestInterpreter;
+  TimestampFilterInterpreter interpreter(NULL, base_interpreter, NULL);
+  TestInterpreterWrapper wrapper(&interpreter);
+
+  interpreter.fake_timestamp_delta_.val_ = 0.010;
+  interpreter.fake_timestamp_max_divergence_ = 0.030;
+
+  HardwareState hs[] = {
+    { 1.000, 0, 1, 1, NULL, 0, 0, 0, 0, 0.002 },
+    { 1.001, 0, 1, 1, NULL, 0, 0, 0, 0, 6.553 },
+    { 1.002, 0, 1, 1, NULL, 0, 0, 0, 0, 0.001 },
+    { 1.003, 0, 1, 1, NULL, 0, 0, 0, 0, 0.001 },
+    { 1.004, 0, 1, 1, NULL, 0, 0, 0, 0, 6.552 },
+    { 1.005, 0, 1, 1, NULL, 0, 0, 0, 0, 6.553 },
+    { 1.006, 0, 1, 1, NULL, 0, 0, 0, 0, 0.002 },
+    { 1.007, 0, 1, 1, NULL, 0, 0, 0, 0, 6.552 }
+  };
+
+  stime_t expected_timestamps[] = {
+    1.000, 1.010, 1.020, 1.030,
+    1.004, 1.014, 1.024, 1.034,
+  };
+
+  for (size_t i = 0; i < arraysize(hs); i++) {
+    wrapper.SyncInterpret(&hs[i], NULL);
+    EXPECT_TRUE(DoubleEq(hs[i].timestamp, expected_timestamps[i]));
+  }
+}
 }  // namespace gestures