on 8a93021 help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp
1306 lines 51 kB history raw
1/*
2 * Copyright (C) 2013-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/QtTest>
18#include <QtCore/QObject>
19#include <QtQuick/QQuickView>
20#include <QtQml/QQmlEngine>
21#include <QPointer>
22#include <private/qquickmousearea_p.h>
23#include <private/qquickwindow_p.h>
26#include <DirectionalDragArea.h>
27#include <DirectionalDragArea_p.h>
28#include <TouchRegistry.h>
30#include "GestureTest.h"
32using namespace UbuntuGestures;
34// Because QSignalSpy(directionalDragArea, SIGNAL(DirectionalDragArea::Status)) simply
35// doesn't work
36class StatusSpy : public QObject {
37 Q_OBJECT
38public:
39 StatusSpy(DirectionalDragArea *edgeDragArea) {
40 m_recognized = false;
41 connect(edgeDragArea->d, &DirectionalDragAreaPrivate::statusChanged,
42 this, &StatusSpy::onStatusChanged);
43 }
44 bool recognized() {
45 return m_recognized;
46 }
48private Q_SLOTS:
49 void onStatusChanged(DirectionalDragAreaPrivate::Status status) {
50 m_recognized |= status == DirectionalDragAreaPrivate::Recognized;
51 }
53private:
54 bool m_recognized;
55};
57/*
58 QQuickMouseArea::canceled() signal is not registered in the meta object system.
59 So using a QSignalSpy to track it won't work. Thus the only way to connect to it
60 is using its method address directly.
61 */
62class MouseAreaSpy : public QObject
64 Q_OBJECT
65public:
66 MouseAreaSpy(QQuickMouseArea *mouseArea)
67 : canceledCount(0)
68 {
69 connect(mouseArea, &QQuickMouseArea::canceled,
70 this, &MouseAreaSpy::onMouseAreaCanceled);
71 }
73 int canceledCount;
75private Q_SLOTS:
76 void onMouseAreaCanceled() {
77 ++canceledCount;
78 }
79};
81class tst_DirectionalDragArea: public GestureTest
83 Q_OBJECT
84public:
85 tst_DirectionalDragArea();
86private Q_SLOTS:
87 void init(); // called right before each and every test function is executed
89 void dragWithShortDirectionChange();
90 void recognitionTimerUsage();
91 void sceneXAndX();
92 void sceneYAndY();
93 void twoFingerTap();
94 void movingDDA();
95 void ignoreOldFinger();
96 void rotated();
97 void sceneDistance();
98 void sceneDistance_data();
99 void disabledWhileDragging();
100 void oneFingerDownFollowedByLateSecondFingerDown();
101 void givesUpWhenLosesTouch();
102 void threeFingerDrag();
103 void immediateRecognitionWhenConstraintsDisabled();
104 void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition();
105 void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data();
106 void gettingTouchOwnershipMakesMouseAreaBehindGetCanceled();
107 void interleavedTouches();
108 void makoRightEdgeDrag();
109 void makoRightEdgeDrag_verticalDownwards();
110 void makoLeftEdgeDrag_slowStart();
111 void makoLeftEdgeDrag_movesSlightlyBackwardsOnStart();
113private:
114 // QTest::touchEvent takes QPoint instead of QPointF and I don't want to
115 // lose precision due to rounding.
116 // Besides, those helper functions lead to more compact code.
117 void sendTouchPress(qint64 timestamp, int id, QPointF pos);
118 void sendTouchUpdate(qint64 timestamp, int id, QPointF pos);
119 void sendTouchRelease(qint64 timestamp, int id, QPointF pos);
120 void sendTouch(qint64 timestamp, int id, QPointF pos,
121 Qt::TouchPointState pointState, QEvent::Type eventType);
123 void passTime(qint64 timeSpanMs);
124};
126tst_DirectionalDragArea::tst_DirectionalDragArea()
127 : GestureTest(QStringLiteral("tst_DirectionalDragArea.qml"))
131void tst_DirectionalDragArea::init()
133 GestureTest::init();
135 // We shouldn't need the three lines below, but a compiz/unity7
136 // regression means we don't pass the test without them because
137 // the window doesn't have the proper size. Can be removed in the
138 // future if the regression is fixed and tests pass again
139 m_view->resize(m_view->rootObject()->width(), m_view->rootObject()->height());
140 QTRY_COMPARE(m_view->width(), (int)m_view->rootObject()->width());
141 QTRY_COMPARE(m_view->height(), (int)m_view->rootObject()->height());
144void tst_DirectionalDragArea::sendTouchPress(qint64 timestamp, int id, QPointF pos)
146 sendTouch(timestamp, id, pos, Qt::TouchPointPressed, QEvent::TouchBegin);
149void tst_DirectionalDragArea::sendTouchUpdate(qint64 timestamp, int id, QPointF pos)
151 sendTouch(timestamp, id, pos, Qt::TouchPointMoved, QEvent::TouchUpdate);
154void tst_DirectionalDragArea::sendTouchRelease(qint64 timestamp, int id, QPointF pos)
156 sendTouch(timestamp, id, pos, Qt::TouchPointReleased, QEvent::TouchEnd);
159void tst_DirectionalDragArea::sendTouch(qint64 timestamp, int id, QPointF pos,
160 Qt::TouchPointState pointState, QEvent::Type eventType)
162 m_fakeTimerFactory->updateTime(timestamp);
164 QTouchEvent::TouchPoint point;
166 point.setState(pointState);
167 point.setId(id);
168 point.setScenePos(pos);
169 point.setPos(pos);
171 QList<QTouchEvent::TouchPoint> points;
172 points << point;
174 QTouchEvent touchEvent(eventType, m_device, Qt::NoModifier, Qt::TouchPointPressed, points);
175 QCoreApplication::sendEvent(m_view, &touchEvent);
177 QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(m_view);
178 windowPrivate->flushDelayedTouchEvent();
181void tst_DirectionalDragArea::passTime(qint64 timeSpanMs)
183 qint64 finalTime = m_fakeTimerFactory->timeSource()->msecsSinceReference() + timeSpanMs;
184 m_fakeTimerFactory->updateTime(finalTime);
187namespace {
188QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea)
190 QPointF localCenter(edgeDragArea->width() / 2., edgeDragArea->height() / 2.);
191 return edgeDragArea->mapToScene(localCenter);
195/*
196 A directional drag should still be recognized if there is a momentaneous, small,
197 change in the direction of a drag. That should be accounted as input noise and
198 therefore ignored.
199 */
200void tst_DirectionalDragArea::dragWithShortDirectionChange()
202 DirectionalDragArea *edgeDragArea =
203 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
204 QVERIFY(edgeDragArea != 0);
205 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
206 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
208 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
209 QPointF touchPoint = initialTouchPos;
211 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0;
212 QPointF dragDirectionVector(1.0, 0.0);
213 qreal touchStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
214 // make sure we are above maximum time
215 int touchStepTimeMs = edgeDragArea->d->maxTime / 20. ;
216 QPointF touchMovement = dragDirectionVector * touchStepDistance;
218 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
220 // Move a bit in the proper direction
221 for (int i=0; i < 3; ++i) {
222 touchPoint += touchMovement;
223 passTime(touchStepTimeMs);
224 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
225 }
227 // Then a sudden and small movement to the opposite direction
228 touchPoint -= touchMovement*0.2;
229 passTime(touchStepTimeMs*0.2);
230 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
232 // And then resume movment in the correct direction until it crosses the distance and time
233 // thresholds.
234 do {
235 touchPoint += touchMovement;
236 passTime(touchStepTimeMs);
237 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
238 } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance
239 || m_fakeTimerFactory->timeSource()->msecsSinceReference() < (edgeDragArea->d->compositionTime * 1.5f));
241 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
243 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
246/*
247 Checks that the recognition timer is started and stopped appropriately.
248 I.e., check that it's running only while gesture recognition is taking place
249 (status == Undecided)
250 */
251void tst_DirectionalDragArea::recognitionTimerUsage()
253 DirectionalDragArea *edgeDragArea =
254 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
255 QVERIFY(edgeDragArea != 0);
256 AbstractTimer *fakeTimer = m_fakeTimerFactory->createTimer();
257 edgeDragArea->d->setRecognitionTimer(fakeTimer);
258 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
260 int timeStepMs = 5; // some arbitrary small value.
262 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
263 QPointF touchPoint = initialTouchPos;
265 QPointF dragDirectionVector(1.0, 0.0);
266 QPointF touchMovement = dragDirectionVector * (edgeDragArea->d->distanceThreshold * 0.2f);
268 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
269 QVERIFY(!fakeTimer->isRunning());
271 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
273 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
274 QVERIFY(fakeTimer->isRunning());
276 // Move beyond distance threshold and composition time to ensure recognition
277 while (m_fakeTimerFactory->timeSource()->msecsSinceReference() <= edgeDragArea->d->compositionTime ||
278 (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->d->distanceThreshold) {
280 QCOMPARE(edgeDragArea->d->status == DirectionalDragAreaPrivate::Undecided, fakeTimer->isRunning());
282 touchPoint += touchMovement;
283 passTime(timeStepMs);
284 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
285 }
287 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
288 QVERIFY(!fakeTimer->isRunning());
291/*
292 Checks that it informs the X coordinate of the touch point in local and scene coordinates
293 correctly.
294 */
295void tst_DirectionalDragArea::sceneXAndX()
297 DirectionalDragArea *edgeDragArea =
298 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
299 QVERIFY(edgeDragArea != 0);
300 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
301 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
302 edgeDragArea->setImmediateRecognition(true);
304 QPointF touchScenePos(m_view->width() - (edgeDragArea->width()/2.0f), m_view->height()/2.0f);
306 sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos);
308 QSignalSpy touchXSpy(edgeDragArea, SIGNAL(touchXChanged(qreal)));
309 QSignalSpy touchSceneXSpy(edgeDragArea, SIGNAL(touchSceneXChanged(qreal)));
311 touchScenePos.rx() = m_view->width() / 2;
312 sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos);
314 QCOMPARE(touchXSpy.count(), 1);
315 QCOMPARE(touchSceneXSpy.count(), 1);
316 QCOMPARE(edgeDragArea->touchX(), touchScenePos.x() - edgeDragArea->x());
317 QCOMPARE(edgeDragArea->touchSceneX(), touchScenePos.x());
320/*
321 Checks that it informs the Y coordinate of the touch point in local and scene coordinates
322 correctly.
323 */
324void tst_DirectionalDragArea::sceneYAndY()
326 DirectionalDragArea *edgeDragArea =
327 m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
328 QVERIFY(edgeDragArea != 0);
329 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
330 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
331 edgeDragArea->setImmediateRecognition(true);
333 QPointF touchScenePos(m_view->width()/2.0f, m_view->height() - (edgeDragArea->height()/2.0f));
335 sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos);
337 QSignalSpy touchYSpy(edgeDragArea, SIGNAL(touchYChanged(qreal)));
338 QSignalSpy touchSceneYSpy(edgeDragArea, SIGNAL(touchSceneYChanged(qreal)));
340 touchScenePos.ry() = m_view->height() / 2;
341 sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos);
343 QCOMPARE(touchYSpy.count(), 1);
344 QCOMPARE(touchSceneYSpy.count(), 1);
345 QCOMPARE(edgeDragArea->touchY(), touchScenePos.y() - edgeDragArea->y());
346 QCOMPARE(edgeDragArea->touchSceneY(), touchScenePos.y());
349/*
350 Regression test for https://bugs.launchpad.net/bugs/1228336
352 Perform a quick two-finger double-tap and check that DirectionalDragArea properly
353 rejects those touch points. In the bug above it got confused and crashed.
354 */
355void tst_DirectionalDragArea::twoFingerTap()
357 DirectionalDragArea *edgeDragArea =
358 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
359 QVERIFY(edgeDragArea != 0);
360 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
361 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
363 // Make touches evenly spaced along the edgeDragArea
364 QPoint touchAPos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
365 QPoint touchBPos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
367 qint64 timeStepMsecs = 5; // some arbitrary, small value
369 // Perform the first two-finger tap
370 // NB: using move() instead of stationary() becasue in the latter you cannot provide
371 // the touch position and therefore it's left with some garbage numbers.
372 QTest::touchEvent(m_view, m_device)
373 .press(0, touchAPos);
375 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
377 passTime(timeStepMsecs);
378 QTest::touchEvent(m_view, m_device)
379 .move(0, touchAPos)
380 .press(1, touchBPos);
382 // A second touch point appeared during recognition, reject immediately as this
383 // can't be a single-touch gesture anymore.
384 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
386 passTime(timeStepMsecs);
387 QTest::touchEvent(m_view, m_device)
388 .release(0, touchAPos)
389 .move(1, touchBPos);
391 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
393 passTime(timeStepMsecs);
394 QTest::touchEvent(m_view, m_device)
395 .release(1, touchBPos);
397 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
399 // Perform the second two-finger tap
401 passTime(timeStepMsecs);
402 QTest::touchEvent(m_view, m_device)
403 .press(0, touchAPos);
405 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
407 passTime(timeStepMsecs);
408 QTest::touchEvent(m_view, m_device)
409 .move(0, touchAPos)
410 .press(1, touchBPos);
412 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
414 passTime(timeStepMsecs);
415 QTest::touchEvent(m_view, m_device)
416 .release(0, touchAPos)
417 .move(1, touchBPos);
419 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
421 passTime(timeStepMsecs);
422 QTest::touchEvent(m_view, m_device)
423 .release(1, touchBPos);
425 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
428/*
429 Tests that gesture recognition works normally even if the DirectionalDragArea moves
430 during recognition.
431 This effectively means that we have to do gesture recognition with scene coordinates
432 instead of local item coordinates.
433 */
434void tst_DirectionalDragArea::movingDDA()
436 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
437 Q_ASSERT(rightwardsLauncher != 0);
439 DirectionalDragArea *edgeDragArea =
440 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
441 Q_ASSERT(edgeDragArea != 0);
442 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
443 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
445 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
446 QPointF touchPoint = initialTouchPos;
448 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
449 QPointF dragDirectionVector(1.0f, 0.0f);
451 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
452 QPointF touchMovement = dragDirectionVector * movementStepDistance;
453 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
454 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
456 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
458 // Move it far ahead along the direction of the gesture
459 // rightwardsLauncher is a parent of our DirectionalDragArea. So moving it will move our DDA
460 rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->d->distanceThreshold * 5.0f);
462 for (int i = 0; i < totalMovementSteps; ++i) {
463 touchPoint += touchMovement;
464 passTime(movementTimeStepMs);
465 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
466 }
468 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
470 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
473/*
474 The presence of and old, rejected, touch point lying on the DirectionalDragArea
475 shouldn't impede the recognition of a gesture from a new touch point.
476 */
477void tst_DirectionalDragArea::ignoreOldFinger()
479 DirectionalDragArea *edgeDragArea =
480 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
481 Q_ASSERT(edgeDragArea != 0);
482 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
483 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
485 // Make touches evenly spaced along the edgeDragArea
486 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
487 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
489 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
491 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
493 // leave it lying around for some time
494 passTime(edgeDragArea->d->maxTime * 10);
496 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
498 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
499 QPointF dragDirectionVector(1.0f, 0.0f);
501 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
502 QPointF touchMovement = dragDirectionVector * movementStepDistance;
503 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
504 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
506 QTest::touchEvent(m_view, m_device)
507 .move(0, touch0Pos)
508 .press(1, touch1Pos);
510 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
512 for (int i = 0; i < totalMovementSteps; ++i) {
513 touch1Pos += touchMovement.toPoint();
514 passTime(movementTimeStepMs);
515 QTest::touchEvent(m_view, m_device)
516 .move(0, touch0Pos)
517 .move(1, touch1Pos);
518 }
520 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
522 QTest::touchEvent(m_view, m_device)
523 .move(0, touch0Pos)
524 .release(1, touch1Pos);
526 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
529/*
530 A Rightwards DDA that is rotated 90 degrees clockwise should recognize gestures
531 that are done downwards in scene coordinates. I.e. the gesture recognition direction
532 should be in local coordinates, not scene coordinates.
533 */
534void tst_DirectionalDragArea::rotated()
536 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
537 baseItem->setRotation(90.);
539 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
540 Q_ASSERT(rightwardsLauncher != 0);
542 DirectionalDragArea *edgeDragArea =
543 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
544 Q_ASSERT(edgeDragArea != 0);
545 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
546 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
548 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
549 QPointF touchPoint = initialTouchPos;
551 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
552 QPointF dragDirectionVector(0.0f, 1.0f);
554 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
555 QPointF touchMovement = dragDirectionVector * movementStepDistance;
556 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
557 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
559 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
561 for (int i = 0; i < totalMovementSteps; ++i) {
562 touchPoint += touchMovement;
563 passTime(movementTimeStepMs);
564 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
565 }
567 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
569 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
572void tst_DirectionalDragArea::sceneDistance()
574 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
575 QFETCH(qreal, rotation);
576 QFETCH(QPointF, dragDirectionVector);
577 baseItem->setRotation(rotation);
579 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
580 Q_ASSERT(rightwardsLauncher != 0);
582 DirectionalDragArea *edgeDragArea =
583 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
584 Q_ASSERT(edgeDragArea != 0);
585 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
586 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
588 // to disable the position smoothing so that we can more easily check sceneDistance values
589 edgeDragArea->setImmediateRecognition(true);
591 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
592 QPointF touchPoint = initialTouchPos;
594 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
596 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
597 QPointF touchMovement = dragDirectionVector * movementStepDistance;
598 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
599 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
601 qint64 timestamp = 0;
603 sendTouchPress(timestamp, 0, touchPoint);
605 for (int i = 0; i < totalMovementSteps; ++i) {
606 touchPoint += touchMovement;
607 timestamp += movementTimeStepMs;
608 sendTouchUpdate(timestamp, 0, touchPoint);
609 }
611 qreal actualDragDistance = ((qreal)totalMovementSteps) * movementStepDistance;
613 // DirectionalDragArea::sceneDistance() must match the actual drag distance as the
614 // drag was aligned with the gesture direction
615 // NB: qFuzzyCompare(), used internally by QCOMPARE(), is broken.
616 QVERIFY(qAbs(edgeDragArea->sceneDistance() - actualDragDistance) < 0.001);
618 timestamp += movementTimeStepMs;
619 sendTouchRelease(timestamp, 0, touchPoint);
622void tst_DirectionalDragArea::sceneDistance_data()
624 QTest::addColumn<qreal>("rotation");
625 QTest::addColumn<QPointF>("dragDirectionVector");
627 QTest::newRow("not rotated") << 0. << QPointF(1., 0.);
628 QTest::newRow("rotated by 90 degrees") << 90. << QPointF(0., 1.);
631/*
632 Regression test for https://bugs.launchpad.net/unity8/+bug/1276122
634 The bug:
635 If setting "enabled: false" while the DirectionalDragArea's (DDA) dragging
636 property is true, the DDA stays in that state and doesn't recover any more.
637*/
638void tst_DirectionalDragArea::disabledWhileDragging()
640 DirectionalDragArea *edgeDragArea =
641 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
642 Q_ASSERT(edgeDragArea != 0);
643 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
644 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
646 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
648 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
649 QPointF dragDirectionVector(1., 0.); // horizontal positive
651 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
652 QPointF touchMovement = dragDirectionVector * movementStepDistance;
653 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
654 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
656 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
658 for (int i = 0; i < totalMovementSteps; ++i) {
659 touchPoint += touchMovement;
660 passTime(movementTimeStepMs);
661 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
662 }
664 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
665 QCOMPARE(edgeDragArea->dragging(), true);
667 // disable the dragArea while it's being dragged.
668 edgeDragArea->setEnabled(false);
670 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
671 QCOMPARE(edgeDragArea->dragging(), false);
673 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
676void tst_DirectionalDragArea::oneFingerDownFollowedByLateSecondFingerDown()
678 DirectionalDragArea *edgeDragArea =
679 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
680 Q_ASSERT(edgeDragArea != 0);
681 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
682 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
684 // Disable some constraints we're not interested in
685 edgeDragArea->d->setMaxTime(60 * 1000);
687 // And ensure others have the values we want
688 edgeDragArea->d->compositionTime = 60;
690 // Put an item right behind edgeDragArea to receive the touches ignored by it
691 DummyItem *dummyItem = new DummyItem;
692 dummyItem->setParentItem(edgeDragArea->parentItem());
693 dummyItem->setX(edgeDragArea->x());
694 dummyItem->setY(edgeDragArea->y());
695 dummyItem->setZ(edgeDragArea->z() - 1.0);
696 dummyItem->setWidth(edgeDragArea->width());
697 dummyItem->setHeight(edgeDragArea->height());
699 // Make touches evenly spaced along the edgeDragArea
700 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
701 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
703 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
705 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
707 // We are now going to be way beyond compositionTime
708 passTime(edgeDragArea->d->compositionTime*3);
710 QTest::touchEvent(m_view, m_device)
711 .move(0, touch0Pos)
712 .press(1, touch1Pos);
714 // A new touch has come, but as it can't be composed with touch 0, it should be
715 // ignored/rejected by the DirectionalDragArea
716 // Therefore the last event received by dummyItem must have both touch points (0 and 1)
717 {
718 TouchMemento &touchMemento = dummyItem->touchEvents.last();
719 QCOMPARE(touchMemento.touchPoints.count(), 2);
720 QVERIFY(touchMemento.containsTouchWithId(0));
721 QVERIFY(touchMemento.containsTouchWithId(1));
722 }
724 passTime(30);
726 QTest::touchEvent(m_view, m_device)
727 .move(0, touch0Pos)
728 .move(1, touch1Pos);
730 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
732 passTime(5);
734 QTest::touchEvent(m_view, m_device)
735 .release(0, touch0Pos)
736 .move(1, touch1Pos);
738 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
740 passTime(5);
742 QTest::touchEvent(m_view, m_device)
743 .release(1, touch1Pos);
745 // Shouldn't be keepping info about touches that no longer exist or interest us
746 QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
748 delete dummyItem;
751void tst_DirectionalDragArea::givesUpWhenLosesTouch()
753 DirectionalDragArea *edgeDragArea =
754 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
755 Q_ASSERT(edgeDragArea != 0);
756 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
757 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
759 // Disable some constraints we're not interested in
760 edgeDragArea->d->setMaxTime(60 * 1000);
762 // Put an item right in front of edgeDragArea
763 DummyItem *dummyItem = new DummyItem(edgeDragArea->parentItem());
764 dummyItem->setX(edgeDragArea->x());
765 dummyItem->setY(edgeDragArea->y());
766 dummyItem->setZ(edgeDragArea->z() + 1.0);
767 dummyItem->setWidth(edgeDragArea->width());
768 dummyItem->setHeight(edgeDragArea->height());
770 QPoint touchPos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
772 dummyItem->touchEventHandler = [&](QTouchEvent *event) {
773 m_touchRegistry->addCandidateOwnerForTouch(0, dummyItem);
774 event->ignore();
775 };
777 QTest::touchEvent(m_view, m_device).press(0, touchPos);
779 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
781 m_touchRegistry->requestTouchOwnership(0, dummyItem);
783 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
785 dummyItem->grabTouchPoints({0});
786 dummyItem->touchEventHandler = [&](QTouchEvent *event) { event->accept(); };
788 passTime(5);
789 QTest::touchEvent(m_view, m_device).release(0, touchPos);
791 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
793 QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
796void tst_DirectionalDragArea::threeFingerDrag()
798 DirectionalDragArea *edgeDragArea =
799 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
800 Q_ASSERT(edgeDragArea != 0);
801 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
802 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
804 // Disable some constraints we're not interested in
805 edgeDragArea->d->setMaxTime(60 * 1000);
807 // And ensure others have the values we want
808 edgeDragArea->d->compositionTime = 60;
810 // Make touches evenly spaced along the edgeDragArea
811 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.25f);
812 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.50f);
813 QPoint touch2Pos(edgeDragArea->width()/2.0f, m_view->height()*0.75f);
815 QTest::touchEvent(m_view, m_device)
816 .press(0, touch0Pos);
818 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
820 passTime(5);
821 QTest::touchEvent(m_view, m_device)
822 .move(0, touch0Pos)
823 .press(1, touch1Pos);
825 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
827 passTime(5);
828 QTest::touchEvent(m_view, m_device)
829 .move(0, touch0Pos)
830 .move(1, touch1Pos)
831 .press(2, touch2Pos);
833 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
835 passTime(10);
836 QTest::touchEvent(m_view, m_device)
837 .move(0, touch0Pos)
838 .move(1, touch1Pos)
839 .move(2, touch2Pos);
841 passTime(200);
842 QTest::touchEvent(m_view, m_device)
843 .move(0, touch0Pos)
844 .release(1, touch1Pos)
845 .move(2, touch2Pos);
847 passTime(10);
848 QTest::touchEvent(m_view, m_device)
849 .move(0, touch0Pos)
850 .release(2, touch2Pos);
852 passTime(5);
853 QTest::touchEvent(m_view, m_device)
854 .release(0, touch0Pos);
856 // Shouldn't be keepping info about touches that no longer exist or interest us
857 QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
860/*
861 If all the relevant gesture recognition constraints/parameters have been disabled,
862 it means that the gesture recognition itself has been disabled and DirectionalDragArea
863 will therefore work like a simple touch area, merely reporting touch movement.
864 */
865void tst_DirectionalDragArea::immediateRecognitionWhenConstraintsDisabled()
867 DirectionalDragArea *edgeDragArea =
868 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
869 Q_ASSERT(edgeDragArea != 0);
870 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
871 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
873 // Disable the minimum amount of constraints to ensure immediate recognition
874 edgeDragArea->d->setDistanceThreshold(0);
875 edgeDragArea->d->compositionTime = 0;
877 // Put an item right behind edgeDragArea to receive the touches ignored by it
878 DummyItem *dummyItem = new DummyItem;
879 dummyItem->setParentItem(edgeDragArea->parentItem());
880 dummyItem->setX(edgeDragArea->x());
881 dummyItem->setY(edgeDragArea->y());
882 dummyItem->setZ(edgeDragArea->z() - 1.0);
883 dummyItem->setWidth(edgeDragArea->width());
884 dummyItem->setHeight(edgeDragArea->height());
886 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
888 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
890 // check for immediate recognition
891 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
893 // and therefore it should have immediately grabbed the touch point,
894 // not letting it leak to items behind him.
895 QCOMPARE(dummyItem->touchEvents.count(), 0);
898void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition()
900 DirectionalDragArea *edgeDragArea =
901 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
902 Q_ASSERT(edgeDragArea != 0);
903 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
904 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
906 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
908 // Move less than the minimum needed for the drag gesture recognition
909 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 0.5f;
910 QPointF dragDirectionVector(1., 0.); // horizontal positive
912 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
913 QPointF touchMovement = dragDirectionVector * movementStepDistance;
914 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
915 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 0.8f) / totalMovementSteps;
917 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
919 for (int i = 0; i < totalMovementSteps; ++i) {
920 touchPoint += touchMovement;
921 passTime(movementTimeStepMs);
922 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
923 }
925 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
927 // edgeDragArea should be an undecided candidate
928 {
929 auto touchInfo = m_touchRegistry->findTouchInfo(0);
930 QCOMPARE(touchInfo->candidates.size(), 1);
931 QCOMPARE(touchInfo->candidates.at(0).item.data(), edgeDragArea);
932 QCOMPARE(touchInfo->candidates.at(0).state, TouchRegistry::CandidateInfo::Undecided);
933 }
935 // disable the dragArea while it's still recognizing a possible drag gesture.
936 QFETCH(bool, disable);
937 if (disable) {
938 edgeDragArea->setEnabled(false);
939 } else {
940 edgeDragArea->setVisible(false);
941 }
943 // edgeDragArea should no longer be a candidate
944 {
945 auto touchInfo = m_touchRegistry->findTouchInfo(0);
946 QCOMPARE(touchInfo->candidates.size(), 0);
947 }
949 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
951 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
954void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data()
956 QTest::addColumn<bool>("disable");
958 QTest::newRow("disabled") << true;
959 QTest::newRow("invisible") << false;
962void tst_DirectionalDragArea::gettingTouchOwnershipMakesMouseAreaBehindGetCanceled()
964 DirectionalDragArea *edgeDragArea =
965 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
966 QVERIFY(edgeDragArea != nullptr);
967 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
968 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
970 QQuickMouseArea *mouseArea =
971 m_view->rootObject()->findChild<QQuickMouseArea*>("mouseArea");
972 QVERIFY(mouseArea != nullptr);
974 MouseAreaSpy mouseAreaSpy(mouseArea);
976 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
977 QPointF touchPoint = initialTouchPos;
979 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2;
980 QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
981 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
982 QPointF touchMovement = dragDirectionVector * movementStepDistance;
983 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
984 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
986 QCOMPARE(mouseArea->pressed(), false);
988 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
990 // The TouchBegin passes through the DirectionalDragArea and reaches the MouseArea behind it,
991 // where it's converted to a MouseEvent by QQuickWindow and sent to the MouseArea which then
992 // accepts it. Making it get pressed.
993 QCOMPARE(mouseArea->pressed(), true);
994 QCOMPARE(mouseAreaSpy.canceledCount, 0);
996 for (int i = 0; i < totalMovementSteps; ++i) {
997 touchPoint += touchMovement;
998 passTime(movementTimeStepMs);
999 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
1002 // As the DirectionalDragArea recognizes the gesture, it grabs the touch from the MouseArea,
1003 // which should make the MouseArea get a cancelation event, which will then cause it to
1004 // reset its state (going back to "unpressed"/"released").
1005 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
1006 QCOMPARE(mouseArea->pressed(), false);
1007 QCOMPARE(mouseAreaSpy.canceledCount, 1);
1009 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
1012void tst_DirectionalDragArea::interleavedTouches()
1014 DirectionalDragArea *edgeDragArea =
1015 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1016 QVERIFY(edgeDragArea != 0);
1017 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1018 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1020 QPointF touch0 = edgeDragArea->mapToScene(
1021 QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.3));
1023 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2;
1024 QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
1025 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
1026 QPointF touchMovement = dragDirectionVector * movementStepDistance;
1027 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
1028 int movementTimeStepMs = (edgeDragArea->d->maxTime * 0.4f) / totalMovementSteps;
1030 QTest::touchEvent(m_view, m_device).press(0, touch0.toPoint());
1031 for (int i = 0; i < totalMovementSteps; ++i) {
1032 touch0 += touchMovement;
1033 passTime(movementTimeStepMs);
1034 QTest::touchEvent(m_view, m_device).move(0, touch0.toPoint());
1036 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
1038 QPointF touch1 = edgeDragArea->mapToScene(
1039 QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.6));
1041 QTest::touchEvent(m_view, m_device)
1042 .move(0, touch0.toPoint())
1043 .press(1, touch1.toPoint());
1045 touch1 += touchMovement;
1046 passTime(movementTimeStepMs);
1047 QTest::touchEvent(m_view, m_device)
1048 .move(0, touch0.toPoint())
1049 .move(1, touch1.toPoint());
1051 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
1053 QTest::touchEvent(m_view, m_device)
1054 .release(0, touch0.toPoint())
1055 .move(1, touch1.toPoint());
1057 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1059 touch1 += touchMovement;
1060 passTime(movementTimeStepMs);
1061 QTest::touchEvent(m_view, m_device)
1062 .move(1, touch1.toPoint());
1064 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1066 QPointF touch2 = edgeDragArea->mapToScene(
1067 QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.9));
1069 passTime(edgeDragArea->d->compositionTime + movementTimeStepMs);
1070 QTest::touchEvent(m_view, m_device)
1071 .move(1, touch1.toPoint())
1072 .press(2, touch2.toPoint());
1074 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
1075 QCOMPARE(edgeDragArea->d->touchId, 2);
1077 touch2 += touchMovement;
1078 passTime(movementTimeStepMs);
1079 QTest::touchEvent(m_view, m_device)
1080 .move(1, touch1.toPoint())
1081 .move(2, touch2.toPoint());
1083 touch1 += touchMovement;
1084 passTime(movementTimeStepMs);
1085 QTest::touchEvent(m_view, m_device)
1086 .move(1, touch1.toPoint())
1087 .move(2, touch2.toPoint());
1089 passTime(movementTimeStepMs);
1090 QTest::touchEvent(m_view, m_device)
1091 .release(1, touch1.toPoint())
1092 .move(2, touch2.toPoint());
1094 passTime(movementTimeStepMs);
1095 QTest::touchEvent(m_view, m_device)
1096 .release(2, touch2.toPoint());
1098 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1102 A valid right-edge drag performed on mako
1103 */
1104void tst_DirectionalDragArea::makoRightEdgeDrag()
1106 m_view->resize(768, 1280);
1107 QTest::qWait(300);
1109 DirectionalDragArea *edgeDragArea =
1110 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1111 QVERIFY(edgeDragArea != nullptr);
1112 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1113 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1115 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1117 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1119 sendTouchPress(319744, 0, QPointF(767.001, 719.719));
1120 sendTouchUpdate(319765, 0, QPointF(765.744,729.973));
1121 sendTouchUpdate(319784, 0, QPointF(740.879,752.182));
1122 sendTouchUpdate(319803, 0, QPointF(689.698,795.795));
1123 sendTouchUpdate(319826, 0, QPointF(616.978,856.212));
1124 sendTouchUpdate(319845, 0, QPointF(558.769,906.157));
1125 sendTouchUpdate(319859, 0, QPointF(513.219,945.266));
1126 sendTouchUpdate(319878, 0, QPointF(481.31,975.496));
1127 sendTouchUpdate(319902, 0, QPointF(460.016,997.439));
1128 sendTouchUpdate(319920, 0, QPointF(449.761,1008.6));
1129 sendTouchUpdate(319929, 0, QPointF(445.891,1012.42));
1130 sendTouchUpdate(319947, 0, QPointF(444.884,1013.93));
1131 sendTouchUpdate(319965, 0, QPointF(444.461,1014.35));
1132 sendTouchUpdate(320057, 0, QPointF(444.71,1013.56));
1133 sendTouchUpdate(320138, 0, QPointF(445.434,1013.6));
1134 sendTouchUpdate(320154, 0, QPointF(446.338,1012.98));
1135 sendTouchUpdate(320171, 0, QPointF(447.232,1012.08));
1136 sendTouchRelease(320171, 0, QPointF(447.232,1012.08));
1138 QCOMPARE(statusSpy->recognized(), true);
1140 delete statusSpy;
1144 A vertical, downwards swipe performed on mako near its right edge.
1146 The DirectionalDragArea on the right edge must not recognize this
1147 gesture.
1148 */
1149void tst_DirectionalDragArea::makoRightEdgeDrag_verticalDownwards()
1151 m_view->resize(768, 1280);
1152 QTest::qWait(300);
1154 DirectionalDragArea *edgeDragArea =
1155 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1156 QVERIFY(edgeDragArea != nullptr);
1157 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1158 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1160 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1162 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1164 sendTouchPress(12012445, 26, QPointF(767.001,461.82));
1165 sendTouchUpdate(12012472, 26, QPointF(767.001,462.569));
1166 sendTouchUpdate(12012528, 26, QPointF(767.001,463.334));
1167 sendTouchUpdate(12012546, 26, QPointF(767.001,466.856));
1168 sendTouchUpdate(12012571, 26, QPointF(767.001,473.291));
1169 sendTouchUpdate(12012587, 26, QPointF(767.001,487.31));
1170 sendTouchUpdate(12012604, 26, QPointF(765.364,507.521));
1171 sendTouchUpdate(12012618, 26, QPointF(765.364,507.521));
1172 sendTouchUpdate(12012627, 26, QPointF(762.642,534.317));
1173 sendTouchUpdate(12012655, 26, QPointF(760.846,573.406));
1174 sendTouchUpdate(12012667, 26, QPointF(759.838,625.295));
1175 sendTouchUpdate(12012675, 26, QPointF(758.875,703.207));
1176 sendTouchUpdate(12012696, 26, QPointF(761.52,777.015));
1177 sendTouchUpdate(12012713, 26, QPointF(765.659,835.591));
1178 sendTouchUpdate(12012731, 26, QPointF(766.778,883.206));
1179 sendTouchUpdate(12012748, 26, QPointF(767.001,922.937));
1180 sendTouchUpdate(12012779, 26, QPointF(767.001,967.558));
1181 sendTouchUpdate(12012798, 26, QPointF(767.001,1006.12));
1182 sendTouchUpdate(12012809, 26, QPointF(767.001,1033.1));
1183 sendTouchRelease(12012810, 26, QPointF(767.001,1033.1));
1185 QCOMPARE(statusSpy->recognized(), false);
1187 delete statusSpy;
1191 A valid left-edge drag performed on mako. This one starts a bit slow than speeds up
1192 */
1193void tst_DirectionalDragArea::makoLeftEdgeDrag_slowStart()
1195 m_view->resize(768, 1280);
1196 QTest::qWait(300);
1198 DirectionalDragArea *edgeDragArea =
1199 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1200 QVERIFY(edgeDragArea != nullptr);
1201 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1202 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1204 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1206 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1208 sendTouchPress(4002267, 77, QPointF(0,885.154));
1209 sendTouchUpdate(4002275, 77, QPointF(0,886.214));
1210 sendTouchUpdate(4002311, 77, QPointF(1.09568,887.75));
1211 sendTouchUpdate(4002329, 77, QPointF(3.53647,890.191));
1212 sendTouchUpdate(4002347, 77, QPointF(7.87434,892.879));
1213 sendTouchUpdate(4002366, 77, QPointF(12.3036,895.075));
1214 sendTouchUpdate(4002384, 77, QPointF(15.8885,896.849));
1215 sendTouchUpdate(4002406, 77, QPointF(18.4504,897.88));
1216 sendTouchUpdate(4002420, 77, QPointF(20.2429,898.149));
1217 sendTouchUpdate(4002439, 77, QPointF(20.9945,898.149));
1218 sendTouchUpdate(4002457, 77, QPointF(21.8819,898.149));
1219 sendTouchUpdate(4002480, 77, QPointF(22.7454,897.389));
1220 sendTouchUpdate(4002493, 77, QPointF(23.5456,896.589));
1221 sendTouchUpdate(4002511, 77, QPointF(24.5435,895.031));
1222 sendTouchUpdate(4002529, 77, QPointF(25.4271,892.32));
1223 sendTouchUpdate(4002548, 77, QPointF(26.3145,889.658));
1224 sendTouchUpdate(4002566, 77, QPointF(27.2004,886.999));
1225 sendTouchUpdate(4002584, 77, QPointF(28.035,885.048));
1226 sendTouchUpdate(4002603, 77, QPointF(29.9684,883.167));
1227 sendTouchUpdate(4002620, 77, QPointF(33.3591,881.403));
1228 sendTouchUpdate(4002639, 77, QPointF(44.1017,879.642));
1229 sendTouchUpdate(4002657, 77, QPointF(64.828,878.502));
1230 sendTouchUpdate(4002675, 77, QPointF(87.9486,878.157));
1231 sendTouchUpdate(4002693, 77, QPointF(112.96,877.742));
1232 sendTouchUpdate(4002711, 77, QPointF(138.903,877.157));
1233 sendTouchUpdate(4002729, 77, QPointF(163.204,877.157));
1234 sendTouchUpdate(4002747, 77, QPointF(182.127,877.157));
1235 sendTouchUpdate(4002765, 77, QPointF(194.478,877.657));
1236 sendTouchUpdate(4002785, 77, QPointF(201.474,878.508));
1237 sendTouchUpdate(4002803, 77, QPointF(204.855,879.401));
1238 sendTouchUpdate(4002822, 77, QPointF(206.616,880.281));
1239 sendTouchUpdate(4002839, 77, QPointF(207.115,880.906));
1240 sendTouchUpdate(4002894, 77, QPointF(206.865,881.184));
1241 sendTouchUpdate(4002912, 77, QPointF(206.865,882.143));
1242 sendTouchUpdate(4002930, 77, QPointF(206.865,883.106));
1243 sendTouchUpdate(4002949, 77, QPointF(206.526,883.994));
1244 sendTouchUpdate(4002967, 77, QPointF(205.866,884.88));
1245 sendTouchUpdate(4002985, 77, QPointF(205.866,885.766));
1246 sendTouchUpdate(4003005, 77, QPointF(205.866,886.654));
1247 sendTouchUpdate(4003021, 77, QPointF(205.366,887.537));
1248 sendTouchUpdate(4003039, 77, QPointF(204.592,888.428));
1249 sendTouchUpdate(4003050, 77, QPointF(204.367,888.653));
1250 sendTouchRelease(4003050, 77, QPointF(204.367,888.653));
1252 QCOMPARE(statusSpy->recognized(), true);
1254 delete statusSpy;
1257void tst_DirectionalDragArea::makoLeftEdgeDrag_movesSlightlyBackwardsOnStart()
1259 m_view->resize(768, 1280);
1260 QTest::qWait(300);
1262 DirectionalDragArea *edgeDragArea =
1263 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1264 QVERIFY(edgeDragArea != nullptr);
1265 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer());
1266 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1268 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1270 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1272 sendTouchPress(41097, 24, QPointF(13.9909,827.177));
1273 sendTouchUpdate(41120, 24, QPointF(19.2375,825.677));
1274 sendTouchUpdate(41138, 24, QPointF(18.4057,826.177));
1275 sendTouchUpdate(41161, 24, QPointF(20.1067,825.867));
1276 sendTouchUpdate(41177, 24, QPointF(21.8869,824.977));
1277 sendTouchUpdate(41193, 24, QPointF(24.7603,823.494));
1278 sendTouchUpdate(41211, 24, QPointF(28.3889,821.725));
1279 sendTouchUpdate(41229, 24, QPointF(32.2909,819.955));
1280 sendTouchUpdate(41247, 24, QPointF(38.2251,817.431));
1281 sendTouchUpdate(41266, 24, QPointF(52.4182,814.223));
1282 sendTouchUpdate(41284, 24, QPointF(85.8465,809.483));
1283 sendTouchUpdate(41302, 24, QPointF(126.091,802.741));
1284 sendTouchUpdate(41320, 24, QPointF(153.171,797.977));
1285 sendTouchUpdate(41338, 24, QPointF(170.565,795.077));
1286 sendTouchUpdate(41356, 24, QPointF(178.685,794.101));
1287 sendTouchUpdate(41375, 24, QPointF(183.706,793.225));
1288 sendTouchUpdate(41393, 24, QPointF(186.112,793.19));
1289 sendTouchUpdate(41411, 24, QPointF(187.634,793.19));
1290 sendTouchUpdate(41429, 24, QPointF(188.505,793.19));
1291 sendTouchUpdate(41532, 24, QPointF(187.816,793.19));
1292 sendTouchUpdate(41538, 24, QPointF(186.902,793.19));
1293 sendTouchUpdate(41557, 24, QPointF(186.01,793.19));
1294 sendTouchUpdate(41575, 24, QPointF(185.125,793.444));
1295 sendTouchUpdate(41593, 24, QPointF(184.229,793.69));
1296 sendTouchUpdate(41605, 24, QPointF(183.88,793.69));
1297 sendTouchRelease(41607, 24, QPointF(183.88,793.69));
1299 QCOMPARE(statusSpy->recognized(), true);
1301 delete statusSpy;
1304QTEST_MAIN(tst_DirectionalDragArea)
1306#include "tst_DirectionalDragArea.moc"