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