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