• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <deque>
6 #include <math.h>
7 #include <set>
8 #include <stdio.h>
9 #include <utility>
10 #include <vector>
11 
12 #include <gtest/gtest.h>
13 
14 #include "include/gestures.h"
15 #include "include/lookahead_filter_interpreter.h"
16 #include "include/unittest_util.h"
17 #include "include/util.h"
18 
19 using std::deque;
20 using std::pair;
21 
22 namespace gestures {
23 
24 class LookaheadFilterInterpreterTest : public ::testing::Test {};
25 
26 class LookaheadFilterInterpreterTestInterpreter : public Interpreter {
27  public:
LookaheadFilterInterpreterTestInterpreter()28   LookaheadFilterInterpreterTestInterpreter()
29       : Interpreter(NULL, NULL, false),
30         timer_return_(NO_DEADLINE),
31         clear_incoming_hwstates_(false), expected_id_(-1),
32         expected_flags_(0), expected_flags_at_(-1),
33         expected_flags_at_occurred_(false) {}
34 
SyncInterpret(HardwareState * hwstate,stime_t * timeout)35   virtual void SyncInterpret(HardwareState* hwstate, stime_t* timeout) {
36     for (size_t i = 0; i < hwstate->finger_cnt; i++)
37       all_ids_.insert(hwstate->fingers[i].tracking_id);
38     if (expected_id_ >= 0) {
39       EXPECT_EQ(1, hwstate->finger_cnt);
40       EXPECT_EQ(expected_id_, hwstate->fingers[0].tracking_id);
41     }
42     if (!expected_ids_.empty()) {
43       EXPECT_EQ(expected_ids_.size(), hwstate->finger_cnt);
44       for (std::set<short>::iterator it = expected_ids_.begin(),
45                e = expected_ids_.end(); it != e; ++it) {
46         EXPECT_TRUE(hwstate->GetFingerState(*it)) << "Can't find ID " << *it
47                                                   << " at "
48                                                   << hwstate->timestamp;
49       }
50     }
51     if (expected_flags_at_ >= 0 &&
52         DoubleEq(expected_flags_at_, hwstate->timestamp) &&
53         hwstate->finger_cnt > 0) {
54       EXPECT_EQ(expected_flags_, hwstate->fingers[0].flags);
55       expected_flags_at_occurred_ = true;
56     }
57     if (clear_incoming_hwstates_)
58       hwstate->finger_cnt = 0;
59     if (timer_return_ >= 0.0) {
60       *timeout = timer_return_;
61       timer_return_ = NO_DEADLINE;
62     }
63     if (return_values_.empty())
64       return;
65     return_value_ = return_values_.front();
66     return_values_.pop_front();
67     ProduceGesture(return_value_);
68   }
69 
HandleTimer(stime_t now,stime_t * timeout)70   virtual void HandleTimer(stime_t now, stime_t* timeout) {
71     EXPECT_TRUE(false);
72   }
73 
74   Gesture return_value_;
75   deque<Gesture> return_values_;
76   stime_t timer_return_;
77   bool clear_incoming_hwstates_;
78   // if expected_id_ >= 0, we expect that there is one finger with
79   // the expected id.
80   short expected_id_;
81   // if expected_ids_ is populated, we expect fingers w/ exactly those IDs
82   std::set<short> expected_ids_;
83   // If we get a hardware state at time expected_flags_at_, it should have
84   // the following flags set.
85   unsigned expected_flags_;
86   stime_t expected_flags_at_;
87   bool expected_flags_at_occurred_;
88   std::set<short> all_ids_;
89 };
90 
TEST(LookaheadFilterInterpreterTest,SimpleTest)91 TEST(LookaheadFilterInterpreterTest, SimpleTest) {
92   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
93   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
94 
95   HardwareProperties initial_hwprops = {
96     0, 0, 100, 100,  // left, top, right, bottom
97     10,  // x res (pixels/mm)
98     10,  // y res (pixels/mm)
99     133, 133,  // scrn DPI X, Y
100     -1,  // orientation minimum
101     2,   // orientation maximum
102     2, 5,  // max fingers, max_touch
103     1, 0, 0,  // t5r2, semi, button pad
104     0, 0,  // has wheel, vertical wheel is high resolution
105     0,  // haptic pad
106   };
107   TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops);
108 
109   FingerState fs[] = {
110     // TM, Tm, WM, Wm, pr, orient, x, y, id
111     { 0, 0, 0, 0, 1, 0, 10, 1, 1, 0 },
112     { 0, 0, 0, 0, 1, 0, 10, 2, 1, 0 },
113     { 0, 0, 0, 0, 1, 0, 10, 3, 1, 0 },
114 
115     { 0, 0, 0, 0, 1, 0, 10, 1, 2, 0 },
116     { 0, 0, 0, 0, 1, 0, 10, 2, 2, 0 },
117 
118     { 0, 0, 0, 0, 1, 0, 10, 1, 3, 0 },
119     { 0, 0, 0, 0, 1, 0, 10, 2, 3, 0 },
120   };
121   HardwareState hs[] = {
122     // Expect movement to take
123     make_hwstate(1.01, 0, 1, 1, &fs[0]),
124     make_hwstate(1.02, 0, 1, 1, &fs[1]),
125     make_hwstate(1.03, 0, 1, 1, &fs[2]),
126 
127     // Expect no movement
128     make_hwstate(2.010, 0, 1, 1, &fs[3]),
129     make_hwstate(2.030, 0, 1, 1, &fs[4]),
130     make_hwstate(2.031, 0, 0, 0, NULL),
131 
132     // Expect movement b/c it's moving really fast
133     make_hwstate(3.010, 0, 1, 1, &fs[5]),
134     make_hwstate(3.011, 0, 1, 1, &fs[6]),
135     make_hwstate(3.030, 0, 0, 0, NULL),
136   };
137 
138   stime_t expected_timeout = 0.0;
139   Gesture expected_movement;
140   for (size_t i = 3; i < arraysize(hs); ++i) {
141     if (i % 3 == 0) {
142       base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
143 
144       for (size_t j = 0; j < 2; ++j) {
145         if (hs[i + j + 1].finger_cnt == 0)
146           break;
147         expected_movement = Gesture(kGestureMove,
148                                     hs[i + j].timestamp,  // start time
149                                     hs[i + j + 1].timestamp,  // end time
150                                     hs[i + j + 1].fingers[0].position_x -
151                                     hs[i + j].fingers[0].position_x,  // dx
152                                     hs[i + j + 1].fingers[0].position_y -
153                                     hs[i + j].fingers[0].position_y);  // dy
154         base_interpreter->return_values_.push_back(expected_movement);
155       }
156 
157       interpreter.reset(new LookaheadFilterInterpreter(
158           NULL, base_interpreter, NULL));
159       wrapper.Reset(interpreter.get());
160       interpreter->min_delay_.val_ = 0.05;
161       expected_timeout = interpreter->min_delay_.val_;
162     }
163     stime_t timeout = NO_DEADLINE;
164     Gesture* out = wrapper.SyncInterpret(&hs[i], &timeout);
165     if (out) {
166       EXPECT_EQ(kGestureTypeFling, out->type);
167       EXPECT_EQ(GESTURES_FLING_TAP_DOWN, out->details.fling.fling_state);
168     }
169     EXPECT_LT(fabs(expected_timeout - timeout), 0.0000001);
170     if ((i % 3) != 2) {
171       expected_timeout -= hs[i + 1].timestamp - hs[i].timestamp;
172     } else {
173       stime_t newtimeout = NO_DEADLINE;
174       out = wrapper.HandleTimer(hs[i].timestamp + timeout, &newtimeout);
175       if (newtimeout < 0.0)
176         EXPECT_DOUBLE_EQ(NO_DEADLINE, newtimeout);
177       if (i == 5) {
178         EXPECT_EQ(nullptr, out);
179       } else {
180         // Expect movement
181         ASSERT_TRUE(out);
182         EXPECT_EQ(kGestureTypeMove, out->type);
183         EXPECT_EQ(expected_movement.start_time, out->start_time);
184         EXPECT_EQ(expected_movement.end_time, out->end_time);
185         EXPECT_EQ(expected_movement.details.move.dx, out->details.move.dx);
186         EXPECT_EQ(expected_movement.details.move.dy, out->details.move.dy);
187       }
188       // Run through rest of interpreter timeouts, makeing sure we get
189       // reasonable timeout values
190       int cnt = 0;
191       stime_t now = hs[i].timestamp + timeout;
192       while (newtimeout >= 0.0) {
193         if (cnt++ == 10)
194           break;
195         timeout = newtimeout;
196         newtimeout = NO_DEADLINE;
197         now += timeout;
198         out = wrapper.HandleTimer(now, &newtimeout);
199         if (newtimeout >= 0.0)
200           EXPECT_LT(newtimeout, 1.0);
201         else
202           EXPECT_DOUBLE_EQ(NO_DEADLINE, newtimeout);
203       }
204     }
205   }
206 }
207 
208 class LookaheadFilterInterpreterVariableDelayTestInterpreter
209     : public Interpreter {
210  public:
LookaheadFilterInterpreterVariableDelayTestInterpreter()211   LookaheadFilterInterpreterVariableDelayTestInterpreter()
212       : Interpreter(NULL, NULL, false), interpret_call_count_ (0) {}
213 
SyncInterpret(HardwareState * hwstate,stime_t * timeout)214   virtual void SyncInterpret(HardwareState* hwstate, stime_t* timeout) {
215     interpret_call_count_++;
216     EXPECT_EQ(1, hwstate->finger_cnt);
217     finger_ids_.insert(hwstate->fingers[0].tracking_id);
218   }
219 
HandleTimer(stime_t now,stime_t * timeout)220   virtual void HandleTimer(stime_t now, stime_t* timeout) {
221     EXPECT_TRUE(false);
222   }
223 
224   std::set<short> finger_ids_;
225   size_t interpret_call_count_;
226 };
227 
228 // Tests that with a zero delay, we can still avoid unnecessary splitting
229 // by using variable delay.
TEST(LookaheadFilterInterpreterTest,VariableDelayTest)230 TEST(LookaheadFilterInterpreterTest, VariableDelayTest) {
231   LookaheadFilterInterpreterVariableDelayTestInterpreter* base_interpreter =
232       new LookaheadFilterInterpreterVariableDelayTestInterpreter;
233   LookaheadFilterInterpreter interpreter(NULL, base_interpreter, NULL);
234 
235   HardwareProperties initial_hwprops = {
236     0, 0, 100, 100,  // left, top, right, bottom
237     1,  // x res (pixels/mm)
238     1,  // y res (pixels/mm)
239     133, 133,  // scrn DPI X, Y
240     -1,  // orientation minimum
241     2,   // orientation maximum
242     5, 5,  // max fingers, max_touch,
243     0, 0, 0,  // t5r2, semi, button pad
244     0, 0,  // has wheel, vertical wheel is high resolution
245     0,  // haptic pad
246   };
247   TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops);
248 
249   FingerState fs[] = {
250     // TM, Tm, WM, Wm, pr, orient, x, y, id
251     { 0, 0, 0, 0, 1, 0, 10, 10, 10, 1 },
252     { 0, 0, 0, 0, 1, 0, 10, 30, 10, 1 },
253     { 0, 0, 0, 0, 1, 0, 10, 50, 10, 1 },
254   };
255   HardwareState hs[] = {
256     // Expect movement to take
257     make_hwstate(1.01, 0, 1, 1, &fs[0]),
258     make_hwstate(1.02, 0, 1, 1, &fs[1]),
259     make_hwstate(1.03, 0, 1, 1, &fs[2]),
260   };
261 
262   interpreter.min_delay_.val_ = 0.0;
263 
264   for (size_t i = 0; i < arraysize(hs); i++) {
265     stime_t timeout = NO_DEADLINE;
266     wrapper.SyncInterpret(&hs[i], &timeout);
267     stime_t next_input = i < (arraysize(hs) - 1) ? hs[i + 1].timestamp :
268         INFINITY;
269     stime_t now = hs[i].timestamp;
270     while (timeout >= 0 && (timeout + now) < next_input) {
271       now += timeout;
272       timeout = NO_DEADLINE;
273       wrapper.HandleTimer(now, &timeout);
274     }
275   }
276   EXPECT_EQ(3, base_interpreter->interpret_call_count_);
277   EXPECT_EQ(1, base_interpreter->finger_ids_.size());
278   EXPECT_EQ(1, *base_interpreter->finger_ids_.begin());
279 }
280 
281 class LookaheadFilterInterpreterNoTapSetTestInterpreter
282     : public Interpreter {
283  public:
LookaheadFilterInterpreterNoTapSetTestInterpreter()284   LookaheadFilterInterpreterNoTapSetTestInterpreter()
285       : Interpreter(NULL, NULL, false), interpret_call_count_(0) {}
286 
SyncInterpret(HardwareState * hwstate,stime_t * timeout)287   virtual void SyncInterpret(HardwareState* hwstate, stime_t* timeout) {
288     EXPECT_EQ(expected_finger_cnts_[interpret_call_count_],
289               hwstate->finger_cnt);
290     interpret_call_count_++;
291     if (hwstate->finger_cnt > 0)
292       EXPECT_TRUE(hwstate->fingers[0].flags & GESTURES_FINGER_NO_TAP);
293   }
294 
HandleTimer(stime_t now,stime_t * timeout)295   virtual void HandleTimer(stime_t now, stime_t* timeout) {
296     EXPECT_TRUE(false);
297   }
298 
299   std::set<short> finger_ids_;
300   size_t interpret_call_count_;
301   std::vector<short> expected_finger_cnts_;
302 };
303 
304 // Tests that with a zero delay, we can still avoid unnecessary splitting
305 // by using variable delay.
TEST(LookaheadFilterInterpreterTest,NoTapSetTest)306 TEST(LookaheadFilterInterpreterTest, NoTapSetTest) {
307   LookaheadFilterInterpreterNoTapSetTestInterpreter* base_interpreter =
308       new LookaheadFilterInterpreterNoTapSetTestInterpreter;
309   LookaheadFilterInterpreter interpreter(NULL, base_interpreter, NULL);
310   interpreter.min_delay_.val_ = 0.0;
311 
312   HardwareProperties initial_hwprops = {
313     0, 0, 100, 100,  // left, top, right, bottom
314     1,  // x res (pixels/mm)
315     1,  // y res (pixels/mm)
316     133, 133,  // scrn DPI X, Y
317     -1,  // orientation minimum
318     2,   // orientation maximum
319     5, 5,  // max fingers, max_touch
320     0, 0, 0,  // t5r2, semi, button pad
321     0, 0,  // has wheel, vertical wheel is high resolution
322     0,  // haptic pad
323   };
324 
325   FingerState fs[] = {
326     // TM, Tm, WM, Wm, pr, orient, x, y, id, flags
327     { 0, 0, 0, 0, 1, 0, 30, 10, 0, 0 },
328     { 0, 0, 0, 0, 1, 0, 30, 30, 0, 0 },
329     { 0, 0, 0, 0, 1, 0, 10, 10, 1, 0 },
330     { 0, 0, 0, 0, 1, 0, 10, 30, 1, 0 },
331   };
332   HardwareState hs[] = {
333     // Expect movement to take
334     make_hwstate(0.01, 0, 1, 1, &fs[0]),
335     make_hwstate(0.01, 0, 1, 1, &fs[1]),
336     make_hwstate(0.03, 0, 0, 0, NULL),
337     make_hwstate(1.01, 0, 1, 1, &fs[2]),
338     make_hwstate(1.02, 0, 1, 1, &fs[3]),
339   };
340 
341   TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops);
342 
343 
344   for (size_t i = 0; i < arraysize(hs); i++) {
345     base_interpreter->expected_finger_cnts_.push_back(hs[i].finger_cnt);
346     stime_t timeout = NO_DEADLINE;
347     interpreter.SyncInterpret(&hs[i], &timeout);
348     stime_t next_input = i < (arraysize(hs) - 1) ? hs[i + 1].timestamp :
349         INFINITY;
350     stime_t now = hs[i].timestamp;
351     while (timeout >= 0 && (timeout + now) < next_input) {
352       now += timeout;
353       timeout = NO_DEADLINE;
354       interpreter.HandleTimer(now, &timeout);
355     }
356   }
357   EXPECT_EQ(arraysize(hs), base_interpreter->interpret_call_count_);
358 }
359 
360 // This test makes sure that if an interpreter requests a timeout, and then
361 // there is a spurious callback, that we request another callback for the time
362 // that remains.
TEST(LookaheadFilterInterpreterTest,SpuriousCallbackTest)363 TEST(LookaheadFilterInterpreterTest, SpuriousCallbackTest) {
364   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
365   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
366 
367   HardwareProperties initial_hwprops = {
368     0, 0, 100, 100,  // left, top, right, bottom
369     10,  // x res (pixels/mm)
370     10,  // y res (pixels/mm)
371     133, 133,  // scrn DPI X, Y
372     -1,  // orientation minimum
373     2,   // orientation maximum
374     2, 5,  // max fingers, max_touch
375     1, 0, 0,  // t5r2, semi, button pad
376     0, 0,  // has wheel, vertical wheel is high resolution
377     0,  // haptic pad
378   };
379   TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops);
380 
381   HardwareState hs = make_hwstate(1, 0, 0, 0, NULL);
382 
383   base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
384   base_interpreter->timer_return_ = 1.0;
385   interpreter.reset(new LookaheadFilterInterpreter(
386       NULL, base_interpreter, NULL));
387   wrapper.Reset(interpreter.get());
388   interpreter->min_delay_.val_ = 0.05;
389 
390   stime_t timeout = NO_DEADLINE;
391   Gesture* out = wrapper.SyncInterpret(&hs, &timeout);
392   EXPECT_EQ(nullptr, out);
393   EXPECT_FLOAT_EQ(interpreter->min_delay_.val_, timeout);
394 
395   out = wrapper.HandleTimer(hs.timestamp + interpreter->min_delay_.val_,
396                                  &timeout);
397   EXPECT_EQ(nullptr, out);
398   EXPECT_FLOAT_EQ(1.0, timeout);
399 
400 
401   out = wrapper.HandleTimer(hs.timestamp + interpreter->min_delay_.val_ +
402                                  0.25,
403                                  &timeout);
404   EXPECT_EQ(nullptr, out);
405   EXPECT_FLOAT_EQ(0.75, timeout);
406 }
407 
TEST(LookaheadFilterInterpreterTest,TimeGoesBackwardsTest)408 TEST(LookaheadFilterInterpreterTest, TimeGoesBackwardsTest) {
409   LookaheadFilterInterpreterTestInterpreter* base_interpreter =
410       new LookaheadFilterInterpreterTestInterpreter;
411   Gesture expected_movement = Gesture(kGestureMove,
412                                       0.0,  // start time
413                                       0.0,  // end time
414                                       1.0,  // dx
415                                       1.0);  // dy
416   base_interpreter->return_values_.push_back(expected_movement);
417   base_interpreter->return_values_.push_back(expected_movement);
418   LookaheadFilterInterpreter interpreter(NULL, base_interpreter, NULL);
419 
420   HardwareProperties initial_hwprops = {
421     0, 0, 100, 100,  // left, top, right, bottom
422     1,  // x res (pixels/mm)
423     1,  // y res (pixels/mm)
424     133, 133,  // scrn DPI X, Y
425     -1,  // orientation minimum
426     2,   // orientation maximum
427     2, 5,  // max fingers, max_touch
428     1, 0, 0,  // t5r2, semi, button pad
429     0, 0,  // has wheel, vertical wheel is high resolution
430     0,  // haptic pad
431   };
432   TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops);
433 
434 
435   FingerState fs = {
436     // TM, Tm, WM, Wm, pr, orient, x, y, id
437     0, 0, 0, 0, 1, 0, 20, 20, 1, 0
438   };
439   HardwareState hs[] = {
440     // Initial state
441     make_hwstate(9.00, 0, 1, 1, &fs),
442     // Time jumps backwards, then goes forwards
443     make_hwstate(0.01, 0, 1, 1, &fs),
444     make_hwstate(0.02, 0, 1, 1, &fs),
445     make_hwstate(0.03, 0, 1, 1, &fs),
446     make_hwstate(0.04, 0, 1, 1, &fs),
447     make_hwstate(0.05, 0, 1, 1, &fs),
448     make_hwstate(0.06, 0, 1, 1, &fs),
449     make_hwstate(0.07, 0, 1, 1, &fs),
450     make_hwstate(0.08, 0, 1, 1, &fs),
451     make_hwstate(0.09, 0, 1, 1, &fs),
452     make_hwstate(0.10, 0, 1, 1, &fs),
453     make_hwstate(0.11, 0, 1, 1, &fs),
454     make_hwstate(0.12, 0, 1, 1, &fs),
455     make_hwstate(0.13, 0, 1, 1, &fs),
456     make_hwstate(0.14, 0, 1, 1, &fs),
457     make_hwstate(0.15, 0, 1, 1, &fs),
458     make_hwstate(0.16, 0, 1, 1, &fs),
459     make_hwstate(0.17, 0, 1, 1, &fs),
460     make_hwstate(0.18, 0, 1, 1, &fs),
461     make_hwstate(0.19, 0, 1, 1, &fs),
462     make_hwstate(0.20, 0, 1, 1, &fs),
463   };
464   for (size_t i = 0; i < arraysize(hs); ++i) {
465     stime_t timeout_requested = -1.0;
466     Gesture* result = wrapper.SyncInterpret(&hs[i], &timeout_requested);
467     if (result && result->type == kGestureTypeMove)
468       return;  // Success!
469   }
470   ADD_FAILURE() << "Should have gotten a move gesture";
471 }
472 
TEST(LookaheadFilterInterpreterTest,InterpolateHwStateTest)473 TEST(LookaheadFilterInterpreterTest, InterpolateHwStateTest) {
474   // This test takes the first two HardwareStates, Interpolates them, putting
475   // the output into the fourth slot. The third slot is the expected output.
476   FingerState fs[] = {
477     // TM, Tm, WM, Wm, pr, orient, x, y, id
478     { 0.1, 0.4, 1.6, 1.2, 10, 3, 102, 102, 1, 0 },
479     { 0.2, 0.5, 1.7, 1.3, 11, 4, 4, 4, 2, 0 },
480     { 0.3, 0.6, 1.8, 1.4, 12, 5, 4444, 9999, 3, 0 },
481 
482     { 0.5, 0.2, 2.0, 1.2, 13, 8, 200, 100, 1, 0 },
483     { 0.7, 0.4, 2.3, 1.3, 17, 7, 20, 22, 2, 0 },
484     { 1.0, 0.5, 2.4, 1.6, 10, 9, 5000, 5000, 3, 0 },
485 
486     { 0.3, 0.3, 1.8, 1.2, 11.5, 5.5, 151, 101, 1, 0 },
487     { 0.45, 0.45, 2.0, 1.3, 14, 5.5, 12, 13, 2, 0 },
488     { 0.65, 0.55, 2.1, 1.5, 11, 7, 4722, 7499.5, 3, 0 },
489 
490     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
491     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
492     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
493   };
494   HardwareState hs[] = {
495     // Expect movement to take
496     make_hwstate(1.011,  2, 3, 3, &fs[0]),
497     make_hwstate(1.022,  2, 3, 3, &fs[3]),
498     make_hwstate(1.0165, 2, 3, 3, &fs[6]),
499     make_hwstate(0, 0, 0, 0, &fs[9]),
500   };
501 
502   LookaheadFilterInterpreter::Interpolate(hs[0], hs[1], &hs[3]);
503   EXPECT_DOUBLE_EQ(hs[2].timestamp, hs[3].timestamp);
504   EXPECT_EQ(hs[2].buttons_down, hs[3].buttons_down);
505   EXPECT_EQ(hs[2].touch_cnt, hs[3].touch_cnt);
506   EXPECT_EQ(hs[2].finger_cnt, hs[3].finger_cnt);
507   for (size_t i = 0; i < hs[3].finger_cnt; i++)
508     EXPECT_TRUE(hs[2].fingers[i] == hs[3].fingers[i]) << "i=" << i;
509 }
510 
TEST(LookaheadFilterInterpreterTest,InterpolateTest)511 TEST(LookaheadFilterInterpreterTest, InterpolateTest) {
512   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
513   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
514 
515   HardwareProperties initial_hwprops = {
516     0, 0, 100, 100,  // left, top, right, bottom
517     10,  // x res (pixels/mm)
518     10,  // y res (pixels/mm)
519     133, 133,  // scrn DPI X, Y
520     -1,  // orientation minimum
521     2,   // orientation maximum
522     2, 5,  // max fingers, max_touch
523     1, 0, 0,  // t5r2, semi, button pad
524     0, 0,  // has wheel, vertical wheel is high resolution
525     0,  // haptic pad
526   };
527   TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops);
528 
529   FingerState fs = {
530     // TM, Tm, WM, Wm, pr, orient, x, y, id
531     0, 0, 0, 0, 1, 0, 10, 1, 1, 0
532   };
533   HardwareState hs[] = {
534     // Expect movement to take
535     make_hwstate(1.01, 0, 1, 1, &fs),
536     make_hwstate(1.02, 0, 1, 1, &fs),
537     make_hwstate(1.04, 0, 1, 1, &fs),
538   };
539 
540   // Tests that we can properly decide when to interpolate two events.
541   for (size_t i = 0; i < 2; ++i) {
542     bool should_interpolate = i;
543     base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
544     base_interpreter->clear_incoming_hwstates_ = true;
545     base_interpreter->return_values_.push_back(
546         Gesture(kGestureMove,
547                 0,  // start time
548                 1,  // end time
549                 0,  // dx
550                 1));  // dy
551     base_interpreter->return_values_.push_back(
552         Gesture(kGestureMove,
553                 1,  // start time
554                 2,  // end time
555                 0,  // dx
556                 2));  // dy
557     base_interpreter->return_values_.push_back(
558         Gesture(kGestureMove,
559                 2,  // start time
560                 3,  // end time
561                 0,  // dx
562                 3));  // dy
563     interpreter.reset(new LookaheadFilterInterpreter(
564         NULL, base_interpreter, NULL));
565     wrapper.Reset(interpreter.get());
566     interpreter->min_delay_.val_ = 0.05;
567 
568     stime_t timeout = NO_DEADLINE;
569     Gesture* out = wrapper.SyncInterpret(&hs[0], &timeout);
570     EXPECT_EQ(reinterpret_cast<Gesture*>(NULL), out);
571     EXPECT_GT(timeout, 0);
572     const size_t next_idx = should_interpolate ? 2 : 1;
573     timeout = NO_DEADLINE;
574     out = wrapper.SyncInterpret(&hs[next_idx], &timeout);
575     EXPECT_EQ(reinterpret_cast<Gesture*>(NULL), out);
576     EXPECT_GT(timeout, 0);
577 
578     // Fetch the gestures
579     size_t gs_count = 0;
580     stime_t now = hs[next_idx].timestamp + timeout;
581     do {
582       timeout = NO_DEADLINE;
583       out = wrapper.HandleTimer(now, &timeout);
584       EXPECT_NE(reinterpret_cast<Gesture*>(NULL), out);
585       gs_count++;
586       now += timeout;
587     } while(timeout > 0.0);
588     EXPECT_EQ(should_interpolate ? 3 : 2, gs_count);
589   }
590 }
591 
TEST(LookaheadFilterInterpreterTest,InterpolationOverdueTest)592 TEST(LookaheadFilterInterpreterTest, InterpolationOverdueTest) {
593   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
594   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
595 
596   HardwareProperties initial_hwprops = {
597     0, 0, 10, 10,  // left, top, right, bottom
598     1,  // x res (pixels/mm)
599     1,  // y res (pixels/mm)
600     25, 25,  // scrn DPI X, Y
601     -1,  // orientation minimum
602     2,   // orientation maximum
603     2, 5,  // max fingers, max_touch
604     1, 0, 0,  // t5r2, semi, button pad
605     0, 0,  // has wheel, vertical wheel is high resolution
606     0,  // haptic pad
607   };
608   TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops);
609 
610   FingerState fs = {
611     // TM, Tm, WM, Wm, pr, orient, x, y, id
612     0, 0, 0, 0, 1, 0, 10, 1, 1, 0
613   };
614   // These timestamps cause an interpolated event to be 1.492 at time 1.495,
615   // and so this tests that an overdue interpolated event is handled correctly.
616   HardwareState hs[] = {
617     // Expect movement to take
618     make_hwstate(1.456, 0, 1, 1, &fs),
619     make_hwstate(1.495, 0, 1, 1, &fs),
620   };
621 
622   base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
623   base_interpreter->timer_return_ = 0.700;
624   base_interpreter->return_values_.push_back(
625       Gesture(kGestureMove,
626               0,  // start time
627               1,  // end time
628               0,  // dx
629               1));  // dy
630   base_interpreter->return_values_.push_back(
631       Gesture(kGestureMove,
632               1,  // start time
633               2,  // end time
634               0,  // dx
635               2));  // dy
636   interpreter.reset(new LookaheadFilterInterpreter(
637       NULL, base_interpreter, NULL));
638   interpreter->min_delay_.val_ = 0.017;
639   wrapper.Reset(interpreter.get());
640 
641   stime_t timeout = NO_DEADLINE;
642   Gesture* out = wrapper.SyncInterpret(&hs[0], &timeout);
643   EXPECT_EQ(nullptr, out);
644   EXPECT_FLOAT_EQ(timeout, interpreter->min_delay_.val_);
645 
646   stime_t now = hs[0].timestamp + timeout;
647   timeout = NO_DEADLINE;
648   out = wrapper.HandleTimer(now, &timeout);
649   ASSERT_NE(nullptr, out);
650   EXPECT_EQ(kGestureTypeMove, out->type);
651   EXPECT_EQ(1, out->details.move.dy);
652   EXPECT_DOUBLE_EQ(timeout, 0.700);
653 
654   timeout = NO_DEADLINE;
655   out = wrapper.SyncInterpret(&hs[1], &timeout);
656   ASSERT_NE(nullptr, out);
657   EXPECT_EQ(kGestureTypeMove, out->type);
658   EXPECT_EQ(2, out->details.move.dy);
659   EXPECT_GE(timeout, 0.0);
660 }
661 
662 struct HardwareStateLastId {
663   HardwareState hs;
664   short expected_last_id;
665 };
666 
TEST(LookaheadFilterInterpreterTest,DrumrollTest)667 TEST(LookaheadFilterInterpreterTest, DrumrollTest) {
668   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
669   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
670 
671   HardwareProperties initial_hwprops = {
672     0, 0, 100, 100,  // left, top, right, bottom
673     1,  // x res (pixels/mm)
674     1,  // y res (pixels/mm)
675     25, 25,  // scrn DPI X, Y
676     -1,  // orientation minimum
677     2,   // orientation maximum
678     2, 5,  // max fingers, max_touch
679     1, 0, 0,  // t5r2, semi, button pad
680     0, 0,  // has wheel, vertical wheel is high resolution
681     0,  // haptic pad
682   };
683   TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops);
684 
685   FingerState fs[] = {
686     // TM, Tm, WM, Wm, pr, orient, x, y, id
687     { 0, 0, 0, 0, 1, 0, 40, 40, 1, 0 },
688     { 0, 0, 0, 0, 1, 0, 40, 80, 1, 0 },
689     { 0, 0, 0, 0, 1, 0, 40, 40, 2, 0 },
690     { 0, 0, 0, 0, 1, 0, 41, 80, 2, 0 },
691     // Warp cases:
692     { 0, 0, 0, 0, 1, 0, 40, 40, 3, 0 },
693     { 0, 0, 0, 0, 1, 0, 41, 80, 3, GESTURES_FINGER_WARP_X },
694     { 0, 0, 0, 0, 1, 0, 40, 40, 4, 0 },
695     { 0, 0, 0, 0, 1, 0, 41, 80, 4, GESTURES_FINGER_WARP_Y },
696     { 0, 0, 0, 0, 1, 0, 40, 40, 5, 0 },
697     { 0, 0, 0, 0, 1, 0, 41, 80, 5, GESTURES_FINGER_WARP_X |
698                                    GESTURES_FINGER_WARP_Y },
699   };
700   // These timestamps cause an interpolated event to be 1.492 at time 1.495,
701   // and so this tests that an overdue interpolated event is handled correctly.
702   HardwareStateLastId hsid[] = {
703     // Expect movement to take
704     { make_hwstate(1.000, 0, 1, 1, &fs[0]), 1 },
705     { make_hwstate(1.001, 0, 1, 1, &fs[0]), 1 },
706     { make_hwstate(1.002, 0, 1, 1, &fs[1]), 2 },
707     { make_hwstate(1.003, 0, 1, 1, &fs[1]), 2 },
708     { make_hwstate(1.004, 0, 1, 1, &fs[2]), 3 },
709     { make_hwstate(1.005, 0, 1, 1, &fs[3]), 4 },
710     { make_hwstate(1.006, 0, 1, 1, &fs[2]), 5 },
711     // Warp cases:
712     { make_hwstate(1.007, 0, 1, 1, &fs[4]), 6 },
713     { make_hwstate(1.008, 0, 1, 1, &fs[5]), 6 },
714     { make_hwstate(1.009, 0, 1, 1, &fs[6]), 7 },
715     { make_hwstate(1.010, 0, 1, 1, &fs[7]), 7 },
716     { make_hwstate(1.011, 0, 1, 1, &fs[8]), 8 },
717     { make_hwstate(1.012, 0, 1, 1, &fs[9]), 8 },
718   };
719 
720   base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
721   base_interpreter->return_values_.push_back(
722       Gesture(kGestureMove,
723               0,  // start time
724               1,  // end time
725               0,  // dx
726               1));  // dy
727   interpreter.reset(new LookaheadFilterInterpreter(
728       NULL, base_interpreter, NULL));
729   wrapper.Reset(interpreter.get());
730 
731   for (size_t i = 0; i < arraysize(hsid); i++) {
732     stime_t timeout = NO_DEADLINE;
733     Gesture* out = wrapper.SyncInterpret(&hsid[i].hs, &timeout);
734     if (out) {
735       EXPECT_EQ(kGestureTypeFling, out->type);
736       EXPECT_EQ(GESTURES_FLING_TAP_DOWN, out->details.fling.fling_state);
737     }
738     EXPECT_GT(timeout, 0);
739     EXPECT_EQ(interpreter->last_id_, hsid[i].expected_last_id);
740   }
741 }
742 
TEST(LookaheadFilterInterpreterTest,QuickMoveTest)743 TEST(LookaheadFilterInterpreterTest, QuickMoveTest) {
744   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
745   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
746 
747   HardwareProperties initial_hwprops = {
748     0, 0, 100, 100,  // left, top, right, bottom
749     1,  // x res (pixels/mm)
750     1,  // y res (pixels/mm)
751     25, 25,  // scrn DPI X, Y
752     -1,  // orientation minimum
753     2,   // orientation maximum
754     2, 5,  // max fingers, max_touch
755     1, 0, 0,  // t5r2, semi, button pad
756     0, 0,  // has wheel, vertical wheel is high resolution
757     0,  // haptic pad
758   };
759   TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops);
760 
761   FingerState fs[] = {
762     // TM, Tm, WM, Wm, pr, orient, x, y, id
763     { 0, 0, 0, 0, 1, 0, 40, 40, 1, 0 },
764     { 0, 0, 0, 0, 1, 0, 41, 80, 1, 0 },
765     { 0, 0, 0, 0, 1, 0, 40, 40, 1, 0 },
766 
767     { 0, 0, 0, 0, 1, 0, 40, 40, 2, 0 },
768     { 0, 0, 0, 0, 1, 0, 41, 80, 2, 0 },
769     { 0, 0, 0, 0, 1, 0, 40, 120, 2, 0 },
770   };
771 
772   HardwareState hs[] = {
773     // Drumroll
774     make_hwstate(1.000, 0, 1, 1, &fs[0]),
775     make_hwstate(1.001, 0, 1, 1, &fs[1]),
776     make_hwstate(1.002, 0, 1, 1, &fs[2]),
777     // No touch
778     make_hwstate(1.003, 0, 0, 0, &fs[0]),
779     // Quick movement
780     make_hwstate(1.034, 0, 1, 1, &fs[3]),
781     make_hwstate(1.035, 0, 1, 1, &fs[4]),
782     make_hwstate(1.036, 0, 1, 1, &fs[5]),
783   };
784 
785   base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
786   interpreter.reset(new LookaheadFilterInterpreter(
787       NULL, base_interpreter, NULL));
788   wrapper.Reset(interpreter.get());
789 
790   stime_t timeout = NO_DEADLINE;
791   const auto& queue = interpreter->queue_;
792 
793   // Pushing the first event
794   wrapper.SyncInterpret(&hs[0], &timeout);
795   EXPECT_EQ(queue.size(), 1);
796   EXPECT_EQ(queue.back().fs_[0].tracking_id, 1);
797 
798   // Expecting Drumroll detected and ID reassigned 1 -> 2.
799   wrapper.SyncInterpret(&hs[1], &timeout);
800   EXPECT_EQ(queue.size(), 2);
801   EXPECT_EQ(queue.back().fs_[0].tracking_id, 2);
802 
803   // Expecting Drumroll detected and ID reassigned 1 -> 3.
804   wrapper.SyncInterpret(&hs[2], &timeout);
805   EXPECT_EQ(queue.size(), 3);
806   EXPECT_EQ(queue.back().fs_[0].tracking_id, 3);
807 
808   // Removing the touch.
809   wrapper.SyncInterpret(&hs[3], &timeout);
810   EXPECT_EQ(queue.size(), 4);
811 
812   // New event comes, old events removed from the queue.
813   // New finger tracking ID assigned 2 - > 4.
814   wrapper.SyncInterpret(&hs[4], &timeout);
815   EXPECT_EQ(queue.size(), 2);
816   EXPECT_EQ(queue.back().fs_[0].tracking_id, 4);
817 
818   // Expecting Drumroll detected and ID reassigned 2 -> 5.
819   wrapper.SyncInterpret(&hs[5], &timeout);
820   EXPECT_EQ(queue.back().fs_[0].tracking_id, 5);
821 
822   // Expecting Quick movement detected and ID correction 5 -> 4.
823   wrapper.SyncInterpret(&hs[6], &timeout);
824   EXPECT_EQ(interpreter->queue_.at(-1).fs_[0].tracking_id, 4);
825   EXPECT_EQ(interpreter->queue_.at(-2).fs_[0].tracking_id, 4);
826   EXPECT_EQ(interpreter->queue_.at(-3).fs_[0].tracking_id, 4);
827 }
828 
829 struct QuickSwipeTestInputs {
830   stime_t now;
831   float x0, y0, pressure0;
832   short id0;
833   float x1, y1, pressure1;
834   short id1;
835 };
836 
837 // Based on a couple quick swipes of 2 fingers on Alex, makes sure that we
838 // don't drumroll-separate the fingers.
TEST(LookaheadFilterInterpreterTest,QuickSwipeTest)839 TEST(LookaheadFilterInterpreterTest, QuickSwipeTest) {
840   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
841   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
842 
843   HardwareProperties initial_hwprops = {
844     0.000000,  // left edge
845     0.000000,  // top edge
846     95.934784,  // right edge
847     65.259262,  // bottom edge
848     1.000000,  // x pixels/TP width
849     1.000000,  // y pixels/TP height
850     25.400000,  // x screen DPI
851     25.400000,  // y screen DPI
852     -1,  // orientation minimum
853     2,   // orientation maximum
854     2,  // max fingers
855     5,  // max touch
856     1,  // t5r2
857     0,  // semi-mt
858     1,   // is button pad
859     0,  // has_wheel
860     0,  // wheel_is_hi_res
861     0,  // is haptic pad
862   };
863   TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops);
864 
865   // Actual data captured from Alex
866   QuickSwipeTestInputs inputs[] = {
867     // Two fingers arriving at the same time doing a swipe
868     { 6.30188, 50.34, 53.29, 22.20, 91, 33.28, 56.05, 22.20, 92 },
869     { 6.33170, 55.13, 32.40, 31.85, 91, 35.02, 42.20, 28.63, 92 },
870 
871     // Two fingers doing a swipe, but one arrives a few frames before
872     // the other
873     { 84.602478, 35.41, 65.27,  7.71, 93, -1.00, -1.00, -1.00, -1 },
874     { 84.641174, 38.17, 43.07, 31.85, 93, -1.00, -1.00, -1.00, -1 },
875     { 84.666290, 42.78, 21.66, 35.07, 93, 61.36, 31.83, 22.20, 94 },
876     { 84.690422, 50.43,  5.37, 15.75, 93, 66.93, 12.64, 28.63, 94 },
877   };
878 
879   base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
880   interpreter.reset(new LookaheadFilterInterpreter(
881       NULL, base_interpreter, NULL));
882   wrapper.Reset(interpreter.get());
883 
884   interpreter->min_delay_.val_ = 0.017;
885   interpreter->max_delay_.val_ = 0.026;
886 
887   // Prime it w/ a dummy hardware state
888   stime_t timeout = NO_DEADLINE;
889   HardwareState temp_hs = make_hwstate(0.000001, 0, 0, 0, NULL);
890   wrapper.SyncInterpret(&temp_hs, &timeout);
891   wrapper.HandleTimer(temp_hs.timestamp + timeout, NULL);
892 
893   std::set<short> input_ids;
894 
895   for (size_t i = 0; i < arraysize(inputs); i++) {
896     const QuickSwipeTestInputs& in = inputs[i];
897     FingerState fs[] = {
898       // TM, Tm, WM, Wm, pr, orient, x, y, id, flags
899       { 0, 0, 0, 0, in.pressure0, 0, in.x0, in.y0, in.id0, 0 },
900       { 0, 0, 0, 0, in.pressure1, 0, in.x1, in.y1, in.id1, 0 },
901     };
902     unsigned short finger_cnt = in.id0 < 0 ? 0 : (in.id1 < 0 ? 1 : 2);
903     HardwareState hs = make_hwstate(in.now, 0, finger_cnt, finger_cnt, fs);
904 
905     for (size_t idx = 0; idx < finger_cnt; idx++)
906       input_ids.insert(fs[idx].tracking_id);
907 
908     stime_t timeout = NO_DEADLINE;
909     wrapper.SyncInterpret(&hs, &timeout);
910     if (timeout >= 0) {
911       stime_t next_timestamp = INFINITY;
912       if (i < arraysize(inputs) - 1)
913         next_timestamp = inputs[i + 1].now;
914       stime_t now = in.now;
915       while (timeout >= 0 && (now + timeout) < next_timestamp) {
916         now += timeout;
917         timeout = NO_DEADLINE;
918         wrapper.HandleTimer(now, &timeout);
919       }
920     }
921   }
922 
923   EXPECT_EQ(input_ids.size(), base_interpreter->all_ids_.size());
924 }
925 
926 struct CyapaDrumrollTestInputs {
927   bool reset_;
928   stime_t now_;
929   float x_, y_, pressure_;
930   unsigned flags_;
931   bool jump_here_;
932 };
933 
934 // Replays a couple instances of drumroll from a Cyapa system as reported by
935 // Doug Anderson.
TEST(LookaheadFilterInterpreterTest,CyapaDrumrollTest)936 TEST(LookaheadFilterInterpreterTest, CyapaDrumrollTest) {
937   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
938   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
939 
940   HardwareProperties initial_hwprops = {
941     0.000000,  // left edge
942     0.000000,  // top edge
943     106.666672,  // right edge
944     68.000000,  // bottom edge
945     1.000000,  // x pixels/TP width
946     1.000000,  // y pixels/TP height
947     25.400000,  // x screen DPI
948     25.400000,  // y screen DPI
949     -1,  // orientation minimum
950     2,   // orientation maximum
951     15,  // max fingers
952     5,  // max touch
953     0,  // t5r2
954     0,  // semi-mt
955     0,  // is button pad
956     0,  // has_wheel
957     0,  // wheel_is_hi_res
958     0,  // is haptic pad
959   };
960   TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops);
961 
962   CyapaDrumrollTestInputs inputs[] = {
963     // First run:
964     { true,  3.39245, 67.83, 34.10,  3.71, 0, false },
965     { false, 3.40097, 67.83, 34.10, 30.88, 0, false },
966     { false, 3.40970, 67.83, 34.10, 42.52, 0, false },
967     { false, 3.44442, 67.83, 34.40, 44.46, 0, false },
968     { false, 3.45307, 67.83, 34.60, 44.46, 0, false },
969     { false, 3.46176, 67.83, 34.79, 44.46, 0, false },
970     { false, 3.47041, 68.16, 35.20, 46.40, 0, false },
971     { false, 3.47929, 68.83, 35.60, 50.28, 0, false },
972     { false, 3.48806, 69.25, 35.90, 50.28, 0, false },
973     { false, 3.49700, 69.75, 36.10, 52.22, 0, false },
974     { false, 3.50590, 70.08, 36.50, 50.28, 0, false },
975     { false, 3.51464, 70.41, 36.60, 52.22, 0, false },
976     { false, 3.52355, 70.75, 36.79, 52.22, 0, false },
977     { false, 3.53230, 71.00, 36.90, 52.22, 0, false },
978     { false, 3.54118, 71.16, 36.90, 50.28, 0, false },
979     { false, 3.55004, 71.33, 36.90, 52.22, 0, false },
980     { false, 3.55900, 71.58, 37.10, 54.16, 0, false },
981     { false, 3.56801, 71.66, 37.10, 52.22, 0, false },
982     { false, 3.57690, 71.83, 37.10, 54.16, 0, false },
983     { false, 3.59494, 71.91, 37.10, 52.22, 0, false },
984     { false, 3.63092, 72.00, 37.10, 54.16, 0, false },
985     { false, 3.68472, 72.00, 37.10, 56.10, 0, false },
986     { false, 3.70275, 72.00, 37.10, 54.16, 0, false },
987     { false, 3.71167, 72.00, 37.10, 52.22, 0, false },
988     { false, 3.72067, 72.00, 37.10, 50.28, 0, false },
989     { false, 3.72959, 72.00, 37.10, 42.52, 0, false },
990     { false, 3.73863, 72.00, 37.10, 27.00, 0, false },
991     // jump occurs here:
992     { false, 3.74794, 14.58, 67.70, 17.30, 2, true },
993     { false, 3.75703, 13.91, 66.59, 48.34, 2, false },
994     { false, 3.76619, 13.91, 66.59, 50.28, 0, false },
995     { false, 3.77531, 13.91, 66.20, 58.04, 0, false },
996     { false, 3.78440, 13.91, 66.20, 58.04, 0, false },
997     { false, 3.80272, 13.91, 66.00, 59.99, 0, false },
998     { false, 3.81203, 13.91, 66.00, 61.93, 0, false },
999     { false, 3.83017, 13.91, 66.00, 61.93, 0, false },
1000     { false, 3.83929, 13.91, 65.80, 61.93, 0, false },
1001     { false, 3.84849, 13.91, 65.70, 61.93, 0, false },
1002     { false, 3.90325, 13.91, 65.70, 59.99, 0, false },
1003     { false, 3.91247, 13.91, 65.70, 56.10, 0, false },
1004     { false, 3.92156, 13.91, 65.70, 42.52, 0, false },
1005     // Second run:
1006     { true,  39.25706, 91.08, 26.70, 25.06, 0, false },
1007     { false, 39.26551, 91.08, 26.70, 32.82, 0, false },
1008     { false, 39.27421, 89.66, 26.70, 34.76, 1, false },
1009     { false, 39.28285, 88.50, 26.70, 38.64, 1, false },
1010     { false, 39.29190, 87.75, 26.70, 42.52, 0, false },
1011     { false, 39.30075, 86.66, 26.70, 44.46, 0, false },
1012     { false, 39.30940, 85.66, 26.70, 44.46, 0, false },
1013     { false, 39.31812, 83.91, 26.70, 44.46, 0, false },
1014     { false, 39.32671, 82.25, 26.40, 48.34, 0, false },
1015     { false, 39.33564, 80.66, 26.30, 48.34, 0, false },
1016     { false, 39.34467, 79.25, 26.10, 50.28, 0, false },
1017     { false, 39.35335, 77.41, 26.00, 48.34, 0, false },
1018     { false, 39.36222, 75.50, 25.80, 52.22, 0, false },
1019     { false, 39.37135, 74.25, 25.80, 54.16, 0, false },
1020     { false, 39.38032, 73.25, 25.80, 56.10, 0, false },
1021     { false, 39.38921, 71.91, 25.80, 52.22, 0, false },
1022     { false, 39.39810, 70.25, 25.80, 56.10, 0, false },
1023     { false, 39.40708, 68.75, 25.80, 58.04, 0, false },
1024     { false, 39.41612, 67.75, 25.80, 59.99, 0, false },
1025     { false, 39.42528, 66.83, 25.70, 61.93, 0, false },
1026     { false, 39.43439, 66.25, 25.70, 58.04, 0, false },
1027     { false, 39.44308, 65.33, 25.70, 58.04, 0, false },
1028     { false, 39.45196, 64.41, 25.70, 59.99, 0, false },
1029     { false, 39.46083, 63.75, 25.70, 59.99, 0, false },
1030     { false, 39.46966, 63.25, 25.70, 61.93, 0, false },
1031     { false, 39.47855, 62.83, 25.70, 65.81, 0, false },
1032     { false, 39.48741, 62.50, 25.70, 63.87, 0, false },
1033     { false, 39.49632, 62.00, 25.70, 63.87, 0, false },
1034     { false, 39.50527, 61.66, 25.70, 61.93, 0, false },
1035     { false, 39.51422, 61.41, 25.70, 61.93, 0, false },
1036     { false, 39.52323, 61.08, 25.70, 63.87, 0, false },
1037     { false, 39.54126, 61.00, 25.70, 65.81, 0, false },
1038     { false, 39.55042, 60.83, 25.70, 65.81, 0, false },
1039     { false, 39.55951, 60.75, 25.70, 65.81, 0, false },
1040     { false, 39.56852, 60.33, 25.70, 63.87, 0, false },
1041     { false, 39.57756, 60.00, 25.70, 63.87, 0, false },
1042     { false, 39.58664, 59.58, 25.70, 63.87, 0, false },
1043     { false, 39.59553, 59.08, 25.70, 63.87, 0, false },
1044     { false, 39.60432, 58.50, 25.70, 67.75, 0, false },
1045     { false, 39.61319, 57.75, 25.70, 67.75, 0, false },
1046     { false, 39.62219, 57.33, 25.70, 67.75, 0, false },
1047     { false, 39.63088, 56.83, 25.70, 67.75, 0, false },
1048     { false, 39.63976, 56.33, 25.70, 67.75, 0, false },
1049     { false, 39.64860, 55.83, 25.70, 67.75, 0, false },
1050     { false, 39.65758, 55.33, 25.70, 65.81, 0, false },
1051     { false, 39.66647, 54.83, 25.70, 65.81, 0, false },
1052     { false, 39.67554, 54.33, 26.00, 69.69, 0, false },
1053     { false, 39.68430, 53.75, 26.10, 67.75, 0, false },
1054     { false, 39.69313, 53.33, 26.40, 67.75, 0, false },
1055     { false, 39.70200, 52.91, 26.40, 67.75, 0, false },
1056     { false, 39.71106, 52.33, 26.60, 67.75, 0, false },
1057     { false, 39.71953, 51.83, 26.80, 69.69, 0, false },
1058     { false, 39.72814, 51.41, 26.80, 71.63, 0, false },
1059     { false, 39.73681, 50.75, 26.80, 71.63, 0, false },
1060     { false, 39.74569, 50.33, 26.80, 71.63, 0, false },
1061     { false, 39.75422, 49.83, 26.80, 73.57, 0, false },
1062     { false, 39.76303, 49.33, 26.80, 75.51, 0, false },
1063     { false, 39.77166, 49.00, 26.80, 73.57, 0, false },
1064     { false, 39.78054, 48.41, 26.80, 75.51, 0, false },
1065     { false, 39.78950, 48.16, 26.80, 75.51, 0, false },
1066     { false, 39.79827, 47.83, 26.80, 75.51, 0, false },
1067     { false, 39.80708, 47.58, 26.80, 77.45, 0, false },
1068     { false, 39.81598, 47.41, 26.80, 77.45, 0, false },
1069     { false, 39.82469, 47.33, 26.80, 75.51, 0, false },
1070     { false, 39.83359, 47.25, 26.80, 75.51, 0, false },
1071     { false, 39.84252, 47.25, 26.80, 77.45, 0, false },
1072     { false, 39.87797, 47.25, 26.80, 75.51, 0, false },
1073     { false, 39.88674, 47.25, 26.80, 71.63, 0, false },
1074     { false, 39.89573, 47.25, 26.80, 67.75, 0, false },
1075     { false, 39.90444, 47.25, 26.80, 52.22, 0, false },
1076     { false, 39.91334, 47.25, 26.80, 27.00, 0, false },
1077     { false, 39.92267, 21.00, 62.29, 34.76, 1, true },
1078     { false, 39.93177, 21.00, 62.50, 46.40, 0, false },
1079     { false, 39.94127, 21.00, 62.79, 56.10, 2, false },
1080     { false, 39.95053, 21.00, 62.79, 61.93, 0, false },
1081     { false, 39.96006, 21.00, 62.79, 63.87, 0, false },
1082     { false, 39.96919, 21.00, 62.79, 65.81, 0, false },
1083     { false, 39.97865, 21.00, 62.79, 67.75, 0, false },
1084     { false, 39.99727, 21.00, 62.79, 67.75, 0, false },
1085     { false, 40.00660, 21.00, 62.79, 67.75, 0, false },
1086     { false, 40.02541, 21.00, 62.60, 67.75, 0, false },
1087     { false, 40.04417, 21.00, 62.60, 65.81, 0, false },
1088     { false, 40.05345, 21.00, 62.60, 63.87, 0, false },
1089     { false, 40.06241, 21.00, 62.60, 58.04, 0, false },
1090     { false, 40.07105, 21.00, 60.90, 34.76, 2, false },
1091     { false, 40.07990, 21.16, 59.10,  5.65, 2, false },
1092   };
1093 
1094   for (size_t i = 0; i < arraysize(inputs); i++) {
1095     const CyapaDrumrollTestInputs& input = inputs[i];
1096     FingerState fs = {
1097       // TM, Tm, WM, Wm, pr, orient, x, y, id, flags
1098       0, 0, 0, 0, input.pressure_, 0, input.x_, input.y_, 1, input.flags_
1099     };
1100     HardwareState hs = make_hwstate(input.now_, 0, 1, 1, &fs);
1101     if (input.reset_) {
1102       if (base_interpreter) {
1103         EXPECT_TRUE(base_interpreter->expected_flags_at_occurred_);
1104       }
1105       base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
1106       base_interpreter->expected_id_ = 1;
1107       interpreter.reset(new LookaheadFilterInterpreter(
1108           NULL, base_interpreter, NULL));
1109       wrapper.Reset(interpreter.get());
1110     }
1111     if (input.jump_here_) {
1112       base_interpreter->expected_flags_ =
1113           GESTURES_FINGER_WARP_X | GESTURES_FINGER_WARP_Y;
1114       base_interpreter->expected_flags_at_ = input.now_;
1115     }
1116     stime_t timeout = NO_DEADLINE;
1117     wrapper.SyncInterpret(&hs, &timeout);
1118     if (timeout >= 0) {
1119       stime_t next_timestamp = INFINITY;
1120       if (i < arraysize(inputs) - 1)
1121         next_timestamp = inputs[i + 1].now_;
1122       stime_t now = input.now_;
1123       while (timeout >= 0 && (now + timeout) < next_timestamp) {
1124         now += timeout;
1125         timeout = NO_DEADLINE;
1126         wrapper.HandleTimer(now, &timeout);
1127       }
1128     }
1129   }
1130   ASSERT_TRUE(base_interpreter);
1131   EXPECT_TRUE(base_interpreter->expected_flags_at_occurred_);
1132 }
1133 
1134 struct CyapaQuickTwoFingerMoveTestInputs {
1135   stime_t now;
1136   float x0, y0, pressure0;
1137   float x1, y1, pressure1;
1138   float x2, y2, pressure2;
1139 };
1140 
1141 // Using data from a real log, tests that when we do a swipe with large delay
1142 // on Lumpy, we don't reassign finger IDs b/c we use sufficient temporary
1143 // delay.
TEST(LookaheadFilterInterpreterTest,CyapaQuickTwoFingerMoveTest)1144 TEST(LookaheadFilterInterpreterTest, CyapaQuickTwoFingerMoveTest) {
1145   LookaheadFilterInterpreterTestInterpreter* base_interpreter =
1146       new LookaheadFilterInterpreterTestInterpreter;
1147   LookaheadFilterInterpreter interpreter(NULL, base_interpreter, NULL);
1148   interpreter.min_delay_.val_ = 0.0;
1149 
1150   HardwareProperties initial_hwprops = {
1151     0.000000,  // left edge
1152     0.000000,  // top edge
1153     106.666672,  // right edge
1154     68.000000,  // bottom edge
1155     1.000000,  // x pixels/TP width
1156     1.000000,  // y pixels/TP height
1157     25.400000,  // x screen DPI
1158     25.400000,  // y screen DPI
1159     -1,  // orientation minimum
1160     2,   // orientation maximum
1161     15,  // max fingers
1162     5,  // max touch
1163     0,  // t5r2
1164     0,  // semi-mt
1165     0,  // is button pad
1166     0,  // has_wheel
1167     0,  // wheel_is_hi_res
1168     0,  // is haptic pad
1169   };
1170   TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops);
1171 
1172   CyapaQuickTwoFingerMoveTestInputs inputs[] = {
1173     { 1.13156, 38.16,  8.10, 52.2, 57.41,  6.40, 40.5, 75.66,  6.50, 36.7 },
1174     { 1.14369, 37.91, 17.50, 50.2, 56.83, 15.50, 40.5, 75.25, 15.30, 32.8 },
1175     { 1.15980, 34.66, 31.60, 48.3, 53.58, 29.40, 40.5, 72.25, 29.10, 28.9 }
1176   };
1177   // Prime it w/ a dummy hardware state
1178   stime_t timeout = NO_DEADLINE;
1179   HardwareState temp_hs = make_hwstate(0.000001, 0, 0, 0, NULL);
1180   interpreter.SyncInterpret(&temp_hs, &timeout);
1181 
1182   base_interpreter->expected_ids_.insert(1);
1183   base_interpreter->expected_ids_.insert(2);
1184   base_interpreter->expected_ids_.insert(3);
1185   for (size_t i = 0; i < arraysize(inputs); i++) {
1186     const CyapaQuickTwoFingerMoveTestInputs& input = inputs[i];
1187     FingerState fs[] = {
1188       { 0, 0, 0, 0, input.pressure0, 0, input.x0, input.y0, 1, 0 },
1189       { 0, 0, 0, 0, input.pressure1, 0, input.x1, input.y1, 2, 0 },
1190       { 0, 0, 0, 0, input.pressure2, 0, input.x2, input.y2, 3, 0 }
1191     };
1192     HardwareState hs =
1193         make_hwstate(input.now, 0, arraysize(fs), arraysize(fs), fs);
1194     timeout = NO_DEADLINE;
1195     interpreter.SyncInterpret(&hs, &timeout);
1196     if (timeout >= 0) {
1197       stime_t next_timestamp = INFINITY;
1198       if (i < arraysize(inputs) - 1)
1199         next_timestamp = inputs[i + 1].now;
1200       stime_t now = input.now;
1201       while (timeout >= 0 && (now + timeout) < next_timestamp) {
1202         now += timeout;
1203         timeout = NO_DEADLINE;
1204         fprintf(stderr, "calling handler timer: %f\n", now);
1205         interpreter.HandleTimer(now, &timeout);
1206       }
1207     }
1208   }
1209 }
1210 
TEST(LookaheadFilterInterpreterTest,SemiMtNoTrackingIdAssignmentTest)1211 TEST(LookaheadFilterInterpreterTest, SemiMtNoTrackingIdAssignmentTest) {
1212   LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
1213   std::unique_ptr<LookaheadFilterInterpreter> interpreter;
1214 
1215   HardwareProperties hwprops = {
1216     0, 0, 100, 100,  // left, top, right, bottom
1217     1,  // x res (pixels/mm)
1218     1,  // y res (pixels/mm)
1219     25, 25,  // scrn DPI X, Y
1220     -1,  // orientation minimum
1221     2,   // orientation maximum
1222     2, 5,  // max fingers, max_touch
1223     1, 1, 0,  // t5r2, semi, button pad
1224     0, 0,  // has wheel, vertical wheel is high resolution
1225     0,  // haptic pad
1226   };
1227   TestInterpreterWrapper wrapper(interpreter.get(), &hwprops);
1228 
1229   FingerState fs[] = {
1230     // TM, Tm, WM, Wm, pr, orient, x, y, id
1231     { 0, 0, 0, 0, 5, 0, 76, 45, 20, 0},  // 0
1232 
1233     { 0, 0, 0, 0, 62, 0, 56, 43, 20, 0},  // 1
1234     { 0, 0, 0, 0, 62, 0, 76, 41, 21, 0},
1235 
1236     { 0, 0, 0, 0, 76, 0, 56, 38, 20, 0},  // 3
1237     { 0, 0, 0, 0, 76, 0, 75, 35, 21, 0},
1238 
1239     { 0, 0, 0, 0, 78, 0, 56, 31, 20, 0},  // 5
1240     { 0, 0, 0, 0, 78, 0, 75, 27, 21, 0},
1241 
1242     { 0, 0, 0, 0, 78, 0, 56, 22, 20, 0},  // 7
1243     { 0, 0, 0, 0, 78, 0, 75, 18, 21, 0},
1244 
1245     // It will trigger the tracking id assignment for a quick move on a
1246     // non-semi-mt device.
1247     { 0, 0, 0, 0, 78, 0, 56, 13, 20, 0},  // 9
1248     { 0, 0, 0, 0, 78, 0, 75, 8, 21, 0}
1249   };
1250 
1251   HardwareState hs[] = {
1252     make_hwstate(328.989039, 0, 1, 1, &fs[0]),
1253     make_hwstate(329.013853, 0, 2, 2, &fs[1]),
1254     make_hwstate(329.036266, 0, 2, 2, &fs[3]),
1255     make_hwstate(329.061772, 0, 2, 2, &fs[5]),
1256     make_hwstate(329.086734, 0, 2, 2, &fs[7]),
1257     make_hwstate(329.110350, 0, 2, 2, &fs[9]),
1258   };
1259 
1260   base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
1261   interpreter.reset(new LookaheadFilterInterpreter(
1262       NULL, base_interpreter, NULL));
1263   wrapper.Reset(interpreter.get());
1264 
1265   stime_t timeout = NO_DEADLINE;
1266   const auto& queue = interpreter->queue_;
1267 
1268   wrapper.SyncInterpret(&hs[0], &timeout);
1269   EXPECT_EQ(queue.back().fs_[0].tracking_id, 20);
1270 
1271   // Test if the fingers in queue have the same tracking ids from input.
1272   for (size_t i = 1; i < arraysize(hs); i++) {
1273     wrapper.SyncInterpret(&hs[i], &timeout);
1274     EXPECT_EQ(queue.back().fs_[0].tracking_id, 20);  // the same input id
1275     EXPECT_EQ(queue.back().fs_[1].tracking_id, 21);
1276   }
1277 }
1278 
1279 }  // namespace gestures
1280