on db7effd help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp
379 lines 11 kB history raw
1/*
2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17#include <qpa/qwindowsysteminterface.h>
18#include <QtTest>
19#include <QQmlEngine>
20#include <QQuickView>
21#include <QSharedPointer>
22#include <private/qquickwindow_p.h>
24// C++ std lib
25#include <functional>
27#include <TouchGate.h>
28#include <TouchRegistry.h>
30#include "TestItem.h"
32class CandidateItem : public QQuickItem
34 Q_OBJECT
36public:
37 std::function<void(QTouchEvent*)> touchEventHandler;
39protected:
40 void touchEvent(QTouchEvent *event) override;
41};
43class tst_TouchGate : public QObject
45 Q_OBJECT
46public:
47 tst_TouchGate(QObject *parent = nullptr);
48private Q_SLOTS:
49 void initTestCase(); // will be called before the first test function is executed
50 void cleanupTestCase(); // will be called after the last test function was executed.
52 void init(); // called right before each and every test function is executed
53 void cleanup(); // called right after each and every test function is executed
55private:
56 void onlyCandidate_passThrough();
57 void holdsEventsUntilGainsOwnership();
58 void holdsEventsUntilGainsOwnership_data();
59 void holdsEventsUntilGainsOwnership_repeatingTouchId();
60 void dontDispacthToDisabledOrInvisibleTarget();
61 void dontDispacthToDisabledOrInvisibleTarget_data();
63private Q_SLOTS:
64 void disabledWhileHoldingTouch();
66private:
67 QQuickView *createView();
68 TouchRegistry *touchRegistry;
69 QQuickView *view;
70 QTouchDevice *device;
71};
73tst_TouchGate::tst_TouchGate(QObject *parent)
74 : QObject(parent)
75 , touchRegistry(nullptr)
76 , view(nullptr)
77 , device(nullptr)
81void tst_TouchGate::initTestCase()
83 if (!device) {
84 device = new QTouchDevice;
85 device->setType(QTouchDevice::TouchScreen);
86 QWindowSystemInterface::registerTouchDevice(device);
87 }
90void tst_TouchGate::cleanupTestCase()
94void tst_TouchGate::init()
96 touchRegistry = TouchRegistry::instance();
98 view = createView();
99 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
100 view->show();
101 QVERIFY(QTest::qWaitForWindowExposed(view));
102 QVERIFY(view->rootObject() != 0);
103 qApp->processEvents();
106void tst_TouchGate::cleanup()
108 delete view;
109 view = 0;
111 delete touchRegistry;
112 touchRegistry = nullptr;
115QQuickView *tst_TouchGate::createView()
117 QQuickView *window = new QQuickView(0);
118 window->setResizeMode(QQuickView::SizeRootObjectToView);
119 window->resize(720, 720);
121 return window;
124/*
125 Simplest case. TouchGate is the only candidate for the touch point, thus it
126 will instantly gain ownership causing the event to pass through it directly to
127 its child.
128 */
129void tst_TouchGate::onlyCandidate_passThrough()
131 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
132 Q_ASSERT(touchGate);
134 TestItem *testItem = new TestItem;
135 testItem->setWidth(touchGate->width());
136 testItem->setHeight(touchGate->height());
137 testItem->setParentItem(view->rootObject());
138 testItem->setZ(0.0);
140 touchGate->setZ(1.0);
141 touchGate->setTargetItem(testItem);
143 QTest::touchEvent(view, device)
144 .press(0, QPoint(100,100));
146 QCOMPARE(testItem->touchEventsReceived.count(), 1);
147 QVERIFY(touchGate->m_storedEvents.isEmpty());
150void tst_TouchGate::holdsEventsUntilGainsOwnership()
152 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
153 Q_ASSERT(touchGate);
154 QFETCH(bool, ownershipAfterTouchEnd);
156 TestItem *testItem = new TestItem;
157 testItem->setWidth(touchGate->width());
158 testItem->setHeight(touchGate->height());
159 testItem->setParentItem(view->rootObject());
160 testItem->setZ(0.0);
162 touchGate->setZ(1.0);
163 touchGate->setTargetItem(testItem);
165 // Put it in front of touchGate
166 CandidateItem *candidateItem = new CandidateItem;
167 candidateItem->setWidth(touchGate->width());
168 candidateItem->setHeight(touchGate->height());
169 candidateItem->setParentItem(view->rootObject());
170 candidateItem->setZ(2.0);
172 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
173 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
174 event->ignore();
175 };
177 QTest::touchEvent(view, device)
178 .press(0, QPoint(100,100));
180 QCOMPARE(testItem->touchEventsReceived.count(), 0);
182 QTest::touchEvent(view, device)
183 .move(0, QPoint(101,101));
185 QCOMPARE(testItem->touchEventsReceived.count(), 0);
187 if (!ownershipAfterTouchEnd) {
188 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
189 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
190 wp->flushDelayedTouchEvent();
191 // TouchGate should now open its flood gates and let testItem get all
192 // events from touch 0 produced so far
193 QCOMPARE(testItem->touchEventsReceived.count(), 2);
194 }
196 QTest::touchEvent(view, device)
197 .release(0, QPoint(101,101));
199 if (ownershipAfterTouchEnd) {
200 QCOMPARE(testItem->touchEventsReceived.count(), 0);
201 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
202 // TouchGate should now open its flood gates and let testItem get all
203 // events from touch 0 produced so far
204 }
206 QCOMPARE(testItem->touchEventsReceived.count(), 3);
208 QVERIFY(touchGate->m_storedEvents.isEmpty());
209 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
212void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
214 QTest::addColumn<bool>("ownershipAfterTouchEnd");
216 QTest::newRow("touch end after touch ownership") << false;
217 QTest::newRow("touch ownership after touch end") << true;
220/*
221 A touch point of id 0 starts and ends. Then the next touch point is also given
222 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
223 points.
225 Note that this won't be a problem with Mir as it assigns unique ids for the touch
226 points it produces.
227 */
228void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
230 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
231 Q_ASSERT(touchGate);
233 TestItem *testItem = new TestItem;
234 testItem->setWidth(touchGate->width());
235 testItem->setHeight(touchGate->height());
236 testItem->setParentItem(view->rootObject());
237 testItem->setZ(0.0);
239 touchGate->setZ(1.0);
240 touchGate->setTargetItem(testItem);
242 QTest::touchEvent(view, device)
243 .press(0, QPoint(100,100));
244 QTest::touchEvent(view, device)
245 .move(0, QPoint(101,101));
246 QTest::touchEvent(view, device)
247 .release(0, QPoint(101,101));
249 QCOMPARE(testItem->touchEventsReceived.count(), 3);
250 testItem->touchEventsReceived.clear();
252 // Put it in front of touchGate
253 CandidateItem *candidateItem = new CandidateItem;
254 candidateItem->setWidth(touchGate->width());
255 candidateItem->setHeight(touchGate->height());
256 candidateItem->setParentItem(view->rootObject());
257 candidateItem->setZ(2.0);
259 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
260 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
261 event->ignore();
262 };
264 // A brand new touch, but with the same id as the previous one
265 QTest::touchEvent(view, device)
266 .press(0, QPoint(200,200));
267 QTest::touchEvent(view, device)
268 .move(0, QPoint(201,201));
269 QTest::touchEvent(view, device)
270 .release(0, QPoint(201,201));
272 QCOMPARE(testItem->touchEventsReceived.count(), 0);
274 touchRegistry->requestTouchOwnership(0, candidateItem);
276 QCOMPARE(testItem->touchEventsReceived.count(), 0);
278 QVERIFY(touchGate->m_storedEvents.isEmpty());
281void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
283 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
284 Q_ASSERT(touchGate);
286 TestItem *testItem = new TestItem;
287 testItem->setWidth(touchGate->width());
288 testItem->setHeight(touchGate->height());
289 testItem->setParentItem(view->rootObject());
290 testItem->setZ(0.0);
292 QFETCH(bool, isEnabled);
293 testItem->setEnabled(isEnabled);
295 QFETCH(bool, isVisible);
296 testItem->setVisible(isVisible);
298 touchGate->setZ(1.0);
299 touchGate->setTargetItem(testItem);
301 QTest::touchEvent(view, device)
302 .press(0, QPoint(100,100));
304 QCOMPARE(testItem->touchEventsReceived.count(), 0);
305 QVERIFY(touchGate->m_storedEvents.isEmpty());
308void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
310 QTest::addColumn<bool>("isEnabled");
311 QTest::addColumn<bool>("isVisible");
313 QTest::newRow("disabled visible") << false << true;
314 QTest::newRow("enabled invisible") << true << false;
315 QTest::newRow("disabled invisible") << false << false;
318void tst_TouchGate::disabledWhileHoldingTouch()
320 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
321 Q_ASSERT(touchGate);
323 TestItem *testItem = new TestItem;
324 testItem->setWidth(touchGate->width());
325 testItem->setHeight(touchGate->height());
326 testItem->setParentItem(view->rootObject());
327 testItem->setZ(0.0);
329 touchGate->setZ(1.0);
330 touchGate->setTargetItem(testItem);
332 QTest::touchEvent(view, device)
333 .press(0, QPoint(100,100));
335 QCOMPARE(testItem->touchEventsReceived.count(), 1);
336 testItem->touchEventsReceived.clear();
338 touchGate->setEnabled(false);
340 QTest::touchEvent(view, device)
341 .move(0, QPoint(101,101));
343 // Nothing new came as TouchGate didn't even get it because it's disabled
344 QCOMPARE(testItem->touchEventsReceived.count(), 0);
346 touchGate->setEnabled(true);
348 QTest::touchEvent(view, device)
349 .move(0, QPoint(102,102));
351 QTest::touchEvent(view, device)
352 .release(0, QPoint(102,102));
354 // Nothing new came because TouchGate has already discarded touch 0
355 QCOMPARE(testItem->touchEventsReceived.count(), 0);
357 QTest::touchEvent(view, device)
358 .press(1, QPoint(200,200));
360 QCOMPARE(testItem->touchEventsReceived.count(), 1);
361 {
362 // it got only the new touch point.
363 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
364 QCOMPARE(touchEvent->touchPoints().count(), 1);
365 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
366 }
369///////////// CandidateItem /////////////////////////////////////////////////////////////
371void CandidateItem::touchEvent(QTouchEvent *event)
373 touchEventHandler(event);
377QTEST_MAIN(tst_TouchGate)
379#include "tst_TouchGate.moc"