replay: Fixed bug in trimmer which caused playback errors

The trimmed replay logs will now reset all slots to the tracking id -1
before and after the actual log. Which basically means: all fingers removed.
There is a test-case in trimmer_tests to check if all trimmed files actually
end with all fingers removed.

BUG=chromium-os:31732
TEST=make tests

Change-Id: I77d3844d721351620d15812db5cb497174dc42f5
Reviewed-on: https://gerrit.chromium.org/gerrit/28897
Commit-Ready: Dennis Kempin <denniskempin@chromium.org>
Reviewed-by: Dennis Kempin <denniskempin@chromium.org>
Tested-by: Dennis Kempin <denniskempin@chromium.org>
diff --git a/replay/src/trimmer.cc b/replay/src/trimmer.cc
index 29eab27..3fa661a 100644
--- a/replay/src/trimmer.cc
+++ b/replay/src/trimmer.cc
@@ -24,10 +24,14 @@
   Evdev* device = replay_->evdev_device();
 
   // write slots
-  for (int i = 0; i < evstate->slot_count; i++) {
-    MtSlotPtr slot = &evstate->slots[i];
-    if (slot->tracking_id == -1)
+  for (int i = evstate->slot_min; i < evstate->slot_min + evstate->slot_count;
+       i++) {
+    MtSlotPtr slot = &evstate->slots[i - evstate->slot_min];
+    if (slot->tracking_id == -1) {
+      WriteEvent(out, syn->time, EV_ABS, ABS_MT_SLOT, i);
+      WriteEvent(out, syn->time, EV_ABS, ABS_MT_TRACKING_ID, -1);
       continue;
+    }
     WriteEvent(out, syn->time, EV_ABS, ABS_MT_SLOT, i);
     WriteEvent(out, syn->time, EV_ABS, ABS_MT_TOUCH_MAJOR, slot->touch_major);
     WriteEvent(out, syn->time, EV_ABS, ABS_MT_TOUCH_MINOR, slot->touch_minor);
@@ -43,6 +47,16 @@
     WriteEvent(out, syn->time, EV_ABS, ABS_MT_DISTANCE, slot->distance);
   }
 
+  // activate the currently active slot
+  for (int i = evstate->slot_min; i < evstate->slot_min + evstate->slot_count;
+       i++) {
+    MtSlotPtr slot = &evstate->slots[i - evstate->slot_min];
+    if (slot == evstate->slot_current) {
+      WriteEvent(out, syn->time, EV_ABS, ABS_MT_SLOT, i);
+      break;
+    }
+  }
+
   // write key state
   for (int i = 0; i < KEY_CNT; ++i) {
     if (TestBit(i, device->key_state_bitmask)) {
@@ -75,7 +89,7 @@
           continue;
         }
       } else if (timestamp >= to) {
-        // we have reached the to timestamp. we are done here.
+        // we have reached the 'to' timestamp
         evemu::EvemuDevice::WriteEvent(out->GetStream(), event);
         break;
       }
@@ -89,6 +103,15 @@
       evemu::EvemuDevice::WriteEvent(out->GetStream(), event);
     }
   }
+
+  // 0.5 seconds after replay: Add cleanup state
+  EventStatePtr evstate = replay_->current_state();
+  event.time.tv_usec += 500;
+  for (int i = 0; i < evstate->slot_count; i++) {
+    WriteEvent(out, event.time, EV_ABS, ABS_MT_SLOT, i);
+    WriteEvent(out, event.time, EV_ABS, ABS_MT_TRACKING_ID, -1);
+  }
+
   return true;
 }
 
