on 6ca9421 help sign in
unity8/tests/libs/UbuntuGestures/tst_TouchRegistry.cpp
915 lines 35 kB history raw
1/*
2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17#include <QtTest>
18#include <QSet>
19#include <QTouchEvent>
21#include <Timer.h>
22#include <TouchOwnershipEvent.h>
23#include <TouchRegistry.h>
24#include <UnownedTouchEvent.h>
26using namespace UbuntuGestures;
28class TouchMemento {
29public:
30 TouchMemento(const QTouchEvent *touchEvent);
31 Qt::TouchPointStates touchPointStates;
32 QList<QTouchEvent::TouchPoint> touchPoints;
34 bool containsTouchWithId(int touchId) const;
35};
37class DummyCandidate : public QQuickItem
39 Q_OBJECT
40public:
41 bool event(QEvent *e) override;
42 QSet<int> ownedTouches;
43 QSet<int> lostTouches;
44 QList<TouchMemento> unownedTouchEvents;
45};
47class tst_TouchRegistry : public QObject
49 Q_OBJECT
50public:
51 tst_TouchRegistry() : QObject(0) { }
52private Q_SLOTS:
53 void initTestCase() {} // will be called before the first test function is executed
54 void cleanupTestCase() {} // will be called after the last test function was executed.
56 void init(); // called right before each and every test function is executed
57 void cleanup(); // called right after each and every test function is executed
59 void requestWithNoCandidates();
60 void lateCandidateRequestGetsNothing();
61 void lateCandidateGestOwnershipOnceEarlyCandidateQuits();
62 void dispatchesTouchEventsToCandidates();
63 void dispatchesTouchEventsToWatchers();
64 void keepDispatchingToWatchersAfterLastCandidateGivesUp();
65 void candidatesAndWatchers_1();
66 void candidatesAndWatchers_2();
67 void rejectingTouchfterItsEnd();
68 void removeOldUndecidedCandidates();
69 void interimOwnerWontGetUnownedTouchEvents();
70 void candidateVanishes();
72private:
73 TouchRegistry *touchRegistry;
74};
76void tst_TouchRegistry::init()
78 touchRegistry = TouchRegistry::instance();
81void tst_TouchRegistry::cleanup()
83 delete touchRegistry;
86void tst_TouchRegistry::requestWithNoCandidates()
88 DummyCandidate candidate;
90 {
91 QList<QTouchEvent::TouchPoint> touchPoints;
92 touchPoints.append(QTouchEvent::TouchPoint(0));
93 touchPoints[0].setState(Qt::TouchPointPressed);
94 QTouchEvent touchEvent(QEvent::TouchBegin,
95 0 /* device */,
96 Qt::NoModifier,
97 Qt::TouchPointPressed,
98 touchPoints);
99 touchRegistry->update(&touchEvent);
100 }
102 touchRegistry->requestTouchOwnership(0, &candidate);
104 QVERIFY(candidate.ownedTouches.contains(0));
107void tst_TouchRegistry::lateCandidateRequestGetsNothing()
109 DummyCandidate earlyCandidate;
110 earlyCandidate.setObjectName("early");
111 DummyCandidate lateCandidate;
112 lateCandidate.setObjectName("late");
114 {
115 QList<QTouchEvent::TouchPoint> touchPoints;
116 touchPoints.append(QTouchEvent::TouchPoint(0));
117 touchPoints[0].setState(Qt::TouchPointPressed);
118 QTouchEvent touchEvent(QEvent::TouchBegin,
119 0 /* device */,
120 Qt::NoModifier,
121 Qt::TouchPointPressed,
122 touchPoints);
123 touchRegistry->update(&touchEvent);
124 }
126 touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
127 touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
129 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
130 QVERIFY(lateCandidate.ownedTouches.isEmpty());
132 touchRegistry->requestTouchOwnership(0, &lateCandidate);
134 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
135 QVERIFY(lateCandidate.ownedTouches.isEmpty());
137 touchRegistry->requestTouchOwnership(0, &earlyCandidate);
139 QVERIFY(earlyCandidate.ownedTouches.contains(0));
140 QVERIFY(lateCandidate.ownedTouches.isEmpty());
143void tst_TouchRegistry::lateCandidateGestOwnershipOnceEarlyCandidateQuits()
145 DummyCandidate earlyCandidate;
146 DummyCandidate lateCandidate;
148 {
149 QList<QTouchEvent::TouchPoint> touchPoints;
150 touchPoints.append(QTouchEvent::TouchPoint(0));
151 touchPoints[0].setState(Qt::TouchPointPressed);
152 QTouchEvent touchEvent(QEvent::TouchBegin,
153 0 /* device */,
154 Qt::NoModifier,
155 Qt::TouchPointPressed,
156 touchPoints);
157 touchRegistry->update(&touchEvent);
158 }
160 touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
161 touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
163 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
164 QVERIFY(lateCandidate.ownedTouches.isEmpty());
166 touchRegistry->requestTouchOwnership(0, &lateCandidate);
168 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
169 QVERIFY(lateCandidate.ownedTouches.isEmpty());
171 touchRegistry->removeCandidateOwnerForTouch(0, &earlyCandidate);
173 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
174 QVERIFY(lateCandidate.ownedTouches.contains(0));
177void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
179 QQuickItem rootItem;
181 DummyCandidate candidate0;
182 candidate0.setObjectName("0");
183 candidate0.setParentItem(&rootItem);
184 candidate0.setX(1);
185 candidate0.setY(2);
187 DummyCandidate candidate1;
188 candidate1.setObjectName("1");
189 candidate0.setParentItem(&rootItem);
190 candidate1.setX(3);
191 candidate1.setY(4);
193 {
194 QList<QTouchEvent::TouchPoint> touchPoints;
195 touchPoints.append(QTouchEvent::TouchPoint(0));
196 touchPoints[0].setState(Qt::TouchPointPressed);
197 touchPoints[0].setRect(QRect(10, 10, 0, 0));
198 QTouchEvent touchEvent(QEvent::TouchBegin,
199 0 /* device */,
200 Qt::NoModifier,
201 Qt::TouchPointPressed,
202 touchPoints);
203 touchRegistry->update(&touchEvent);
204 }
206 touchRegistry->addCandidateOwnerForTouch(0, &candidate0);
208 {
209 QList<QTouchEvent::TouchPoint> touchPoints;
210 touchPoints.append(QTouchEvent::TouchPoint(0));
211 touchPoints[0].setState(Qt::TouchPointMoved);
212 touchPoints[0].setRect(QRect(11, 11, 0, 0));
213 touchPoints.append(QTouchEvent::TouchPoint(1));
214 touchPoints[1].setState(Qt::TouchPointPressed);
215 touchPoints[1].setRect(QRect(20, 20, 0, 0));
216 QTouchEvent touchEvent(QEvent::TouchUpdate,
217 0 /* device */,
218 Qt::NoModifier,
219 Qt::TouchPointPressed | Qt::TouchPointMoved,
220 touchPoints);
221 touchRegistry->update(&touchEvent);
222 }
224 // candidate0 should have received an update on the touch he's interested on.
225 QCOMPARE(candidate0.unownedTouchEvents.count(), 1);
226 // make sure only touch 0 is there (i.e. no mention of touch 1)
227 QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints.count(), 1);
228 QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].id(), 0);
229 // Check that the points local coordinates have been mapped to candidate0's coordinate system.
230 QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().x(), 11 - candidate0.x());
231 QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().y(), 11 - candidate0.y());
233 touchRegistry->addCandidateOwnerForTouch(1, &candidate1);
235 {
236 QList<QTouchEvent::TouchPoint> touchPoints;
237 touchPoints.append(QTouchEvent::TouchPoint(0));
238 touchPoints[0].setState(Qt::TouchPointMoved);
239 touchPoints[0].setRect(QRect(12, 12, 0, 0));
240 touchPoints.append(QTouchEvent::TouchPoint(1));
241 touchPoints[1].setState(Qt::TouchPointMoved);
242 touchPoints[1].setRect(QRect(21, 21, 0, 0));
243 QTouchEvent touchEvent(QEvent::TouchUpdate,
244 0 /* device */,
245 Qt::NoModifier,
246 Qt::TouchPointPressed | Qt::TouchPointMoved,
247 touchPoints);
248 touchRegistry->update(&touchEvent);
249 }
251 // candidate0 gets updates only for touch 0 and
252 // candidate1 gets updates only for touch 1
254 QCOMPARE(candidate0.unownedTouchEvents.count(), 2);
255 QCOMPARE(candidate0.unownedTouchEvents[1].touchPoints.count(), 1);
256 QCOMPARE(candidate0.unownedTouchEvents[1].touchPoints[0].id(), 0);
258 QCOMPARE(candidate1.unownedTouchEvents.count(), 1);
259 QCOMPARE(candidate1.unownedTouchEvents[0].touchPoints.count(), 1);
260 QCOMPARE(candidate1.unownedTouchEvents[0].touchPoints[0].id(), 1);
263void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
265 QQuickItem rootItem;
267 DummyCandidate watcher;
268 watcher.setObjectName("watcher");
269 watcher.setParentItem(&rootItem);
270 watcher.setX(1);
271 watcher.setY(2);
273 {
274 QList<QTouchEvent::TouchPoint> touchPoints;
275 touchPoints.append(QTouchEvent::TouchPoint(0));
276 touchPoints[0].setState(Qt::TouchPointPressed);
277 touchPoints[0].setRect(QRect(10, 10, 0, 0));
278 QTouchEvent touchEvent(QEvent::TouchBegin,
279 0 /* device */,
280 Qt::NoModifier,
281 Qt::TouchPointPressed,
282 touchPoints);
283 touchRegistry->update(&touchEvent);
284 }
286 touchRegistry->addTouchWatcher(0, &watcher);
288 {
289 QList<QTouchEvent::TouchPoint> touchPoints;
290 touchPoints.append(QTouchEvent::TouchPoint(0));
291 touchPoints[0].setState(Qt::TouchPointMoved);
292 touchPoints[0].setRect(QRect(11, 11, 0, 0));
293 touchPoints.append(QTouchEvent::TouchPoint(1));
294 touchPoints[1].setState(Qt::TouchPointPressed);
295 touchPoints[1].setRect(QRect(20, 20, 0, 0));
296 QTouchEvent touchEvent(QEvent::TouchUpdate,
297 0 /* device */,
298 Qt::NoModifier,
299 Qt::TouchPointPressed | Qt::TouchPointMoved,
300 touchPoints);
301 touchRegistry->update(&touchEvent);
302 }
304 // watcher should have received an update on the touch he's interested on.
305 QCOMPARE(watcher.unownedTouchEvents.count(), 1);
306 // make sure only touch 0 is there (i.e. no mention of touch 1)
307 QCOMPARE(watcher.unownedTouchEvents[0].touchPoints.count(), 1);
308 QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].id(), 0);
309 // Check that the points local coordinates have been mapped to watcher's coordinate system.
310 QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].rect().x(), 11 - watcher.x());
311 QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].rect().y(), 11 - watcher.y());
313 {
314 QList<QTouchEvent::TouchPoint> touchPoints;
315 touchPoints.append(QTouchEvent::TouchPoint(0));
316 touchPoints[0].setState(Qt::TouchPointMoved);
317 touchPoints[0].setRect(QRect(12, 12, 0, 0));
318 touchPoints.append(QTouchEvent::TouchPoint(1));
319 touchPoints[1].setState(Qt::TouchPointMoved);
320 touchPoints[1].setRect(QRect(21, 21, 0, 0));
321 QTouchEvent touchEvent(QEvent::TouchUpdate,
322 0 /* device */,
323 Qt::NoModifier,
324 Qt::TouchPointPressed | Qt::TouchPointMoved,
325 touchPoints);
326 touchRegistry->update(&touchEvent);
327 }
329 // watcher gets updates only for touch 0
331 QCOMPARE(watcher.unownedTouchEvents.count(), 2);
332 QCOMPARE(watcher.unownedTouchEvents[1].touchPoints.count(), 1);
333 QCOMPARE(watcher.unownedTouchEvents[1].touchPoints[0].id(), 0);
336void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
338 DummyCandidate item;
340 {
341 QList<QTouchEvent::TouchPoint> touchPoints;
342 touchPoints.append(QTouchEvent::TouchPoint(0));
343 touchPoints[0].setState(Qt::TouchPointPressed);
344 QTouchEvent touchEvent(QEvent::TouchBegin,
345 0 /* device */,
346 Qt::NoModifier,
347 Qt::TouchPointPressed,
348 touchPoints);
349 touchRegistry->update(&touchEvent);
350 }
352 touchRegistry->addCandidateOwnerForTouch(0, &item);
354 {
355 QList<QTouchEvent::TouchPoint> touchPoints;
356 touchPoints.append(QTouchEvent::TouchPoint(0));
357 touchPoints[0].setState(Qt::TouchPointMoved);
358 touchPoints.append(QTouchEvent::TouchPoint(1));
359 touchPoints[1].setState(Qt::TouchPointPressed);
360 QTouchEvent touchEvent(QEvent::TouchUpdate,
361 0 /* device */,
362 Qt::NoModifier,
363 Qt::TouchPointPressed | Qt::TouchPointMoved,
364 touchPoints);
365 touchRegistry->update(&touchEvent);
366 }
368 QCOMPARE(item.unownedTouchEvents.count(), 1);
369 QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 1);
370 QCOMPARE(item.unownedTouchEvents[0].touchPoints[0].id(), 0);
371 item.unownedTouchEvents.clear();
373 touchRegistry->addTouchWatcher(1, &item);
375 {
376 QList<QTouchEvent::TouchPoint> touchPoints;
377 touchPoints.append(QTouchEvent::TouchPoint(0));
378 touchPoints[0].setState(Qt::TouchPointMoved);
379 touchPoints.append(QTouchEvent::TouchPoint(1));
380 touchPoints[1].setState(Qt::TouchPointMoved);
381 QTouchEvent touchEvent(QEvent::TouchUpdate,
382 0 /* device */,
383 Qt::NoModifier,
384 Qt::TouchPointMoved,
385 touchPoints);
386 touchRegistry->update(&touchEvent);
387 }
389 QCOMPARE(item.unownedTouchEvents.count(), 1);
390 QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 2);
391 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(0));
392 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
393 item.unownedTouchEvents.clear();
395 {
396 QList<QTouchEvent::TouchPoint> touchPoints;
397 touchPoints.append(QTouchEvent::TouchPoint(0));
398 touchPoints[0].setState(Qt::TouchPointReleased);
399 touchPoints.append(QTouchEvent::TouchPoint(1));
400 touchPoints[1].setState(Qt::TouchPointMoved);
401 QTouchEvent touchEvent(QEvent::TouchUpdate,
402 0 /* device */,
403 Qt::NoModifier,
404 Qt::TouchPointReleased | Qt::TouchPointMoved,
405 touchPoints);
406 touchRegistry->update(&touchEvent);
407 }
409 QCOMPARE(item.unownedTouchEvents.count(), 1);
410 QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 2);
411 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(0));
412 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
413 item.unownedTouchEvents.clear();
415 touchRegistry->removeCandidateOwnerForTouch(0, &item);
417 {
418 QList<QTouchEvent::TouchPoint> touchPoints;
419 touchPoints.append(QTouchEvent::TouchPoint(1));
420 touchPoints[0].setState(Qt::TouchPointReleased);
421 QTouchEvent touchEvent(QEvent::TouchEnd,
422 0 /* device */,
423 Qt::NoModifier,
424 Qt::TouchPointReleased,
425 touchPoints);
426 touchRegistry->update(&touchEvent);
427 }
429 QCOMPARE(item.unownedTouchEvents.count(), 1);
430 QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 1);
431 QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
432 item.unownedTouchEvents.clear();
434 QVERIFY(touchRegistry->m_touchInfoPool.isEmpty());
437/*
438 Regression test that reproduces a problematic scenario that came up during manual testing.
439 It reproduces the interaction between TouchRegistry and a DirectionalDragArea
440 */
441void tst_TouchRegistry::candidatesAndWatchers_1()
443 DummyCandidate item;
445 {
446 QList<QTouchEvent::TouchPoint> touchPoints;
447 touchPoints.append(QTouchEvent::TouchPoint(0));
448 touchPoints[0].setState(Qt::TouchPointPressed);
449 QTouchEvent touchEvent(QEvent::TouchBegin,
450 0 /* device */,
451 Qt::NoModifier,
452 Qt::TouchPointPressed,
453 touchPoints);
454 touchRegistry->update(&touchEvent);
455 }
457 touchRegistry->addCandidateOwnerForTouch(0, &item);
459 {
460 QList<QTouchEvent::TouchPoint> touchPoints;
461 touchPoints.append(QTouchEvent::TouchPoint(0));
462 touchPoints[0].setState(Qt::TouchPointMoved);
463 touchPoints.append(QTouchEvent::TouchPoint(1));
464 touchPoints[1].setState(Qt::TouchPointPressed);
465 QTouchEvent touchEvent(QEvent::TouchUpdate,
466 0 /* device */,
467 Qt::NoModifier,
468 Qt::TouchPointPressed | Qt::TouchPointMoved,
469 touchPoints);
470 touchRegistry->update(&touchEvent);
471 }
473 touchRegistry->addTouchWatcher(1, &item);
475 touchRegistry->removeCandidateOwnerForTouch(0, &item);
477 touchRegistry->addTouchWatcher(0, &item);
479 {
480 QList<QTouchEvent::TouchPoint> touchPoints;
481 touchPoints.append(QTouchEvent::TouchPoint(0));
482 touchPoints[0].setState(Qt::TouchPointReleased);
483 touchPoints.append(QTouchEvent::TouchPoint(1));
484 touchPoints[1].setState(Qt::TouchPointMoved);
485 QTouchEvent touchEvent(QEvent::TouchUpdate,
486 0 /* device */,
487 Qt::NoModifier,
488 Qt::TouchPointReleased | Qt::TouchPointMoved,
489 touchPoints);
490 touchRegistry->update(&touchEvent);
491 }
493 {
494 QList<QTouchEvent::TouchPoint> touchPoints;
495 touchPoints.append(QTouchEvent::TouchPoint(1));
496 touchPoints[0].setState(Qt::TouchPointReleased);
497 QTouchEvent touchEvent(QEvent::TouchEnd,
498 0 /* device */,
499 Qt::NoModifier,
500 Qt::TouchPointReleased,
501 touchPoints);
502 touchRegistry->update(&touchEvent);
503 }
505 QVERIFY(touchRegistry->m_touchInfoPool.isEmpty());
507 item.unownedTouchEvents.clear();
509 {
510 QList<QTouchEvent::TouchPoint> touchPoints;
511 touchPoints.append(QTouchEvent::TouchPoint(0));
512 touchPoints[0].setState(Qt::TouchPointPressed);
513 QTouchEvent touchEvent(QEvent::TouchBegin,
514 0 /* device */,
515 Qt::NoModifier,
516 Qt::TouchPointPressed,
517 touchPoints);
518 touchRegistry->update(&touchEvent);
519 }
521 // Haven't made any subscription for that new touch 0.
522 QCOMPARE(item.unownedTouchEvents.count(), 0);
525/*
526 Regression test that reproduces a problematic scenario that came up during manual testing.
527 It reproduces the interaction between TouchRegistry, DirectionalDragArea and a TouchGate.
528 */
529void tst_TouchRegistry::candidatesAndWatchers_2()
531 DummyCandidate directionalDragArea;
532 directionalDragArea.setObjectName("DirectionalDragArea");
534 DummyCandidate touchGate;
535 touchGate.setObjectName("TouchGate");
537 // [DDA] 1298 TouchBegin (id:0, state:pressed, scenePos:(147,1023))
538 {
539 QList<QTouchEvent::TouchPoint> touchPoints;
540 touchPoints.append(QTouchEvent::TouchPoint(0));
541 touchPoints[0].setState(Qt::TouchPointPressed);
542 QTouchEvent touchEvent(QEvent::TouchBegin,
543 0 /* device */,
544 Qt::NoModifier,
545 Qt::TouchPointPressed,
546 touchPoints);
547 touchRegistry->update(&touchEvent);
548 }
550 // [TouchRegistry] addCandidateOwnerForTouch id 0 candidate DirectionalDragArea
551 touchRegistry->addCandidateOwnerForTouch(0, &directionalDragArea);
553 // [TouchRegistry] requestTouchOwnership id 0 candidate TouchGate
554 touchRegistry->requestTouchOwnership(0, &touchGate);
556 //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(147,1023)) (id:1, state:pressed, scenePos:(327,792))
557 {
558 QList<QTouchEvent::TouchPoint> touchPoints;
559 touchPoints.append(QTouchEvent::TouchPoint(0));
560 touchPoints[0].setState(Qt::TouchPointMoved);
561 touchPoints.append(QTouchEvent::TouchPoint(1));
562 touchPoints[1].setState(Qt::TouchPointPressed);
563 QTouchEvent touchEvent(QEvent::TouchUpdate,
564 0 /* device */,
565 Qt::NoModifier,
566 Qt::TouchPointPressed | Qt::TouchPointMoved,
567 touchPoints);
568 touchRegistry->update(&touchEvent);
569 }
571 // [TouchRegistry] addTouchWatcher id 1 watcher DirectionalDragArea
572 touchRegistry->addTouchWatcher(1, &directionalDragArea);
574 // [TouchRegistry] removeCandidateOwnerForTouch id 0 candidate DirectionalDragArea
575 touchRegistry->removeCandidateOwnerForTouch(0, &directionalDragArea);
577 //[TouchRegistry] sending TouchWonershipEvent(id = 0 gained) to candidate TouchGate
578 QCOMPARE(touchGate.ownedTouches.count(), 1);
579 QVERIFY(touchGate.ownedTouches.contains(0));
581 // [TouchRegistry] addTouchWatcher id 0 watcher DirectionalDragArea
582 touchRegistry->addTouchWatcher(0, &directionalDragArea);
584 // [TouchRegistry] requestTouchOwnership id 1 candidate TouchGate
585 touchRegistry->requestTouchOwnership(1, &touchGate);
587 //[TouchRegistry] sending TouchWonershipEvent(id = 1 gained) to candidate TouchGate
588 QCOMPARE(touchGate.ownedTouches.count(), 2);
589 QVERIFY(touchGate.ownedTouches.contains(1));
591 directionalDragArea.unownedTouchEvents.clear();
592 touchGate.unownedTouchEvents.clear();
594 //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(148,1025)) (id:1, state:moved, scenePos:(329,795))
595 {
596 QList<QTouchEvent::TouchPoint> touchPoints;
597 touchPoints.append(QTouchEvent::TouchPoint(0));
598 touchPoints[0].setState(Qt::TouchPointMoved);
599 touchPoints.append(QTouchEvent::TouchPoint(1));
600 touchPoints[1].setState(Qt::TouchPointMoved);
601 QTouchEvent touchEvent(QEvent::TouchUpdate,
602 0 /* device */,
603 Qt::NoModifier,
604 Qt::TouchPointMoved,
605 touchPoints);
606 touchRegistry->update(&touchEvent);
607 }
609 //vvvvv DDA Watchers are being ignored from now on vvvvvvv
611 QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
612 QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 2);
613 QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
614 QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(1));
616 QVERIFY(touchGate.unownedTouchEvents.isEmpty());
618 directionalDragArea.unownedTouchEvents.clear();
620 //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(151,1029)) (id:1, state:released, scenePos:(329,795))
621 {
622 QList<QTouchEvent::TouchPoint> touchPoints;
623 touchPoints.append(QTouchEvent::TouchPoint(0));
624 touchPoints[0].setState(Qt::TouchPointMoved);
625 touchPoints.append(QTouchEvent::TouchPoint(1));
626 touchPoints[1].setState(Qt::TouchPointReleased);
627 QTouchEvent touchEvent(QEvent::TouchUpdate,
628 0 /* device */,
629 Qt::NoModifier,
630 Qt::TouchPointMoved | Qt::TouchPointReleased,
631 touchPoints);
632 touchRegistry->update(&touchEvent);
633 }
635 QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
636 QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 2);
637 QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
638 QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(1));
640 QVERIFY(touchGate.unownedTouchEvents.isEmpty());
642 directionalDragArea.unownedTouchEvents.clear();
644 //[TouchRegistry] got TouchEnd (id:0, state:released, scenePos:(157,1034))
645 {
646 QList<QTouchEvent::TouchPoint> touchPoints;
647 touchPoints.append(QTouchEvent::TouchPoint(0));
648 touchPoints[0].setState(Qt::TouchPointReleased);
649 QTouchEvent touchEvent(QEvent::TouchEnd,
650 0 /* device */,
651 Qt::NoModifier,
652 Qt::TouchPointReleased,
653 touchPoints);
654 touchRegistry->update(&touchEvent);
655 }
657 QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
658 QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 1);
659 QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
661 QVERIFY(touchGate.unownedTouchEvents.isEmpty());
664void tst_TouchRegistry::rejectingTouchfterItsEnd()
666 DummyCandidate earlyCandidate;
667 DummyCandidate lateCandidate;
669 {
670 QList<QTouchEvent::TouchPoint> touchPoints;
671 touchPoints.append(QTouchEvent::TouchPoint(0));
672 touchPoints[0].setState(Qt::TouchPointPressed);
673 QTouchEvent touchEvent(QEvent::TouchBegin,
674 0 /* device */,
675 Qt::NoModifier,
676 Qt::TouchPointPressed,
677 touchPoints);
678 touchRegistry->update(&touchEvent);
679 }
681 touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
682 touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
684 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
685 QVERIFY(lateCandidate.ownedTouches.isEmpty());
687 touchRegistry->requestTouchOwnership(0, &lateCandidate);
689 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
690 QVERIFY(lateCandidate.ownedTouches.isEmpty());
692 {
693 QList<QTouchEvent::TouchPoint> touchPoints;
694 touchPoints.append(QTouchEvent::TouchPoint(0));
695 touchPoints[0].setState(Qt::TouchPointReleased);
696 QTouchEvent touchEvent(QEvent::TouchEnd,
697 0 /* device */,
698 Qt::NoModifier,
699 Qt::TouchPointPressed,
700 touchPoints);
701 touchRegistry->update(&touchEvent);
702 }
704 QVERIFY(earlyCandidate.ownedTouches.isEmpty());
705 QVERIFY(lateCandidate.ownedTouches.isEmpty());
707 touchRegistry->removeCandidateOwnerForTouch(0, &earlyCandidate);
709 QCOMPARE(lateCandidate.ownedTouches.count(), 1);
710 QCOMPARE(lateCandidate.ownedTouches.contains(0), 1);
712 // Check that there's no trace left of touch 0 as we no longer need to keep tabs on it.
713 QVERIFY(!touchRegistry->findTouchInfo(0));
716void tst_TouchRegistry::removeOldUndecidedCandidates()
718 FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
719 touchRegistry->setTimerFactory(fakeTimerFactory);
721 DummyCandidate undecidedCandidate;
722 undecidedCandidate.setObjectName("undecided");
724 DummyCandidate candidateThatWantsTouch;
725 candidateThatWantsTouch.setObjectName("wantsTouch");
727 {
728 QList<QTouchEvent::TouchPoint> touchPoints;
729 touchPoints.append(QTouchEvent::TouchPoint(0));
730 touchPoints[0].setState(Qt::TouchPointPressed);
731 QTouchEvent touchEvent(QEvent::TouchBegin,
732 0 /* device */,
733 Qt::NoModifier,
734 Qt::TouchPointPressed,
735 touchPoints);
736 touchRegistry->update(&touchEvent);
737 }
739 touchRegistry->addCandidateOwnerForTouch(0, &undecidedCandidate);
741 touchRegistry->requestTouchOwnership(0, &candidateThatWantsTouch);
743 QVERIFY(undecidedCandidate.ownedTouches.isEmpty());
744 QVERIFY(undecidedCandidate.lostTouches.isEmpty());
745 QVERIFY(candidateThatWantsTouch.ownedTouches.isEmpty());
746 QVERIFY(candidateThatWantsTouch.lostTouches.isEmpty());
748 // Simulate that enough time has passed to cause the CandidateInactivityTimer to timeout,
749 // making TouchRegistry consider that undecidedCantidate defaulted.
750 fakeTimerFactory->updateTime(10000);
752 QVERIFY(undecidedCandidate.ownedTouches.isEmpty());
753 QVERIFY(undecidedCandidate.lostTouches.contains(0));
754 QVERIFY(candidateThatWantsTouch.ownedTouches.contains(0));
755 QVERIFY(candidateThatWantsTouch.lostTouches.isEmpty());
758/*
759 An item that calls requestTouchOwnership() without first having called addCandidateOwnerForTouch()
760 is assumed to be the interim owner of the touch point, thus there's no point in sending
761 UnownedTouchEvents to him as he already gets proper QTouchEvents from QQuickWindow because
762 he didn't ignore the first QTouchEvent with that touch point.
763 */
764void tst_TouchRegistry::interimOwnerWontGetUnownedTouchEvents()
766 FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
767 touchRegistry->setTimerFactory(fakeTimerFactory);
769 DummyCandidate undecidedCandidate;
770 undecidedCandidate.setObjectName("undecided");
772 DummyCandidate interimOwner;
773 interimOwner.setObjectName("interimOwner");
775 {
776 QList<QTouchEvent::TouchPoint> touchPoints;
777 touchPoints.append(QTouchEvent::TouchPoint(0));
778 touchPoints[0].setState(Qt::TouchPointPressed);
779 QTouchEvent touchEvent(QEvent::TouchBegin,
780 0 /* device */,
781 Qt::NoModifier,
782 Qt::TouchPointPressed,
783 touchPoints);
784 touchRegistry->update(&touchEvent);
785 }
787 touchRegistry->addCandidateOwnerForTouch(0, &undecidedCandidate);
788 touchRegistry->requestTouchOwnership(0, &interimOwner);
790 {
791 QList<QTouchEvent::TouchPoint> touchPoints;
792 touchPoints.append(QTouchEvent::TouchPoint(0));
793 touchPoints[0].setState(Qt::TouchPointMoved);
794 QTouchEvent touchEvent(QEvent::TouchUpdate,
795 0 /* device */,
796 Qt::NoModifier,
797 Qt::TouchPointMoved,
798 touchPoints);
799 touchRegistry->update(&touchEvent);
800 }
802 QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 1);
803 QCOMPARE(interimOwner.unownedTouchEvents.count(), 0);
805 {
806 QList<QTouchEvent::TouchPoint> touchPoints;
807 touchPoints.append(QTouchEvent::TouchPoint(0));
808 touchPoints[0].setState(Qt::TouchPointMoved);
809 QTouchEvent touchEvent(QEvent::TouchUpdate,
810 0 /* device */,
811 Qt::NoModifier,
812 Qt::TouchPointMoved,
813 touchPoints);
814 touchRegistry->update(&touchEvent);
815 }
817 QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 2);
818 QCOMPARE(interimOwner.unownedTouchEvents.count(), 0);
821/*
822 Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1473492
824 Bug caused by candidates getting deleted before ownership resolution
825 */
826void tst_TouchRegistry::candidateVanishes()
828 DummyCandidate mainCandidate;
829 DummyCandidate *missingCandidate = new DummyCandidate;
831 {
832 QList<QTouchEvent::TouchPoint> touchPoints;
833 touchPoints.append(QTouchEvent::TouchPoint(0));
834 touchPoints[0].setState(Qt::TouchPointPressed);
835 QTouchEvent touchEvent(QEvent::TouchBegin,
836 0 /* device */,
837 Qt::NoModifier,
838 Qt::TouchPointPressed,
839 touchPoints);
840 touchRegistry->update(&touchEvent);
841 }
843 touchRegistry->addCandidateOwnerForTouch(0, &mainCandidate);
844 touchRegistry->addCandidateOwnerForTouch(0, missingCandidate);
846 {
847 QList<QTouchEvent::TouchPoint> touchPoints;
848 touchPoints.append(QTouchEvent::TouchPoint(0));
849 touchPoints[0].setState(Qt::TouchPointMoved);
850 QTouchEvent touchEvent(QEvent::TouchUpdate,
851 0 /* device */,
852 Qt::NoModifier,
853 Qt::TouchPointMoved,
854 touchPoints);
855 touchRegistry->update(&touchEvent);
856 }
858 // This candidate suddenly disappears without having removed its candidacy.
859 delete missingCandidate;
860 missingCandidate = nullptr;
862 touchRegistry->requestTouchOwnership(0, &mainCandidate);
864 QVERIFY(mainCandidate.ownedTouches.contains(0));
867////////////// TouchMemento //////////
869TouchMemento::TouchMemento(const QTouchEvent *touchEvent)
870 : touchPointStates(touchEvent->touchPointStates()), touchPoints(touchEvent->touchPoints())
874bool TouchMemento::containsTouchWithId(int touchId) const
876 for (int i = 0; i < touchPoints.count(); ++i) {
877 if (touchPoints.at(i).id() == touchId) {
878 return true;
879 }
880 }
881 return false;
884////////////// DummyCandidate //////////
886bool DummyCandidate::event(QEvent *e)
888 if (e->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
889 TouchOwnershipEvent *touchOwnershipEvent = static_cast<TouchOwnershipEvent *>(e);
891 // NB: Cannot use QVERIFY here because the macro doesn't return a boolean and is
892 // meant for use only directly in the body of a test function
893 if (ownedTouches.contains(touchOwnershipEvent->touchId()))
894 qFatal("Sent ownership event for a touch that is already owned.");
895 if (lostTouches.contains(touchOwnershipEvent->touchId()))
896 qFatal("Sent ownership event for a touch that has already been lost.");
898 if (touchOwnershipEvent->gained()) {
899 ownedTouches.insert(touchOwnershipEvent->touchId());
900 } else {
901 lostTouches.insert(touchOwnershipEvent->touchId());
902 }
903 return true;
904 } else if (e->type() == UnownedTouchEvent::unownedTouchEventType()) {
905 UnownedTouchEvent *unownedTouchEvent = static_cast<UnownedTouchEvent *>(e);
906 unownedTouchEvents.append(TouchMemento(unownedTouchEvent->touchEvent()));
907 return true;
908 } else {
909 return QObject::event(e);
910 }
913QTEST_GUILESS_MAIN(tst_TouchRegistry)
915#include "tst_TouchRegistry.moc"