on ac4b821 help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp
709 lines 25 kB history raw
1/*
2 * Copyright (C) 2013 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>
23#include <DirectionalDragArea.h>
25#include "GestureTest.h"
27using namespace UbuntuGestures;
29class FakeTimer : public AbstractTimer
31 Q_OBJECT
32public:
33 FakeTimer(const SharedTimeSource &timeSource, QObject *parent = 0)
34 : UbuntuGestures::AbstractTimer(parent),
35 m_timeSource(timeSource)
36 {}
38 int interval() const override { return m_interval; }
39 void setInterval(int msecs) override { m_interval = msecs; }
40 void start() override {
41 AbstractTimer::start();
42 m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)m_interval;
43 }
45 void emitTimeout() {
46 m_nextTimeoutTime += m_interval;
47 Q_EMIT timeout();
48 }
50 qint64 nextTimeoutTime() const { return m_nextTimeoutTime; }
51private:
52 int m_interval;
53 SharedTimeSource m_timeSource;
54 qint64 m_nextTimeoutTime;
55};
57class FakeTimeSource : public UbuntuGestures::TimeSource
59public:
60 FakeTimeSource() { m_msecsSinceReference = 0; }
61 virtual qint64 msecsSinceReference() {return m_msecsSinceReference;}
62 qint64 m_msecsSinceReference;
63};
65class tst_DirectionalDragArea: public GestureTest
67 Q_OBJECT
68public:
69 tst_DirectionalDragArea();
70private Q_SLOTS:
71 void init(); // called right before each and every test function is executed
72 void cleanup(); // called right after each and every test function is executed
74 void edgeDrag();
75 void edgeDrag_data();
76 void dragWithShortDirectionChange();
77 void minSpeed();
78 void minSpeed_data();
79 void recognitionTimerUsage();
80 void maxSilenceTime();
81 void sceneXAndX();
82 void sceneYAndY();
83 void twoFingerTap();
84 void movingDDA();
85 void ignoreOldFinger();
87private:
88 void passTime(qint64 timeSpan);
89 FakeTimer *fakeTimer;
90 QSharedPointer<FakeTimeSource> fakeTimeSource;
91};
93tst_DirectionalDragArea::tst_DirectionalDragArea()
94 : GestureTest(QStringLiteral("tst_DirectionalDragArea.qml"))
98void tst_DirectionalDragArea::init()
100 GestureTest::init();
102 fakeTimeSource.reset(new FakeTimeSource);
103 fakeTimer = new FakeTimer(fakeTimeSource);
106void tst_DirectionalDragArea::cleanup()
108 delete fakeTimer;
109 fakeTimer = 0;
111 fakeTimeSource.reset();
113 GestureTest::cleanup();
116void tst_DirectionalDragArea::passTime(qint64 timeSpan)
118 qint64 finalTime = fakeTimeSource->m_msecsSinceReference + timeSpan;
120 if (fakeTimer->isRunning() && finalTime >= fakeTimer->nextTimeoutTime()) {
121 fakeTimeSource->m_msecsSinceReference = fakeTimer->nextTimeoutTime();
122 fakeTimer->emitTimeout();
124 qint64 timeSpanRemainder = finalTime - fakeTimeSource->m_msecsSinceReference;
125 if (timeSpanRemainder > 0) {
126 passTime(timeSpanRemainder);
127 }
128 } else {
129 fakeTimeSource->m_msecsSinceReference = finalTime;
130 }
133namespace {
134QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea, QQuickView *view)
136 switch (edgeDragArea->direction()) {
137 case Direction::Upwards:
138 return QPointF(view->width()/2.0f, view->height() - (edgeDragArea->height()/2.0f));
139 case Direction::Downwards:
140 return QPointF(view->width()/2.0f, edgeDragArea->height()/2.0f);
141 case Direction::Leftwards:
142 return QPointF(view->width() - (edgeDragArea->width()/2.0f), view->height()/2.0f);
143 default: // Direction::Rightwards:
144 return QPointF(edgeDragArea->width()/2.0f, view->height()/2.0f);
145 }
148QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea,
149 qreal wideningAngleMultiplier)
151 qreal angleRadians = edgeDragArea->wideningAngle() * wideningAngleMultiplier
152 * M_PI / 180.0;
154 qreal angleCos = qCos(angleRadians);
155 qreal angleSin = qSin(angleRadians);
157 switch (edgeDragArea->direction()) {
158 case Direction::Upwards:
159 return QPointF(angleSin, -angleCos);
160 case Direction::Downwards:
161 return QPointF(angleSin, angleCos);
162 case Direction::Leftwards:
163 return QPointF(-angleCos, angleSin);
164 default: // Direction::Rightwards:
165 return QPointF(angleCos, angleSin);
166 }
169QPointF createTouchDeviation(DirectionalDragArea *edgeDragArea)
171 qreal deviation = edgeDragArea->maxDeviation() * 0.8;
173 if (Direction::isHorizontal(edgeDragArea->direction())) {
174 return QPointF(0, deviation);
175 } else {
176 return QPointF(deviation, 0);
177 }
181void tst_DirectionalDragArea::edgeDrag()
183 QFETCH(QString, dragAreaObjectName);
184 QFETCH(qreal, wideningAngleMultiplier);
185 QFETCH(qreal, dragDistanceFactor);
186 QFETCH(bool, expectGestureRecognition);
188 DirectionalDragArea *edgeDragArea =
189 m_view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName);
190 QVERIFY(edgeDragArea != 0);
191 edgeDragArea->setRecognitionTimer(fakeTimer);
192 edgeDragArea->setTimeSource(fakeTimeSource);
194 QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
196 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
197 QPointF touchPoint = initialTouchPos;
199 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*dragDistanceFactor;
200 QPointF dragDirectionVector = calculateDirectionVector(edgeDragArea,
201 wideningAngleMultiplier);
202 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
203 QPointF touchMovement = dragDirectionVector * movementStepDistance;
204 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
205 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
207 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
209 QCOMPARE(draggingSpy.count(), 1);
210 QCOMPARE(edgeDragArea->dragging(), true);
212 if (wideningAngleMultiplier > 0) {
213 // go close to the border of the valid area for this touch point
214 // in order to make it easier to leave it by dragging at an angle
215 // slightly bigger than the widening angle
216 touchPoint += createTouchDeviation(edgeDragArea);
217 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
218 }
220 for (int i = 0; i < totalMovementSteps; ++i) {
221 touchPoint += touchMovement;
222 passTime(movementTimeStepMs);
223 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
224 }
226 if (expectGestureRecognition)
227 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
229 if (edgeDragArea->status() == DirectionalDragArea::WaitingForTouch) {
230 QCOMPARE(edgeDragArea->dragging(), false);
231 QCOMPARE(draggingSpy.count(), 2);
232 }
234 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
236 QCOMPARE(draggingSpy.count(), 2);
237 QCOMPARE(edgeDragArea->dragging(), false);
240void tst_DirectionalDragArea::edgeDrag_data()
242 QTest::addColumn<QString>("dragAreaObjectName");
243 QTest::addColumn<qreal>("wideningAngleMultiplier");
244 QTest::addColumn<qreal>("dragDistanceFactor");
245 QTest::addColumn<bool>("expectGestureRecognition");
247 QTest::newRow("rightwards, tiny drag")
248 << "hpDragArea" << 0.0 << 0.2 << false;
250 QTest::newRow("rightwards, straight drag")
251 << "hpDragArea" << 0.0 << 3.0 << true;
253 QTest::newRow("rightwards, diagonal drag")
254 << "hpDragArea" << 0.9 << 3.0 << true;
256 QTest::newRow("rightwards, overly diagonal drag")
257 << "hpDragArea" << 2.0 << 3.0 << false;
259 QTest::newRow("leftwards, tiny drag")
260 << "hnDragArea" << 0.0 << 0.2 << false;
262 QTest::newRow("leftwards, straight drag")
263 << "hnDragArea" << 0.0 << 3.0 << true;
265 QTest::newRow("leftwards, diagonal drag")
266 << "hnDragArea" << 0.9 << 3.0 << true;
268 QTest::newRow("downwards, tiny drag")
269 << "vpDragArea" << 0.0 << 0.2 << false;
271 QTest::newRow("downwards, straight drag")
272 << "vpDragArea" << 0.0 << 3.0 << true;
274 QTest::newRow("downwards, diagonal drag")
275 << "vpDragArea" << 0.9 << 3.0 << true;
277 QTest::newRow("upwards, tiny drag")
278 << "vnDragArea" << 0.0 << 0.2 << false;
280 QTest::newRow("upwards, straight drag")
281 << "vnDragArea" << 0.0 << 3.0 << true;
283 QTest::newRow("upwards, diagonal drag")
284 << "vnDragArea" << 0.9 << 3.0 << true;
286 QTest::newRow("upwards, overly diagonal drag")
287 << "vnDragArea" << 2.0 << 3.0 << false;
290/*
291 A directional drag should still be recognized if there is a momentaneous, small,
292 change in the direction of a drag. That should be accounted as input noise and
293 therefore ignored.
294 */
295void tst_DirectionalDragArea::dragWithShortDirectionChange()
297 DirectionalDragArea *edgeDragArea =
298 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
299 QVERIFY(edgeDragArea != 0);
300 edgeDragArea->setRecognitionTimer(fakeTimer);
301 edgeDragArea->setTimeSource(fakeTimeSource);
303 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
304 QPointF touchPoint = initialTouchPos;
306 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0;
307 QPointF dragDirectionVector(1.0, 0.0);
308 qreal touchStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
309 // make sure we are above minimum speed
310 int touchStepTimeMs = (touchStepDistance / (edgeDragArea->minSpeed() * 5.0f)) * 1000.0f;
311 QPointF touchMovement = dragDirectionVector * touchStepDistance;
313 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
315 // Move a bit in the proper direction
316 for (int i=0; i < 3; ++i) {
317 touchPoint += touchMovement;
318 passTime(touchStepTimeMs);
319 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
320 }
322 // Then a sudden and small movement to the opposite direction
323 touchPoint -= touchMovement*0.2;
324 passTime(touchStepTimeMs*0.2);
325 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
327 // And then resume movment in the correct direction until it crosses the distance and time
328 // thresholds.
329 do {
330 touchPoint += touchMovement;
331 passTime(touchStepTimeMs);
332 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
333 } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance
334 || fakeTimeSource->m_msecsSinceReference < (edgeDragArea->compositionTime() * 1.5f));
336 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
338 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
341/*
342 Checks that a gesture will be rejected if it's slower than minSpeed while
343 status is Undecided.
344 */
345void tst_DirectionalDragArea::minSpeed()
347 QFETCH(qreal, minSpeed);
348 QFETCH(qreal, speed);
349 QFETCH(int, expectedStatusAfterSpeedCheck);
351 DirectionalDragArea *edgeDragArea =
352 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
353 QVERIFY(edgeDragArea != 0);
354 edgeDragArea->setRecognitionTimer(fakeTimer);
355 edgeDragArea->setTimeSource(fakeTimeSource);
357 // A really long, unattainable, number. We don't want it getting recognized before
358 // the speed checks we want have been performed
359 edgeDragArea->setDistanceThreshold(500000);
361 edgeDragArea->setMinSpeed(minSpeed);
363 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
364 QPointF touchPoint = initialTouchPos;
366 QPointF dragDirectionVector(1.0, 0.0);
367 qint64 timeStepMsecs = 10;
368 qreal distanceStep = (speed / 1000.0f) * timeStepMsecs;
369 QPointF touchMovement = dragDirectionVector * distanceStep;
371 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
373 // Move for a while to ensure our speed check is performed a couple of times
374 for (int i=0; i < 20; ++i) {
375 touchPoint += touchMovement;
376 passTime(timeStepMsecs);
377 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
378 }
380 QCOMPARE((int)edgeDragArea->status(), expectedStatusAfterSpeedCheck);
383void tst_DirectionalDragArea::minSpeed_data()
385 QTest::addColumn<qreal>("minSpeed");
386 QTest::addColumn<qreal>("speed");
387 QTest::addColumn<int>("expectedStatusAfterSpeedCheck");
389 QTest::newRow("slower than minSpeed") << 100.0 << 50.0 << (int)DirectionalDragArea::WaitingForTouch;
390 QTest::newRow("faster than minSpeed") << 100.0 << 150.0 << (int)DirectionalDragArea::Undecided;
393/*
394 Checks that the recognition timer is started and stopped appropriately.
395 I.e., check that it's running only while gesture recognition is taking place
396 (status == Undecided)
397 */
398void tst_DirectionalDragArea::recognitionTimerUsage()
400 DirectionalDragArea *edgeDragArea =
401 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
402 QVERIFY(edgeDragArea != 0);
403 edgeDragArea->setRecognitionTimer(fakeTimer);
404 edgeDragArea->setTimeSource(fakeTimeSource);
406 // don't let it interfere with our test
407 edgeDragArea->setMinSpeed(0.0);
409 int timeStepMs = 5; // some arbitrary small value.
411 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
412 QPointF touchPoint = initialTouchPos;
414 QPointF dragDirectionVector(1.0, 0.0);
415 QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.2f);
417 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
418 QVERIFY(!fakeTimer->isRunning());
420 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
422 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
423 QVERIFY(fakeTimer->isRunning());
425 // Move beyond distance threshold and composition time to ensure recognition
426 while (fakeTimeSource->m_msecsSinceReference <= edgeDragArea->compositionTime() ||
427 (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->distanceThreshold()) {
429 QCOMPARE(edgeDragArea->status() == DirectionalDragArea::Undecided, fakeTimer->isRunning());
431 touchPoint += touchMovement;
432 passTime(timeStepMs);
433 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
434 }
436 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
437 QVERIFY(!fakeTimer->isRunning());
440/*
441 A gesture should be rejected if too much time has passed without any new input
442 events from it.
443 */
444void tst_DirectionalDragArea::maxSilenceTime()
446 DirectionalDragArea *edgeDragArea =
447 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
448 QVERIFY(edgeDragArea != 0);
449 edgeDragArea->setRecognitionTimer(fakeTimer);
450 edgeDragArea->setTimeSource(fakeTimeSource);
452 // Make sure this property is not disabled
453 edgeDragArea->setMaxSilenceTime(100);
455 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
456 QPointF touchPoint = initialTouchPos;
458 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
460 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
461 QVERIFY(fakeTimer->isRunning());
463 // Force timer to timeout until after maxSilenceTime has been reached
464 while (fakeTimeSource->m_msecsSinceReference < edgeDragArea->maxSilenceTime()) {
465 passTime(fakeTimer->interval());
466 }
468 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
471/*
472 Checks that it informs the X coordinate of the touch point in local and scene coordinates
473 correctly.
474 */
475void tst_DirectionalDragArea::sceneXAndX()
477 DirectionalDragArea *edgeDragArea =
478 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
479 QVERIFY(edgeDragArea != 0);
480 edgeDragArea->setRecognitionTimer(fakeTimer);
481 edgeDragArea->setTimeSource(fakeTimeSource);
483 QPointF touchScenePos(m_view->width() - (edgeDragArea->width()/2.0f), m_view->height()/2.0f);
485 QTest::touchEvent(m_view, m_device).press(0, touchScenePos.toPoint());
487 QSignalSpy touchXSpy(edgeDragArea, SIGNAL(touchXChanged(qreal)));
488 QSignalSpy touchSceneXSpy(edgeDragArea, SIGNAL(touchSceneXChanged(qreal)));
490 touchScenePos.rx() = m_view->width() / 2;
491 QTest::touchEvent(m_view, m_device).move(0, touchScenePos.toPoint());
493 QCOMPARE(touchXSpy.count(), 1);
494 QCOMPARE(touchSceneXSpy.count(), 1);
495 QCOMPARE(edgeDragArea->touchX(), touchScenePos.x() - edgeDragArea->x());
496 QCOMPARE(edgeDragArea->touchSceneX(), touchScenePos.x());
499/*
500 Checks that it informs the Y coordinate of the touch point in local and scene coordinates
501 correctly.
502 */
503void tst_DirectionalDragArea::sceneYAndY()
505 DirectionalDragArea *edgeDragArea =
506 m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
507 QVERIFY(edgeDragArea != 0);
508 edgeDragArea->setRecognitionTimer(fakeTimer);
509 edgeDragArea->setTimeSource(fakeTimeSource);
511 QPointF touchScenePos(m_view->width()/2.0f, m_view->height() - (edgeDragArea->height()/2.0f));
513 QTest::touchEvent(m_view, m_device).press(0, touchScenePos.toPoint());
515 QSignalSpy touchYSpy(edgeDragArea, SIGNAL(touchYChanged(qreal)));
516 QSignalSpy touchSceneYSpy(edgeDragArea, SIGNAL(touchSceneYChanged(qreal)));
518 touchScenePos.ry() = m_view->height() / 2;
519 QTest::touchEvent(m_view, m_device).move(0, touchScenePos.toPoint());
521 QCOMPARE(touchYSpy.count(), 1);
522 QCOMPARE(touchSceneYSpy.count(), 1);
523 QCOMPARE(edgeDragArea->touchY(), touchScenePos.y() - edgeDragArea->y());
524 QCOMPARE(edgeDragArea->touchSceneY(), touchScenePos.y());
527/*
528 Regression test for https://bugs.launchpad.net/bugs/1228336
530 Perform a quick two-finger double-tap and check that DirectionalDragArea properly
531 rejects those touch points. In the bug above it got confused and crashed.
532 */
533void tst_DirectionalDragArea::twoFingerTap()
535 DirectionalDragArea *edgeDragArea =
536 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
537 QVERIFY(edgeDragArea != 0);
538 edgeDragArea->setRecognitionTimer(fakeTimer);
539 edgeDragArea->setTimeSource(fakeTimeSource);
541 // Make touches evenly spaced along the edgeDragArea
542 QPoint touchAPos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
543 QPoint touchBPos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
545 qint64 timeStepMsecs = 5; // some arbitrary, small value
547 // Perform the first two-finger tap
548 // NB: using move() instead of stationary() becasue in the latter you cannot provide
549 // the touch position and therefore it's left with some garbage numbers.
550 QTest::touchEvent(m_view, m_device)
551 .press(0, touchAPos);
553 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
555 passTime(timeStepMsecs);
556 QTest::touchEvent(m_view, m_device)
557 .move(0, touchAPos)
558 .press(1, touchBPos);
560 // A second touch point appeared during recognition, reject immediately as this
561 // can't be a single-touch gesture anymore.
562 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
564 passTime(timeStepMsecs);
565 QTest::touchEvent(m_view, m_device)
566 .release(0, touchAPos)
567 .move(1, touchBPos);
569 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
571 passTime(timeStepMsecs);
572 QTest::touchEvent(m_view, m_device)
573 .release(1, touchBPos);
575 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
577 // Perform the second two-finger tap
579 passTime(timeStepMsecs);
580 QTest::touchEvent(m_view, m_device)
581 .press(0, touchAPos);
583 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
585 passTime(timeStepMsecs);
586 QTest::touchEvent(m_view, m_device)
587 .move(0, touchAPos)
588 .press(1, touchBPos);
590 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
592 passTime(timeStepMsecs);
593 QTest::touchEvent(m_view, m_device)
594 .release(0, touchAPos)
595 .move(1, touchBPos);
597 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
599 passTime(timeStepMsecs);
600 QTest::touchEvent(m_view, m_device)
601 .release(1, touchBPos);
603 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
606/*
607 Tests that gesture recognition works normally even if the DirectionalDragArea moves
608 during recognition.
609 This effectively means that we have to do gesture recognition with scene coordinates
610 instead of local item coordinates.
611 */
612void tst_DirectionalDragArea::movingDDA()
614 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
615 Q_ASSERT(rightwardsLauncher != 0);
617 DirectionalDragArea *edgeDragArea =
618 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
619 Q_ASSERT(edgeDragArea != 0);
620 edgeDragArea->setRecognitionTimer(fakeTimer);
621 edgeDragArea->setTimeSource(fakeTimeSource);
623 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, m_view);
624 QPointF touchPoint = initialTouchPos;
626 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
627 QPointF dragDirectionVector(1.0f, 0.0f);
629 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
630 QPointF touchMovement = dragDirectionVector * movementStepDistance;
631 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
632 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
634 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
636 // Move it far ahead along the direction of the gesture
637 // rightwardsLauncher is a parent of our DirectionalDragArea. So moving it will move our DDA
638 rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->distanceThreshold() * 5.0f);
640 for (int i = 0; i < totalMovementSteps; ++i) {
641 touchPoint += touchMovement;
642 passTime(movementTimeStepMs);
643 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
644 }
646 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
648 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
651/*
652 The presence of and old, rejected, touch point lying on the DirectionalDragArea
653 shouldn't impede the recognition of a gesture from a new touch point.
654 */
655void tst_DirectionalDragArea::ignoreOldFinger()
657 DirectionalDragArea *edgeDragArea =
658 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
659 Q_ASSERT(edgeDragArea != 0);
660 edgeDragArea->setRecognitionTimer(fakeTimer);
661 edgeDragArea->setTimeSource(fakeTimeSource);
663 // Make touches evenly spaced along the edgeDragArea
664 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
665 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
667 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
669 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
671 // leave it lying around for some time
672 passTime(qMax(edgeDragArea->maxSilenceTime(), edgeDragArea->compositionTime()) * 10);
674 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
676 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
677 QPointF dragDirectionVector(1.0f, 0.0f);
679 qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
680 QPointF touchMovement = dragDirectionVector * movementStepDistance;
681 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
682 int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
684 QTest::touchEvent(m_view, m_device)
685 .move(0, touch0Pos)
686 .press(1, touch1Pos);
688 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
690 for (int i = 0; i < totalMovementSteps; ++i) {
691 touch1Pos += touchMovement.toPoint();
692 passTime(movementTimeStepMs);
693 QTest::touchEvent(m_view, m_device)
694 .move(0, touch0Pos)
695 .move(1, touch1Pos);
696 }
698 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
700 QTest::touchEvent(m_view, m_device)
701 .move(0, touch0Pos)
702 .release(1, touch1Pos);
704 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
707QTEST_MAIN(tst_DirectionalDragArea)
709#include "tst_DirectionalDragArea.moc"