diff --git a/replay/src/trimmer_tests.cc b/replay/src/trimmer_tests.cc
index e93e1da..89e0833 100644
--- a/replay/src/trimmer_tests.cc
+++ b/replay/src/trimmer_tests.cc
@@ -128,17 +128,19 @@
       // only check if one of the devices treats this slot as tracked.
       if (slot_original->tracking_id >= 0 || slot_trimmed->tracking_id >= 0) {
         EXPECT_EQ(slot_original->tracking_id, slot_trimmed->tracking_id);
-        EXPECT_EQ(slot_original->touch_major, slot_trimmed->touch_major);
-        EXPECT_EQ(slot_original->touch_minor, slot_trimmed->touch_minor);
-        EXPECT_EQ(slot_original->width_major, slot_trimmed->width_major);
-        EXPECT_EQ(slot_original->width_minor, slot_trimmed->width_minor);
-        EXPECT_EQ(slot_original->orientation, slot_trimmed->orientation);
-        EXPECT_EQ(slot_original->position_x,  slot_trimmed->position_x );
-        EXPECT_EQ(slot_original->position_y,  slot_trimmed->position_y );
-        EXPECT_EQ(slot_original->tool_type,   slot_trimmed->tool_type  );
-        EXPECT_EQ(slot_original->blob_id,     slot_trimmed->blob_id    );
-        EXPECT_EQ(slot_original->pressure,    slot_trimmed->pressure   );
-        EXPECT_EQ(slot_original->distance,    slot_trimmed->distance   );
+        if (slot_original->tracking_id >= 0 && slot_trimmed->tracking_id >= 0) {
+          EXPECT_EQ(slot_original->touch_major, slot_trimmed->touch_major);
+          EXPECT_EQ(slot_original->touch_minor, slot_trimmed->touch_minor);
+          EXPECT_EQ(slot_original->width_major, slot_trimmed->width_major);
+          EXPECT_EQ(slot_original->width_minor, slot_trimmed->width_minor);
+          EXPECT_EQ(slot_original->orientation, slot_trimmed->orientation);
+          EXPECT_EQ(slot_original->position_x,  slot_trimmed->position_x );
+          EXPECT_EQ(slot_original->position_y,  slot_trimmed->position_y );
+          EXPECT_EQ(slot_original->tool_type,   slot_trimmed->tool_type  );
+          EXPECT_EQ(slot_original->blob_id,     slot_trimmed->blob_id    );
+          EXPECT_EQ(slot_original->pressure,    slot_trimmed->pressure   );
+          EXPECT_EQ(slot_original->distance,    slot_trimmed->distance   );
+        }
       }
     }
 
@@ -148,7 +150,16 @@
                 device_original->evdev_device()->key_state_bitmask[i]);
     }
   }
+  // Checks if the replay left the device clean
+  void ExpectClean() {
+    EventStatePtr state_trimmed = replay_trimmed_->current_state();
 
+    // check if all fingers are removed
+    for (int i = 0; i < state_trimmed->slot_count; i++) {
+      MtSlotPtr slot_trimmed = &state_trimmed->slots[i];
+      EXPECT_EQ(slot_trimmed->tracking_id, -1);
+    }
+  }
   // Replay both devices and check the event state at each SYN event.
   void ExpectEqualReplay() {
     ExpectEqualState(replay_trimmed_, replay_original_);
@@ -213,12 +224,14 @@
   double inf = std::numeric_limits<double>::infinity();
   TrimEvents(-inf, inf);
   ExpectNoTrimming();
+  ExpectClean();
 }
 
 TEST_F(TrimmerTests, TestFirstLastSynTrimming) {
   // first and last SYN timestamp
   TrimEvents(37716.042789, 38257.473632);
   ExpectNoTrimming();
+  ExpectClean();
 }
 
 TEST_F(TrimmerTests, TestTrimWhileFingersTouching) {
@@ -226,6 +239,7 @@
   // end: after 3 finger up/down movement
   TrimEvents(38242.311957, 38244.058656);
   ExpectTrimmedReplayIsEqual();
+  ExpectClean();
 }
 
 TEST_F(TrimmerTests, TestTrimWhileButtonPressed) {
@@ -233,6 +247,7 @@
   // end: after 3 finger up/down movement. With button still pressed.
   TrimEvents(38242.209067, 38253.411325);
   ExpectTrimmedReplayIsEqual();
+  ExpectClean();
 }
 
 }  // namespace replay