on 6ca9421 help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp
383 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#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
23 #include <private/qquickwindow_p.h>
24#endif
26// C++ std lib
27#include <functional>
29#include <TouchGate.h>
30#include <TouchRegistry.h>
32#include "TestItem.h"
34class CandidateItem : public QQuickItem
36 Q_OBJECT
38public:
39 std::function<void(QTouchEvent*)> touchEventHandler;
41protected:
42 void touchEvent(QTouchEvent *event) override;
43};
45class tst_TouchGate : public QObject
47 Q_OBJECT
48public:
49 tst_TouchGate(QObject *parent = nullptr);
50private Q_SLOTS:
51 void initTestCase(); // will be called before the first test function is executed
52 void cleanupTestCase(); // will be called after the last test function was executed.
54 void init(); // called right before each and every test function is executed
55 void cleanup(); // called right after each and every test function is executed
57private:
58 void onlyCandidate_passThrough();
59 void holdsEventsUntilGainsOwnership();
60 void holdsEventsUntilGainsOwnership_data();
61 void holdsEventsUntilGainsOwnership_repeatingTouchId();
62 void dontDispacthToDisabledOrInvisibleTarget();
63 void dontDispacthToDisabledOrInvisibleTarget_data();
65private Q_SLOTS:
66 void disabledWhileHoldingTouch();
68private:
69 QQuickView *createView();
70 TouchRegistry *touchRegistry;
71 QQuickView *view;
72 QTouchDevice *device;
73};
75tst_TouchGate::tst_TouchGate(QObject *parent)
76 : QObject(parent)
77 , touchRegistry(nullptr)
78 , view(nullptr)
79 , device(nullptr)
83void tst_TouchGate::initTestCase()
85 if (!device) {
86 device = new QTouchDevice;
87 device->setType(QTouchDevice::TouchScreen);
88 QWindowSystemInterface::registerTouchDevice(device);
89 }
92void tst_TouchGate::cleanupTestCase()
96void tst_TouchGate::init()
98 touchRegistry = TouchRegistry::instance();
100 view = createView();
101 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
102 view->show();
103 QVERIFY(QTest::qWaitForWindowExposed(view));
104 QVERIFY(view->rootObject() != 0);
105 qApp->processEvents();
108void tst_TouchGate::cleanup()
110 delete view;
111 view = 0;
113 delete touchRegistry;
114 touchRegistry = nullptr;
117QQuickView *tst_TouchGate::createView()
119 QQuickView *window = new QQuickView(0);
120 window->setResizeMode(QQuickView::SizeRootObjectToView);
121 window->resize(720, 720);
123 return window;
126/*
127 Simplest case. TouchGate is the only candidate for the touch point, thus it
128 will instantly gain ownership causing the event to pass through it directly to
129 its child.
130 */
131void tst_TouchGate::onlyCandidate_passThrough()
133 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
134 Q_ASSERT(touchGate);
136 TestItem *testItem = new TestItem;
137 testItem->setWidth(touchGate->width());
138 testItem->setHeight(touchGate->height());
139 testItem->setParentItem(view->rootObject());
140 testItem->setZ(0.0);
142 touchGate->setZ(1.0);
143 touchGate->setTargetItem(testItem);
145 QTest::touchEvent(view, device)
146 .press(0, QPoint(100,100));
148 QCOMPARE(testItem->touchEventsReceived.count(), 1);
149 QVERIFY(touchGate->m_storedEvents.isEmpty());
152void tst_TouchGate::holdsEventsUntilGainsOwnership()
154 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
155 Q_ASSERT(touchGate);
156 QFETCH(bool, ownershipAfterTouchEnd);
158 TestItem *testItem = new TestItem;
159 testItem->setWidth(touchGate->width());
160 testItem->setHeight(touchGate->height());
161 testItem->setParentItem(view->rootObject());
162 testItem->setZ(0.0);
164 touchGate->setZ(1.0);
165 touchGate->setTargetItem(testItem);
167 // Put it in front of touchGate
168 CandidateItem *candidateItem = new CandidateItem;
169 candidateItem->setWidth(touchGate->width());
170 candidateItem->setHeight(touchGate->height());
171 candidateItem->setParentItem(view->rootObject());
172 candidateItem->setZ(2.0);
174 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
175 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
176 event->ignore();
177 };
179 QTest::touchEvent(view, device)
180 .press(0, QPoint(100,100));
182 QCOMPARE(testItem->touchEventsReceived.count(), 0);
184 QTest::touchEvent(view, device)
185 .move(0, QPoint(101,101));
187 QCOMPARE(testItem->touchEventsReceived.count(), 0);
189 if (!ownershipAfterTouchEnd) {
190 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
191#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
192 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
193 wp->flushDelayedTouchEvent();
194#endif
195 // TouchGate should now open its flood gates and let testItem get all
196 // events from touch 0 produced so far
197 QCOMPARE(testItem->touchEventsReceived.count(), 2);
198 }
200 QTest::touchEvent(view, device)
201 .release(0, QPoint(101,101));
203 if (ownershipAfterTouchEnd) {
204 QCOMPARE(testItem->touchEventsReceived.count(), 0);
205 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
206 // TouchGate should now open its flood gates and let testItem get all
207 // events from touch 0 produced so far
208 }
210 QCOMPARE(testItem->touchEventsReceived.count(), 3);
212 QVERIFY(touchGate->m_storedEvents.isEmpty());
213 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
216void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
218 QTest::addColumn<bool>("ownershipAfterTouchEnd");
220 QTest::newRow("touch end after touch ownership") << false;
221 QTest::newRow("touch ownership after touch end") << true;
224/*
225 A touch point of id 0 starts and ends. Then the next touch point is also given
226 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
227 points.
229 Note that this won't be a problem with Mir as it assigns unique ids for the touch
230 points it produces.
231 */
232void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
234 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
235 Q_ASSERT(touchGate);
237 TestItem *testItem = new TestItem;
238 testItem->setWidth(touchGate->width());
239 testItem->setHeight(touchGate->height());
240 testItem->setParentItem(view->rootObject());
241 testItem->setZ(0.0);
243 touchGate->setZ(1.0);
244 touchGate->setTargetItem(testItem);
246 QTest::touchEvent(view, device)
247 .press(0, QPoint(100,100));
248 QTest::touchEvent(view, device)
249 .move(0, QPoint(101,101));
250 QTest::touchEvent(view, device)
251 .release(0, QPoint(101,101));
253 QCOMPARE(testItem->touchEventsReceived.count(), 3);
254 testItem->touchEventsReceived.clear();
256 // Put it in front of touchGate
257 CandidateItem *candidateItem = new CandidateItem;
258 candidateItem->setWidth(touchGate->width());
259 candidateItem->setHeight(touchGate->height());
260 candidateItem->setParentItem(view->rootObject());
261 candidateItem->setZ(2.0);
263 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
264 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
265 event->ignore();
266 };
268 // A brand new touch, but with the same id as the previous one
269 QTest::touchEvent(view, device)
270 .press(0, QPoint(200,200));
271 QTest::touchEvent(view, device)
272 .move(0, QPoint(201,201));
273 QTest::touchEvent(view, device)
274 .release(0, QPoint(201,201));
276 QCOMPARE(testItem->touchEventsReceived.count(), 0);
278 touchRegistry->requestTouchOwnership(0, candidateItem);
280 QCOMPARE(testItem->touchEventsReceived.count(), 0);
282 QVERIFY(touchGate->m_storedEvents.isEmpty());
285void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
287 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
288 Q_ASSERT(touchGate);
290 TestItem *testItem = new TestItem;
291 testItem->setWidth(touchGate->width());
292 testItem->setHeight(touchGate->height());
293 testItem->setParentItem(view->rootObject());
294 testItem->setZ(0.0);
296 QFETCH(bool, isEnabled);
297 testItem->setEnabled(isEnabled);
299 QFETCH(bool, isVisible);
300 testItem->setVisible(isVisible);
302 touchGate->setZ(1.0);
303 touchGate->setTargetItem(testItem);
305 QTest::touchEvent(view, device)
306 .press(0, QPoint(100,100));
308 QCOMPARE(testItem->touchEventsReceived.count(), 0);
309 QVERIFY(touchGate->m_storedEvents.isEmpty());
312void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
314 QTest::addColumn<bool>("isEnabled");
315 QTest::addColumn<bool>("isVisible");
317 QTest::newRow("disabled visible") << false << true;
318 QTest::newRow("enabled invisible") << true << false;
319 QTest::newRow("disabled invisible") << false << false;
322void tst_TouchGate::disabledWhileHoldingTouch()
324 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
325 Q_ASSERT(touchGate);
327 TestItem *testItem = new TestItem;
328 testItem->setWidth(touchGate->width());
329 testItem->setHeight(touchGate->height());
330 testItem->setParentItem(view->rootObject());
331 testItem->setZ(0.0);
333 touchGate->setZ(1.0);
334 touchGate->setTargetItem(testItem);
336 QTest::touchEvent(view, device)
337 .press(0, QPoint(100,100));
339 QCOMPARE(testItem->touchEventsReceived.count(), 1);
340 testItem->touchEventsReceived.clear();
342 touchGate->setEnabled(false);
344 QTest::touchEvent(view, device)
345 .move(0, QPoint(101,101));
347 // Nothing new came as TouchGate didn't even get it because it's disabled
348 QCOMPARE(testItem->touchEventsReceived.count(), 0);
350 touchGate->setEnabled(true);
352 QTest::touchEvent(view, device)
353 .move(0, QPoint(102,102));
355 QTest::touchEvent(view, device)
356 .release(0, QPoint(102,102));
358 // Nothing new came because TouchGate has already discarded touch 0
359 QCOMPARE(testItem->touchEventsReceived.count(), 0);
361 QTest::touchEvent(view, device)
362 .press(1, QPoint(200,200));
364 QCOMPARE(testItem->touchEventsReceived.count(), 1);
365 {
366 // it got only the new touch point.
367 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
368 QCOMPARE(touchEvent->touchPoints().count(), 1);
369 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
370 }
373///////////// CandidateItem /////////////////////////////////////////////////////////////
375void CandidateItem::touchEvent(QTouchEvent *event)
377 touchEventHandler(event);
381QTEST_MAIN(tst_TouchGate)
383#include "tst_TouchGate.moc"