@@ -22,6 +22,35 @@
23#include <DirectionalDragArea.h>
23#include <DirectionalDragArea.h>
25+class FakeTimer : public UbuntuGestures::AbstractTimer
29+ FakeTimer(QObject *parent = 0)
30+ : UbuntuGestures::AbstractTimer(parent),
34+ virtual int interval() const { return m_duration; }
35+ virtual void setInterval(int msecs) { m_duration = msecs; }
36+ virtual void start() { m_isRunning = true; }
37+ virtual void stop() { m_isRunning = false; }
39+ bool isRunning() const { return m_isRunning; }
40+ void emitTimeout() {Q_EMIT timeout();}
46+class FakeTimeSource : public AxisVelocityCalculator::TimeSource
49+ FakeTimeSource() { m_msecsSinceReference = 0; }
50+ virtual qint64 msecsSinceReference() {return m_msecsSinceReference;}
51+ qint64 m_msecsSinceReference;
25class tst_DirectionalDragArea: public QObject
54class tst_DirectionalDragArea: public QObject
@@ -31,13 +60,24 @@ private Q_SLOTS:
31 void initTestCase(); // will be called before the first test function is executed
60 void initTestCase(); // will be called before the first test function is executed
32 void cleanupTestCase(); // will be called after the last test function was executed.
61 void cleanupTestCase(); // will be called after the last test function was executed.
63+ void init(); // called right before each and every test function is executed
64+ void cleanup(); // called right after each and every test function is executed
34 void edgeDrag();
66 void edgeDrag();
35 void edgeDrag_data();
67 void edgeDrag_data();
36 void dragWithShortDirectionChange();
68 void dragWithShortDirectionChange();
70+ void minSpeed_data();
71+ void recognitionTimerUsage();
72+ void maxSilenceTime();
39 QQuickView *createView();
75 QQuickView *createView();
40 QTouchDevice *device;
77 QTouchDevice *device;
78+ FakeTimer *fakeTimer;
79+ FakeTimeSource *fakeTimeSource;
80+ AxisVelocityCalculator *velCalcWithFakeTiming;
43void tst_DirectionalDragArea::initTestCase()
83void tst_DirectionalDragArea::initTestCase()
@@ -47,12 +87,42 @@ void tst_DirectionalDragArea::initTestCase()
47 device->setType(QTouchDevice::TouchScreen);
87 device->setType(QTouchDevice::TouchScreen);
48 QWindowSystemInterface::registerTouchDevice(device);
88 QWindowSystemInterface::registerTouchDevice(device);
52void tst_DirectionalDragArea::cleanupTestCase()
94void tst_DirectionalDragArea::cleanupTestCase()
98+void tst_DirectionalDragArea::init()
100+ view = createView();
101+ view->setSource(QUrl::fromLocalFile("edgeDragExample.qml"));
103+ QVERIFY(QTest::qWaitForWindowExposed(view));
104+ QVERIFY(view->rootObject() != 0);
105+ qApp->processEvents();
107+ fakeTimer = new FakeTimer;
108+ fakeTimeSource = new FakeTimeSource;
109+ velCalcWithFakeTiming = new AxisVelocityCalculator(fakeTimeSource);
112+void tst_DirectionalDragArea::cleanup()
120+ // will bring fakeTimeSource down with it
121+ delete velCalcWithFakeTiming;
123+ velCalcWithFakeTiming = 0;
56QQuickView *tst_DirectionalDragArea::createView()
126QQuickView *tst_DirectionalDragArea::createView()
58 QQuickView *window = new QQuickView(0);
128 QQuickView *window = new QQuickView(0);
@@ -119,17 +189,11 @@ void tst_DirectionalDragArea::edgeDrag()
119 QFETCH(qreal, dragDistanceFactor);
189 QFETCH(qreal, dragDistanceFactor);
120 QFETCH(int, expectedGestureRecognition);
190 QFETCH(int, expectedGestureRecognition);
122− QQuickView *view = createView();
123− QScopedPointer<QQuickView> scope(view);
124− view->setSource(QUrl::fromLocalFile("edgeDragExample.qml"));
126− QVERIFY(QTest::qWaitForWindowExposed(view));
127− QVERIFY(view->rootObject() != 0);
128− qApp->processEvents();
130 DirectionalDragArea *edgeDragArea =
192 DirectionalDragArea *edgeDragArea =
131 view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName);
193 view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName);
132 QVERIFY(edgeDragArea != 0);
194 QVERIFY(edgeDragArea != 0);
195+ edgeDragArea->setRecognitionTimer(fakeTimer);
196+ edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
134 QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
198 QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
@@ -230,17 +294,11 @@ void tst_DirectionalDragArea::edgeDrag_data()
231void tst_DirectionalDragArea::dragWithShortDirectionChange()
295void tst_DirectionalDragArea::dragWithShortDirectionChange()
233− QQuickView *view = createView();
234− QScopedPointer<QQuickView> scope(view);
235− view->setSource(QUrl::fromLocalFile("edgeDragExample.qml"));
237− QVERIFY(QTest::qWaitForWindowExposed(view));
238− QVERIFY(view->rootObject() != 0);
239− qApp->processEvents();
241 DirectionalDragArea *edgeDragArea =
297 DirectionalDragArea *edgeDragArea =
242 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
298 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
243 QVERIFY(edgeDragArea != 0);
299 QVERIFY(edgeDragArea != 0);
300+ edgeDragArea->setRecognitionTimer(fakeTimer);
301+ edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
245 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
303 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
246 QPointF touchPoint = initialTouchPos;
304 QPointF touchPoint = initialTouchPos;
@@ -272,6 +330,140 @@ void tst_DirectionalDragArea::dragWithShortDirectionChange()
272 QTest::touchEvent(view, device).release(0, touchPoint.toPoint());
330 QTest::touchEvent(view, device).release(0, touchPoint.toPoint());
334+ Checks that a gesture will be rejected if it's slower than minSpeed while
335+ status is Undecided.
337+void tst_DirectionalDragArea::minSpeed()
339+ QFETCH(int, minSpeedMsecsDeviation);
340+ QFETCH(int, expectedStatusAfterSpeedCheck);
342+ DirectionalDragArea *edgeDragArea =
343+ view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
344+ QVERIFY(edgeDragArea != 0);
345+ edgeDragArea->setRecognitionTimer(fakeTimer);
346+ edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
348+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
349+ QPointF touchPoint = initialTouchPos;
351+ QPointF dragDirectionVector(1.0, 0.0);
352+ qreal distanceStep = edgeDragArea->distanceThreshold() * 0.1f;
353+ QPointF touchMovement = dragDirectionVector * distanceStep;
354+ qreal minSpeedMsecs = edgeDragArea->minSpeed() / 1000.0;
355+ qint64 timeStepMsecs = qFloor(distanceStep / minSpeedMsecs) + minSpeedMsecsDeviation;
357+ // if it fails it means the params set in the QML file are not in harmony with the values
358+ // used in this test
359+ Q_ASSERT(timeStepMsecs > 0);
361+ fakeTimeSource->m_msecsSinceReference = 0;
362+ QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
364+ // Move a bit in the proper direction
365+ for (int i=0; i < 4; ++i) {
366+ touchPoint += touchMovement;
367+ fakeTimeSource->m_msecsSinceReference += timeStepMsecs;
368+ QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
371+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
373+ // Force the periodic speed check.
374+ fakeTimer->emitTimeout();
376+ QCOMPARE((int)edgeDragArea->status(), expectedStatusAfterSpeedCheck);
379+void tst_DirectionalDragArea::minSpeed_data()
381+ QTest::addColumn<int>("minSpeedMsecsDeviation");
382+ QTest::addColumn<int>("expectedStatusAfterSpeedCheck");
384+ QTest::newRow("slower than minSpeed") << 20 << (int)DirectionalDragArea::Rejected;
385+ QTest::newRow("faster than minSpeed") << -20 << (int)DirectionalDragArea::Undecided;
389+ Checks that the recognition timer is started and stopped appropriately.
390+ I.e., check that it's running only while gesture recognition is taking place
391+ (status == Undecided)
393+void tst_DirectionalDragArea::recognitionTimerUsage()
395+ DirectionalDragArea *edgeDragArea =
396+ view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
397+ QVERIFY(edgeDragArea != 0);
398+ edgeDragArea->setRecognitionTimer(fakeTimer);
399+ edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
401+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
402+ QPointF touchPoint = initialTouchPos;
404+ QPointF dragDirectionVector(1.0, 0.0);
405+ QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.2f);
407+ QVERIFY(!fakeTimer->isRunning());
409+ QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
411+ QVERIFY(fakeTimer->isRunning());
413+ // Move a bit in the proper direction
414+ for (int i=0; i < 3; ++i) {
415+ touchPoint += touchMovement;
416+ QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
419+ QVERIFY(fakeTimer->isRunning());
421+ // Move beyond distance threshold
422+ touchPoint += 3*touchMovement;
423+ QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
425+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
427+ QVERIFY(!fakeTimer->isRunning());
431+ A gesture should be rejected if too much time has passed without any new input
434+void tst_DirectionalDragArea::maxSilenceTime()
436+ DirectionalDragArea *edgeDragArea =
437+ view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
438+ QVERIFY(edgeDragArea != 0);
439+ edgeDragArea->setRecognitionTimer(fakeTimer);
440+ edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
442+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
443+ QPointF touchPoint = initialTouchPos;
445+ fakeTimeSource->m_msecsSinceReference = 0;
446+ QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
448+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
450+ int neededTimeouts = qCeil((qreal)edgeDragArea->maxSilenceTime() / (qreal)fakeTimer->interval());
451+ if ((edgeDragArea->maxSilenceTime() % fakeTimer->interval()) == 0) {
455+ // Force the periodic speed check.
456+ for (int i = 0; i < neededTimeouts; ++i) {
457+ fakeTimer->emitTimeout();
459+ if (i < neededTimeouts - 1) {
460+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
464+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Rejected);
275QTEST_MAIN(tst_DirectionalDragArea)
467QTEST_MAIN(tst_DirectionalDragArea)
277#include "tst_DirectionalDragArea.moc"
469#include "tst_DirectionalDragArea.moc"