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