on 239fdcc help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp
1250 lines 50 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>
25#include <DirectionalDragArea.h>
26#include <DirectionalDragArea_p.h>
27#include <TouchRegistry.h>
29#include "GestureTest.h"
31using namespace UbuntuGestures;
33// Because QSignalSpy(directionalDragArea, SIGNAL(DirectionalDragArea::Status)) simply
34// doesn't work
35class StatusSpy : public QObject {
36 Q_OBJECT
37public:
38 StatusSpy(DirectionalDragArea *edgeDragArea) {
39 m_recognized = false;
40 connect(edgeDragArea->d, &DirectionalDragAreaPrivate::statusChanged,
41 this, &StatusSpy::onStatusChanged);
42 }
43 bool recognized() {
44 return m_recognized;
45 }
47private Q_SLOTS:
48 void onStatusChanged(DirectionalDragAreaPrivate::Status status) {
49 m_recognized |= status == DirectionalDragAreaPrivate::Recognized;
50 }
52private:
53 bool m_recognized;
54};
56/*
57 QQuickMouseArea::canceled() signal is not registered in the meta object system.
58 So using a QSignalSpy to track it won't work. Thus the only way to connect to it
59 is using its method address directly.
60 */
61class MouseAreaSpy : public QObject
63 Q_OBJECT
64public:
65 MouseAreaSpy(QQuickMouseArea *mouseArea)
66 : canceledCount(0)
67 {
68 connect(mouseArea, &QQuickMouseArea::canceled,
69 this, &MouseAreaSpy::onMouseAreaCanceled);
70 }
72 int canceledCount;
74private Q_SLOTS:
75 void onMouseAreaCanceled() {
76 ++canceledCount;
77 }
78};
80class tst_DirectionalDragArea: public GestureTest
82 Q_OBJECT
83public:
84 tst_DirectionalDragArea();
85private Q_SLOTS:
86 void init() override; // called right before each and every test function is executed
88 void dragWithShortDirectionChange();
89 void recognitionTimerUsage();
90 void sceneXAndX();
91 void sceneYAndY();
92 void twoFingerTap();
93 void movingDDA();
94 void ignoreOldFinger();
95 void rotated();
96 void sceneDistance();
97 void sceneDistance_data();
98 void disabledWhileDragging();
99 void oneFingerDownFollowedByLateSecondFingerDown();
100 void givesUpWhenLosesTouch();
101 void threeFingerDrag();
102 void immediateRecognitionWhenConstraintsDisabled();
103 void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition();
104 void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data();
105 void gettingTouchOwnershipMakesMouseAreaBehindGetCanceled();
106 void interleavedTouches();
107 void makoRightEdgeDrag();
108 void makoRightEdgeDrag_verticalDownwards();
109 void makoLeftEdgeDrag_slowStart();
110 void makoLeftEdgeDrag_movesSlightlyBackwardsOnStart();
111};
113tst_DirectionalDragArea::tst_DirectionalDragArea()
114 : GestureTest(QStringLiteral("tst_DirectionalDragArea.qml"))
118void tst_DirectionalDragArea::init()
120 GestureTest::init();
122 // We shouldn't need the three lines below, but a compiz/unity7
123 // regression means we don't pass the test without them because
124 // the window doesn't have the proper size. Can be removed in the
125 // future if the regression is fixed and tests pass again
126 m_view->resize(m_view->rootObject()->width(), m_view->rootObject()->height());
127 QTRY_COMPARE(m_view->width(), (int)m_view->rootObject()->width());
128 QTRY_COMPARE(m_view->height(), (int)m_view->rootObject()->height());
131namespace {
132QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea)
134 QPointF localCenter(edgeDragArea->width() / 2., edgeDragArea->height() / 2.);
135 return edgeDragArea->mapToScene(localCenter);
139/*
140 A directional drag should still be recognized if there is a momentaneous, small,
141 change in the direction of a drag. That should be accounted as input noise and
142 therefore ignored.
143 */
144void tst_DirectionalDragArea::dragWithShortDirectionChange()
146 DirectionalDragArea *edgeDragArea =
147 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
148 QVERIFY(edgeDragArea != 0);
149 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
150 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
152 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
153 QPointF touchPoint = initialTouchPos;
155 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0;
156 QPointF dragDirectionVector(1.0, 0.0);
157 qreal touchStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
158 // make sure we are above maximum time
159 int touchStepTimeMs = edgeDragArea->d->maxTime / 20. ;
160 QPointF touchMovement = dragDirectionVector * touchStepDistance;
162 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
164 // Move a bit in the proper direction
165 for (int i=0; i < 3; ++i) {
166 touchPoint += touchMovement;
167 passTime(touchStepTimeMs);
168 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
169 }
171 // Then a sudden and small movement to the opposite direction
172 touchPoint -= touchMovement*0.2;
173 passTime(touchStepTimeMs*0.2);
174 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
176 // And then resume movment in the correct direction until it crosses the distance and time
177 // thresholds.
178 do {
179 touchPoint += touchMovement;
180 passTime(touchStepTimeMs);
181 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
182 } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance
183 || m_fakeTimerFactory->timeSource()->msecsSinceReference() < (edgeDragArea->d->compositionTime * 1.5f));
185 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
187 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
190/*
191 Checks that the recognition timer is started and stopped appropriately.
192 I.e., check that it's running only while gesture recognition is taking place
193 (status == Undecided)
194 */
195void tst_DirectionalDragArea::recognitionTimerUsage()
197 DirectionalDragArea *edgeDragArea =
198 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
199 QVERIFY(edgeDragArea != 0);
200 AbstractTimer *fakeTimer = m_fakeTimerFactory->createTimer();
201 edgeDragArea->d->setRecognitionTimer(fakeTimer);
202 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
204 int timeStepMs = 5; // some arbitrary small value.
206 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
207 QPointF touchPoint = initialTouchPos;
209 QPointF dragDirectionVector(1.0, 0.0);
210 QPointF touchMovement = dragDirectionVector * (edgeDragArea->d->distanceThreshold * 0.2f);
212 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
213 QVERIFY(!fakeTimer->isRunning());
215 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
217 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
218 QVERIFY(fakeTimer->isRunning());
220 // Move beyond distance threshold and composition time to ensure recognition
221 while (m_fakeTimerFactory->timeSource()->msecsSinceReference() <= edgeDragArea->d->compositionTime ||
222 (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->d->distanceThreshold) {
224 QCOMPARE(edgeDragArea->d->status == DirectionalDragAreaPrivate::Undecided, fakeTimer->isRunning());
226 touchPoint += touchMovement;
227 passTime(timeStepMs);
228 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
229 }
231 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
232 QVERIFY(!fakeTimer->isRunning());
235/*
236 Checks that it informs the X coordinate of the touch point in local and scene coordinates
237 correctly.
238 */
239void tst_DirectionalDragArea::sceneXAndX()
241 DirectionalDragArea *edgeDragArea =
242 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
243 QVERIFY(edgeDragArea != 0);
244 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
245 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
246 edgeDragArea->setImmediateRecognition(true);
248 QPointF touchScenePos(m_view->width() - (edgeDragArea->width()/2.0f), m_view->height()/2.0f);
250 sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos);
252 QSignalSpy touchXSpy(edgeDragArea, &DirectionalDragArea::touchXChanged);
253 QSignalSpy touchSceneXSpy(edgeDragArea, &DirectionalDragArea::touchSceneXChanged);
255 touchScenePos.rx() = m_view->width() / 2;
256 sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos);
258 QCOMPARE(touchXSpy.count(), 1);
259 QCOMPARE(touchSceneXSpy.count(), 1);
260 QCOMPARE(edgeDragArea->touchX(), touchScenePos.x() - edgeDragArea->x());
261 QCOMPARE(edgeDragArea->touchSceneX(), touchScenePos.x());
264/*
265 Checks that it informs the Y coordinate of the touch point in local and scene coordinates
266 correctly.
267 */
268void tst_DirectionalDragArea::sceneYAndY()
270 DirectionalDragArea *edgeDragArea =
271 m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
272 QVERIFY(edgeDragArea != 0);
273 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
274 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
275 edgeDragArea->setImmediateRecognition(true);
277 QPointF touchScenePos(m_view->width()/2.0f, m_view->height() - (edgeDragArea->height()/2.0f));
279 sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos);
281 QSignalSpy touchYSpy(edgeDragArea, &DirectionalDragArea::touchYChanged);
282 QSignalSpy touchSceneYSpy(edgeDragArea, &DirectionalDragArea::touchSceneYChanged);
284 touchScenePos.ry() = m_view->height() / 2;
285 sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos);
287 QCOMPARE(touchYSpy.count(), 1);
288 QCOMPARE(touchSceneYSpy.count(), 1);
289 QCOMPARE(edgeDragArea->touchY(), touchScenePos.y() - edgeDragArea->y());
290 QCOMPARE(edgeDragArea->touchSceneY(), touchScenePos.y());
293/*
294 Regression test for https://bugs.launchpad.net/bugs/1228336
296 Perform a quick two-finger double-tap and check that DirectionalDragArea properly
297 rejects those touch points. In the bug above it got confused and crashed.
298 */
299void tst_DirectionalDragArea::twoFingerTap()
301 DirectionalDragArea *edgeDragArea =
302 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
303 QVERIFY(edgeDragArea != 0);
304 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
305 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
307 // Make touches evenly spaced along the edgeDragArea
308 QPoint touchAPos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
309 QPoint touchBPos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
311 qint64 timeStepMsecs = 5; // some arbitrary, small value
313 // Perform the first two-finger tap
314 // NB: using move() instead of stationary() becasue in the latter you cannot provide
315 // the touch position and therefore it's left with some garbage numbers.
316 QTest::touchEvent(m_view, m_device)
317 .press(0, touchAPos);
319 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
321 passTime(timeStepMsecs);
322 QTest::touchEvent(m_view, m_device)
323 .move(0, touchAPos)
324 .press(1, touchBPos);
326 // A second touch point appeared during recognition, reject immediately as this
327 // can't be a single-touch gesture anymore.
328 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
330 passTime(timeStepMsecs);
331 QTest::touchEvent(m_view, m_device)
332 .release(0, touchAPos)
333 .move(1, touchBPos);
335 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
337 passTime(timeStepMsecs);
338 QTest::touchEvent(m_view, m_device)
339 .release(1, touchBPos);
341 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
343 // Perform the second two-finger tap
345 passTime(timeStepMsecs);
346 QTest::touchEvent(m_view, m_device)
347 .press(0, touchAPos);
349 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
351 passTime(timeStepMsecs);
352 QTest::touchEvent(m_view, m_device)
353 .move(0, touchAPos)
354 .press(1, touchBPos);
356 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
358 passTime(timeStepMsecs);
359 QTest::touchEvent(m_view, m_device)
360 .release(0, touchAPos)
361 .move(1, touchBPos);
363 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
365 passTime(timeStepMsecs);
366 QTest::touchEvent(m_view, m_device)
367 .release(1, touchBPos);
369 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
372/*
373 Tests that gesture recognition works normally even if the DirectionalDragArea moves
374 during recognition.
375 This effectively means that we have to do gesture recognition with scene coordinates
376 instead of local item coordinates.
377 */
378void tst_DirectionalDragArea::movingDDA()
380 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
381 Q_ASSERT(rightwardsLauncher != 0);
383 DirectionalDragArea *edgeDragArea =
384 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
385 Q_ASSERT(edgeDragArea != 0);
386 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
387 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
389 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
390 QPointF touchPoint = initialTouchPos;
392 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
393 QPointF dragDirectionVector(1.0f, 0.0f);
395 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
396 QPointF touchMovement = dragDirectionVector * movementStepDistance;
397 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
398 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
400 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
402 // Move it far ahead along the direction of the gesture
403 // rightwardsLauncher is a parent of our DirectionalDragArea. So moving it will move our DDA
404 rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->d->distanceThreshold * 5.0f);
406 for (int i = 0; i < totalMovementSteps; ++i) {
407 touchPoint += touchMovement;
408 passTime(movementTimeStepMs);
409 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
410 }
412 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
414 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
417/*
418 The presence of and old, rejected, touch point lying on the DirectionalDragArea
419 shouldn't impede the recognition of a gesture from a new touch point.
420 */
421void tst_DirectionalDragArea::ignoreOldFinger()
423 DirectionalDragArea *edgeDragArea =
424 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
425 Q_ASSERT(edgeDragArea != 0);
426 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
427 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
429 // Make touches evenly spaced along the edgeDragArea
430 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
431 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
433 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
435 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
437 // leave it lying around for some time
438 passTime(edgeDragArea->d->maxTime * 10);
440 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
442 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
443 QPointF dragDirectionVector(1.0f, 0.0f);
445 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
446 QPointF touchMovement = dragDirectionVector * movementStepDistance;
447 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
448 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
450 QTest::touchEvent(m_view, m_device)
451 .move(0, touch0Pos)
452 .press(1, touch1Pos);
454 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
456 for (int i = 0; i < totalMovementSteps; ++i) {
457 touch1Pos += touchMovement.toPoint();
458 passTime(movementTimeStepMs);
459 QTest::touchEvent(m_view, m_device)
460 .move(0, touch0Pos)
461 .move(1, touch1Pos);
462 }
464 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
466 QTest::touchEvent(m_view, m_device)
467 .move(0, touch0Pos)
468 .release(1, touch1Pos);
470 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
473/*
474 A Rightwards DDA that is rotated 90 degrees clockwise should recognize gestures
475 that are done downwards in scene coordinates. I.e. the gesture recognition direction
476 should be in local coordinates, not scene coordinates.
477 */
478void tst_DirectionalDragArea::rotated()
480 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
481 baseItem->setRotation(90.);
483 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
484 Q_ASSERT(rightwardsLauncher != 0);
486 DirectionalDragArea *edgeDragArea =
487 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
488 Q_ASSERT(edgeDragArea != 0);
489 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
490 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
492 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
493 QPointF touchPoint = initialTouchPos;
495 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
496 QPointF dragDirectionVector(0.0f, 1.0f);
498 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
499 QPointF touchMovement = dragDirectionVector * movementStepDistance;
500 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
501 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
503 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
505 for (int i = 0; i < totalMovementSteps; ++i) {
506 touchPoint += touchMovement;
507 passTime(movementTimeStepMs);
508 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
509 }
511 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
513 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
516void tst_DirectionalDragArea::sceneDistance()
518 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
519 QFETCH(qreal, rotation);
520 QFETCH(QPointF, dragDirectionVector);
521 baseItem->setRotation(rotation);
523 QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
524 Q_ASSERT(rightwardsLauncher != 0);
526 DirectionalDragArea *edgeDragArea =
527 rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
528 Q_ASSERT(edgeDragArea != 0);
529 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
530 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
532 // to disable the position smoothing so that we can more easily check sceneDistance values
533 edgeDragArea->setImmediateRecognition(true);
535 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
536 QPointF touchPoint = initialTouchPos;
538 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
540 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
541 QPointF touchMovement = dragDirectionVector * movementStepDistance;
542 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
543 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
545 qint64 timestamp = 0;
547 sendTouchPress(timestamp, 0, touchPoint);
549 for (int i = 0; i < totalMovementSteps; ++i) {
550 touchPoint += touchMovement;
551 timestamp += movementTimeStepMs;
552 sendTouchUpdate(timestamp, 0, touchPoint);
553 }
555 qreal actualDragDistance = ((qreal)totalMovementSteps) * movementStepDistance;
557 // DirectionalDragArea::sceneDistance() must match the actual drag distance as the
558 // drag was aligned with the gesture direction
559 // NB: qFuzzyCompare(), used internally by QCOMPARE(), is broken.
560 QVERIFY(qAbs(edgeDragArea->sceneDistance() - actualDragDistance) < 0.001);
562 timestamp += movementTimeStepMs;
563 sendTouchRelease(timestamp, 0, touchPoint);
566void tst_DirectionalDragArea::sceneDistance_data()
568 QTest::addColumn<qreal>("rotation");
569 QTest::addColumn<QPointF>("dragDirectionVector");
571 QTest::newRow("not rotated") << 0. << QPointF(1., 0.);
572 QTest::newRow("rotated by 90 degrees") << 90. << QPointF(0., 1.);
575/*
576 Regression test for https://bugs.launchpad.net/unity8/+bug/1276122
578 The bug:
579 If setting "enabled: false" while the DirectionalDragArea's (DDA) dragging
580 property is true, the DDA stays in that state and doesn't recover any more.
581*/
582void tst_DirectionalDragArea::disabledWhileDragging()
584 DirectionalDragArea *edgeDragArea =
585 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
586 Q_ASSERT(edgeDragArea != 0);
587 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
588 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
590 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
592 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
593 QPointF dragDirectionVector(1., 0.); // horizontal positive
595 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
596 QPointF touchMovement = dragDirectionVector * movementStepDistance;
597 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
598 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
600 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
602 for (int i = 0; i < totalMovementSteps; ++i) {
603 touchPoint += touchMovement;
604 passTime(movementTimeStepMs);
605 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
606 }
608 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
609 QCOMPARE(edgeDragArea->dragging(), true);
611 // disable the dragArea while it's being dragged.
612 edgeDragArea->setEnabled(false);
614 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
615 QCOMPARE(edgeDragArea->dragging(), false);
617 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
620void tst_DirectionalDragArea::oneFingerDownFollowedByLateSecondFingerDown()
622 DirectionalDragArea *edgeDragArea =
623 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
624 Q_ASSERT(edgeDragArea != 0);
625 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
626 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
628 // Disable some constraints we're not interested in
629 edgeDragArea->d->setMaxTime(60 * 1000);
631 // And ensure others have the values we want
632 edgeDragArea->d->compositionTime = 60;
634 // Put an item right behind edgeDragArea to receive the touches ignored by it
635 DummyItem *dummyItem = new DummyItem;
636 dummyItem->setParentItem(edgeDragArea->parentItem());
637 dummyItem->setX(edgeDragArea->x());
638 dummyItem->setY(edgeDragArea->y());
639 dummyItem->setZ(edgeDragArea->z() - 1.0);
640 dummyItem->setWidth(edgeDragArea->width());
641 dummyItem->setHeight(edgeDragArea->height());
643 // Make touches evenly spaced along the edgeDragArea
644 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
645 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
647 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
649 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
651 // We are now going to be way beyond compositionTime
652 passTime(edgeDragArea->d->compositionTime*3);
654 QTest::touchEvent(m_view, m_device)
655 .move(0, touch0Pos)
656 .press(1, touch1Pos);
658 // A new touch has come, but as it can't be composed with touch 0, it should be
659 // ignored/rejected by the DirectionalDragArea
660 // Therefore the last event received by dummyItem must have both touch points (0 and 1)
661 {
662 TouchMemento &touchMemento = dummyItem->touchEvents.last();
663 QCOMPARE(touchMemento.touchPoints.count(), 2);
664 QVERIFY(touchMemento.containsTouchWithId(0));
665 QVERIFY(touchMemento.containsTouchWithId(1));
666 }
668 passTime(30);
670 QTest::touchEvent(m_view, m_device)
671 .move(0, touch0Pos)
672 .move(1, touch1Pos);
674 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
676 passTime(5);
678 QTest::touchEvent(m_view, m_device)
679 .release(0, touch0Pos)
680 .move(1, touch1Pos);
682 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
684 passTime(5);
686 QTest::touchEvent(m_view, m_device)
687 .release(1, touch1Pos);
689 // Shouldn't be keepping info about touches that no longer exist or interest us
690 QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
692 delete dummyItem;
695void tst_DirectionalDragArea::givesUpWhenLosesTouch()
697 DirectionalDragArea *edgeDragArea =
698 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
699 Q_ASSERT(edgeDragArea != 0);
700 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
701 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
703 // Disable some constraints we're not interested in
704 edgeDragArea->d->setMaxTime(60 * 1000);
706 // Put an item right in front of edgeDragArea
707 DummyItem *dummyItem = new DummyItem(edgeDragArea->parentItem());
708 dummyItem->setX(edgeDragArea->x());
709 dummyItem->setY(edgeDragArea->y());
710 dummyItem->setZ(edgeDragArea->z() + 1.0);
711 dummyItem->setWidth(edgeDragArea->width());
712 dummyItem->setHeight(edgeDragArea->height());
714 QPoint touchPos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
716 dummyItem->touchEventHandler = [&](QTouchEvent *event) {
717 m_touchRegistry->addCandidateOwnerForTouch(0, dummyItem);
718 event->ignore();
719 };
721 QTest::touchEvent(m_view, m_device).press(0, touchPos);
723 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
725 m_touchRegistry->requestTouchOwnership(0, dummyItem);
727 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
729 dummyItem->grabTouchPoints({0});
730 dummyItem->touchEventHandler = [&](QTouchEvent *event) { event->accept(); };
732 passTime(5);
733 QTest::touchEvent(m_view, m_device).release(0, touchPos);
735 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
737 QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
740void tst_DirectionalDragArea::threeFingerDrag()
742 DirectionalDragArea *edgeDragArea =
743 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
744 Q_ASSERT(edgeDragArea != 0);
745 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
746 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
748 // Disable some constraints we're not interested in
749 edgeDragArea->d->setMaxTime(60 * 1000);
751 // And ensure others have the values we want
752 edgeDragArea->d->compositionTime = 60;
754 // Make touches evenly spaced along the edgeDragArea
755 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.25f);
756 QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.50f);
757 QPoint touch2Pos(edgeDragArea->width()/2.0f, m_view->height()*0.75f);
759 QTest::touchEvent(m_view, m_device)
760 .press(0, touch0Pos);
762 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
764 passTime(5);
765 QTest::touchEvent(m_view, m_device)
766 .move(0, touch0Pos)
767 .press(1, touch1Pos);
769 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
771 passTime(5);
772 QTest::touchEvent(m_view, m_device)
773 .move(0, touch0Pos)
774 .move(1, touch1Pos)
775 .press(2, touch2Pos);
777 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
779 passTime(10);
780 QTest::touchEvent(m_view, m_device)
781 .move(0, touch0Pos)
782 .move(1, touch1Pos)
783 .move(2, touch2Pos);
785 passTime(200);
786 QTest::touchEvent(m_view, m_device)
787 .move(0, touch0Pos)
788 .release(1, touch1Pos)
789 .move(2, touch2Pos);
791 passTime(10);
792 QTest::touchEvent(m_view, m_device)
793 .move(0, touch0Pos)
794 .release(2, touch2Pos);
796 passTime(5);
797 QTest::touchEvent(m_view, m_device)
798 .release(0, touch0Pos);
800 // Shouldn't be keepping info about touches that no longer exist or interest us
801 QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
804/*
805 If all the relevant gesture recognition constraints/parameters have been disabled,
806 it means that the gesture recognition itself has been disabled and DirectionalDragArea
807 will therefore work like a simple touch area, merely reporting touch movement.
808 */
809void tst_DirectionalDragArea::immediateRecognitionWhenConstraintsDisabled()
811 DirectionalDragArea *edgeDragArea =
812 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
813 Q_ASSERT(edgeDragArea != 0);
814 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
815 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
817 // Disable the minimum amount of constraints to ensure immediate recognition
818 edgeDragArea->d->setDistanceThreshold(0);
819 edgeDragArea->d->compositionTime = 0;
821 // Put an item right behind edgeDragArea to receive the touches ignored by it
822 DummyItem *dummyItem = new DummyItem;
823 dummyItem->setParentItem(edgeDragArea->parentItem());
824 dummyItem->setX(edgeDragArea->x());
825 dummyItem->setY(edgeDragArea->y());
826 dummyItem->setZ(edgeDragArea->z() - 1.0);
827 dummyItem->setWidth(edgeDragArea->width());
828 dummyItem->setHeight(edgeDragArea->height());
830 QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
832 QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
834 // check for immediate recognition
835 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
837 // and therefore it should have immediately grabbed the touch point,
838 // not letting it leak to items behind him.
839 QCOMPARE(dummyItem->touchEvents.count(), 0);
842void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition()
844 DirectionalDragArea *edgeDragArea =
845 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
846 Q_ASSERT(edgeDragArea != 0);
847 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
848 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
850 QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
852 // Move less than the minimum needed for the drag gesture recognition
853 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 0.5f;
854 QPointF dragDirectionVector(1., 0.); // horizontal positive
856 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
857 QPointF touchMovement = dragDirectionVector * movementStepDistance;
858 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
859 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 0.8f) / totalMovementSteps;
861 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
863 for (int i = 0; i < totalMovementSteps; ++i) {
864 touchPoint += touchMovement;
865 passTime(movementTimeStepMs);
866 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
867 }
869 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
871 // edgeDragArea should be an undecided candidate
872 {
873 auto touchInfo = m_touchRegistry->findTouchInfo(0);
874 QCOMPARE(touchInfo->candidates.size(), 1);
875 QCOMPARE(touchInfo->candidates.at(0).item.data(), edgeDragArea);
876 QCOMPARE(touchInfo->candidates.at(0).state, TouchRegistry::CandidateInfo::Undecided);
877 }
879 // disable the dragArea while it's still recognizing a possible drag gesture.
880 QFETCH(bool, disable);
881 if (disable) {
882 edgeDragArea->setEnabled(false);
883 } else {
884 edgeDragArea->setVisible(false);
885 }
887 // edgeDragArea should no longer be a candidate
888 {
889 auto touchInfo = m_touchRegistry->findTouchInfo(0);
890 QCOMPARE(touchInfo->candidates.size(), 0);
891 }
893 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
895 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
898void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data()
900 QTest::addColumn<bool>("disable");
902 QTest::newRow("disabled") << true;
903 QTest::newRow("invisible") << false;
906void tst_DirectionalDragArea::gettingTouchOwnershipMakesMouseAreaBehindGetCanceled()
908 DirectionalDragArea *edgeDragArea =
909 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
910 QVERIFY(edgeDragArea != nullptr);
911 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
912 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
914 QQuickMouseArea *mouseArea =
915 m_view->rootObject()->findChild<QQuickMouseArea*>("mouseArea");
916 QVERIFY(mouseArea != nullptr);
918 MouseAreaSpy mouseAreaSpy(mouseArea);
920 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
921 QPointF touchPoint = initialTouchPos;
923 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2;
924 QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
925 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
926 QPointF touchMovement = dragDirectionVector * movementStepDistance;
927 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
928 int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
930 QCOMPARE(mouseArea->pressed(), false);
932 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
934 // The TouchBegin passes through the DirectionalDragArea and reaches the MouseArea behind it,
935 // where it's converted to a MouseEvent by QQuickWindow and sent to the MouseArea which then
936 // accepts it. Making it get pressed.
937 QCOMPARE(mouseArea->pressed(), true);
938 QCOMPARE(mouseAreaSpy.canceledCount, 0);
940 for (int i = 0; i < totalMovementSteps; ++i) {
941 touchPoint += touchMovement;
942 passTime(movementTimeStepMs);
943 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
944 }
946 // As the DirectionalDragArea recognizes the gesture, it grabs the touch from the MouseArea,
947 // which should make the MouseArea get a cancelation event, which will then cause it to
948 // reset its state (going back to "unpressed"/"released").
949 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
950 QCOMPARE(mouseArea->pressed(), false);
951 QCOMPARE(mouseAreaSpy.canceledCount, 1);
953 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
956void tst_DirectionalDragArea::interleavedTouches()
958 DirectionalDragArea *edgeDragArea =
959 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
960 QVERIFY(edgeDragArea != 0);
961 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
962 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
964 QPointF touch0 = edgeDragArea->mapToScene(
965 QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.3));
967 qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2;
968 QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
969 qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
970 QPointF touchMovement = dragDirectionVector * movementStepDistance;
971 int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
972 int movementTimeStepMs = (edgeDragArea->d->maxTime * 0.4f) / totalMovementSteps;
974 QTest::touchEvent(m_view, m_device).press(0, touch0.toPoint());
975 for (int i = 0; i < totalMovementSteps; ++i) {
976 touch0 += touchMovement;
977 passTime(movementTimeStepMs);
978 QTest::touchEvent(m_view, m_device).move(0, touch0.toPoint());
979 }
980 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
982 QPointF touch1 = edgeDragArea->mapToScene(
983 QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.6));
985 QTest::touchEvent(m_view, m_device)
986 .move(0, touch0.toPoint())
987 .press(1, touch1.toPoint());
989 touch1 += touchMovement;
990 passTime(movementTimeStepMs);
991 QTest::touchEvent(m_view, m_device)
992 .move(0, touch0.toPoint())
993 .move(1, touch1.toPoint());
995 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
997 QTest::touchEvent(m_view, m_device)
998 .release(0, touch0.toPoint())
999 .move(1, touch1.toPoint());
1001 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1003 touch1 += touchMovement;
1004 passTime(movementTimeStepMs);
1005 QTest::touchEvent(m_view, m_device)
1006 .move(1, touch1.toPoint());
1008 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1010 QPointF touch2 = edgeDragArea->mapToScene(
1011 QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.9));
1013 passTime(edgeDragArea->d->compositionTime + movementTimeStepMs);
1014 QTest::touchEvent(m_view, m_device)
1015 .move(1, touch1.toPoint())
1016 .press(2, touch2.toPoint());
1018 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
1019 QCOMPARE(edgeDragArea->d->touchId, 2);
1021 touch2 += touchMovement;
1022 passTime(movementTimeStepMs);
1023 QTest::touchEvent(m_view, m_device)
1024 .move(1, touch1.toPoint())
1025 .move(2, touch2.toPoint());
1027 touch1 += touchMovement;
1028 passTime(movementTimeStepMs);
1029 QTest::touchEvent(m_view, m_device)
1030 .move(1, touch1.toPoint())
1031 .move(2, touch2.toPoint());
1033 passTime(movementTimeStepMs);
1034 QTest::touchEvent(m_view, m_device)
1035 .release(1, touch1.toPoint())
1036 .move(2, touch2.toPoint());
1038 passTime(movementTimeStepMs);
1039 QTest::touchEvent(m_view, m_device)
1040 .release(2, touch2.toPoint());
1042 QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1046 A valid right-edge drag performed on mako
1047 */
1048void tst_DirectionalDragArea::makoRightEdgeDrag()
1050 m_view->resize(768, 1280);
1051 QTest::qWait(300);
1053 DirectionalDragArea *edgeDragArea =
1054 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1055 QVERIFY(edgeDragArea != nullptr);
1056 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1057 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1059 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1061 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1063 sendTouchPress(319744, 0, QPointF(767.001, 719.719));
1064 sendTouchUpdate(319765, 0, QPointF(765.744,729.973));
1065 sendTouchUpdate(319784, 0, QPointF(740.879,752.182));
1066 sendTouchUpdate(319803, 0, QPointF(689.698,795.795));
1067 sendTouchUpdate(319826, 0, QPointF(616.978,856.212));
1068 sendTouchUpdate(319845, 0, QPointF(558.769,906.157));
1069 sendTouchUpdate(319859, 0, QPointF(513.219,945.266));
1070 sendTouchUpdate(319878, 0, QPointF(481.31,975.496));
1071 sendTouchUpdate(319902, 0, QPointF(460.016,997.439));
1072 sendTouchUpdate(319920, 0, QPointF(449.761,1008.6));
1073 sendTouchUpdate(319929, 0, QPointF(445.891,1012.42));
1074 sendTouchUpdate(319947, 0, QPointF(444.884,1013.93));
1075 sendTouchUpdate(319965, 0, QPointF(444.461,1014.35));
1076 sendTouchUpdate(320057, 0, QPointF(444.71,1013.56));
1077 sendTouchUpdate(320138, 0, QPointF(445.434,1013.6));
1078 sendTouchUpdate(320154, 0, QPointF(446.338,1012.98));
1079 sendTouchUpdate(320171, 0, QPointF(447.232,1012.08));
1080 sendTouchRelease(320171, 0, QPointF(447.232,1012.08));
1082 QCOMPARE(statusSpy->recognized(), true);
1084 delete statusSpy;
1088 A vertical, downwards swipe performed on mako near its right edge.
1090 The DirectionalDragArea on the right edge must not recognize this
1091 gesture.
1092 */
1093void tst_DirectionalDragArea::makoRightEdgeDrag_verticalDownwards()
1095 m_view->resize(768, 1280);
1096 QTest::qWait(300);
1098 DirectionalDragArea *edgeDragArea =
1099 m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1100 QVERIFY(edgeDragArea != nullptr);
1101 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1102 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1104 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1106 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1108 sendTouchPress(12012445, 26, QPointF(767.001,461.82));
1109 sendTouchUpdate(12012472, 26, QPointF(767.001,462.569));
1110 sendTouchUpdate(12012528, 26, QPointF(767.001,463.334));
1111 sendTouchUpdate(12012546, 26, QPointF(767.001,466.856));
1112 sendTouchUpdate(12012571, 26, QPointF(767.001,473.291));
1113 sendTouchUpdate(12012587, 26, QPointF(767.001,487.31));
1114 sendTouchUpdate(12012604, 26, QPointF(765.364,507.521));
1115 sendTouchUpdate(12012618, 26, QPointF(765.364,507.521));
1116 sendTouchUpdate(12012627, 26, QPointF(762.642,534.317));
1117 sendTouchUpdate(12012655, 26, QPointF(760.846,573.406));
1118 sendTouchUpdate(12012667, 26, QPointF(759.838,625.295));
1119 sendTouchUpdate(12012675, 26, QPointF(758.875,703.207));
1120 sendTouchUpdate(12012696, 26, QPointF(761.52,777.015));
1121 sendTouchUpdate(12012713, 26, QPointF(765.659,835.591));
1122 sendTouchUpdate(12012731, 26, QPointF(766.778,883.206));
1123 sendTouchUpdate(12012748, 26, QPointF(767.001,922.937));
1124 sendTouchUpdate(12012779, 26, QPointF(767.001,967.558));
1125 sendTouchUpdate(12012798, 26, QPointF(767.001,1006.12));
1126 sendTouchUpdate(12012809, 26, QPointF(767.001,1033.1));
1127 sendTouchRelease(12012810, 26, QPointF(767.001,1033.1));
1129 QCOMPARE(statusSpy->recognized(), false);
1131 delete statusSpy;
1135 A valid left-edge drag performed on mako. This one starts a bit slow than speeds up
1136 */
1137void tst_DirectionalDragArea::makoLeftEdgeDrag_slowStart()
1139 m_view->resize(768, 1280);
1140 QTest::qWait(300);
1142 DirectionalDragArea *edgeDragArea =
1143 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1144 QVERIFY(edgeDragArea != nullptr);
1145 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1146 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1148 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1150 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1152 sendTouchPress(4002267, 77, QPointF(0,885.154));
1153 sendTouchUpdate(4002275, 77, QPointF(0,886.214));
1154 sendTouchUpdate(4002311, 77, QPointF(1.09568,887.75));
1155 sendTouchUpdate(4002329, 77, QPointF(3.53647,890.191));
1156 sendTouchUpdate(4002347, 77, QPointF(7.87434,892.879));
1157 sendTouchUpdate(4002366, 77, QPointF(12.3036,895.075));
1158 sendTouchUpdate(4002384, 77, QPointF(15.8885,896.849));
1159 sendTouchUpdate(4002406, 77, QPointF(18.4504,897.88));
1160 sendTouchUpdate(4002420, 77, QPointF(20.2429,898.149));
1161 sendTouchUpdate(4002439, 77, QPointF(20.9945,898.149));
1162 sendTouchUpdate(4002457, 77, QPointF(21.8819,898.149));
1163 sendTouchUpdate(4002480, 77, QPointF(22.7454,897.389));
1164 sendTouchUpdate(4002493, 77, QPointF(23.5456,896.589));
1165 sendTouchUpdate(4002511, 77, QPointF(24.5435,895.031));
1166 sendTouchUpdate(4002529, 77, QPointF(25.4271,892.32));
1167 sendTouchUpdate(4002548, 77, QPointF(26.3145,889.658));
1168 sendTouchUpdate(4002566, 77, QPointF(27.2004,886.999));
1169 sendTouchUpdate(4002584, 77, QPointF(28.035,885.048));
1170 sendTouchUpdate(4002603, 77, QPointF(29.9684,883.167));
1171 sendTouchUpdate(4002620, 77, QPointF(33.3591,881.403));
1172 sendTouchUpdate(4002639, 77, QPointF(44.1017,879.642));
1173 sendTouchUpdate(4002657, 77, QPointF(64.828,878.502));
1174 sendTouchUpdate(4002675, 77, QPointF(87.9486,878.157));
1175 sendTouchUpdate(4002693, 77, QPointF(112.96,877.742));
1176 sendTouchUpdate(4002711, 77, QPointF(138.903,877.157));
1177 sendTouchUpdate(4002729, 77, QPointF(163.204,877.157));
1178 sendTouchUpdate(4002747, 77, QPointF(182.127,877.157));
1179 sendTouchUpdate(4002765, 77, QPointF(194.478,877.657));
1180 sendTouchUpdate(4002785, 77, QPointF(201.474,878.508));
1181 sendTouchUpdate(4002803, 77, QPointF(204.855,879.401));
1182 sendTouchUpdate(4002822, 77, QPointF(206.616,880.281));
1183 sendTouchUpdate(4002839, 77, QPointF(207.115,880.906));
1184 sendTouchUpdate(4002894, 77, QPointF(206.865,881.184));
1185 sendTouchUpdate(4002912, 77, QPointF(206.865,882.143));
1186 sendTouchUpdate(4002930, 77, QPointF(206.865,883.106));
1187 sendTouchUpdate(4002949, 77, QPointF(206.526,883.994));
1188 sendTouchUpdate(4002967, 77, QPointF(205.866,884.88));
1189 sendTouchUpdate(4002985, 77, QPointF(205.866,885.766));
1190 sendTouchUpdate(4003005, 77, QPointF(205.866,886.654));
1191 sendTouchUpdate(4003021, 77, QPointF(205.366,887.537));
1192 sendTouchUpdate(4003039, 77, QPointF(204.592,888.428));
1193 sendTouchUpdate(4003050, 77, QPointF(204.367,888.653));
1194 sendTouchRelease(4003050, 77, QPointF(204.367,888.653));
1196 QCOMPARE(statusSpy->recognized(), true);
1198 delete statusSpy;
1201void tst_DirectionalDragArea::makoLeftEdgeDrag_movesSlightlyBackwardsOnStart()
1203 m_view->resize(768, 1280);
1204 QTest::qWait(300);
1206 DirectionalDragArea *edgeDragArea =
1207 m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1208 QVERIFY(edgeDragArea != nullptr);
1209 edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1210 edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1212 edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1214 StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1216 sendTouchPress(41097, 24, QPointF(13.9909,827.177));
1217 sendTouchUpdate(41120, 24, QPointF(19.2375,825.677));
1218 sendTouchUpdate(41138, 24, QPointF(18.4057,826.177));
1219 sendTouchUpdate(41161, 24, QPointF(20.1067,825.867));
1220 sendTouchUpdate(41177, 24, QPointF(21.8869,824.977));
1221 sendTouchUpdate(41193, 24, QPointF(24.7603,823.494));
1222 sendTouchUpdate(41211, 24, QPointF(28.3889,821.725));
1223 sendTouchUpdate(41229, 24, QPointF(32.2909,819.955));
1224 sendTouchUpdate(41247, 24, QPointF(38.2251,817.431));
1225 sendTouchUpdate(41266, 24, QPointF(52.4182,814.223));
1226 sendTouchUpdate(41284, 24, QPointF(85.8465,809.483));
1227 sendTouchUpdate(41302, 24, QPointF(126.091,802.741));
1228 sendTouchUpdate(41320, 24, QPointF(153.171,797.977));
1229 sendTouchUpdate(41338, 24, QPointF(170.565,795.077));
1230 sendTouchUpdate(41356, 24, QPointF(178.685,794.101));
1231 sendTouchUpdate(41375, 24, QPointF(183.706,793.225));
1232 sendTouchUpdate(41393, 24, QPointF(186.112,793.19));
1233 sendTouchUpdate(41411, 24, QPointF(187.634,793.19));
1234 sendTouchUpdate(41429, 24, QPointF(188.505,793.19));
1235 sendTouchUpdate(41532, 24, QPointF(187.816,793.19));
1236 sendTouchUpdate(41538, 24, QPointF(186.902,793.19));
1237 sendTouchUpdate(41557, 24, QPointF(186.01,793.19));
1238 sendTouchUpdate(41575, 24, QPointF(185.125,793.444));
1239 sendTouchUpdate(41593, 24, QPointF(184.229,793.69));
1240 sendTouchUpdate(41605, 24, QPointF(183.88,793.69));
1241 sendTouchRelease(41607, 24, QPointF(183.88,793.69));
1243 QCOMPARE(statusSpy->recognized(), true);
1245 delete statusSpy;
1248QTEST_MAIN(tst_DirectionalDragArea)
1250#include "tst_DirectionalDragArea.moc"