on 1bc5ffd help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp
384 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);
122 window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
124 return window;
127/*
128 Simplest case. TouchGate is the only candidate for the touch point, thus it
129 will instantly gain ownership causing the event to pass through it directly to
130 its child.
131 */
132void tst_TouchGate::onlyCandidate_passThrough()
134 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
135 Q_ASSERT(touchGate);
137 TestItem *testItem = new TestItem;
138 testItem->setWidth(touchGate->width());
139 testItem->setHeight(touchGate->height());
140 testItem->setParentItem(view->rootObject());
141 testItem->setZ(0.0);
143 touchGate->setZ(1.0);
144 touchGate->setTargetItem(testItem);
146 QTest::touchEvent(view, device)
147 .press(0, QPoint(100,100));
149 QCOMPARE(testItem->touchEventsReceived.count(), 1);
150 QVERIFY(touchGate->m_storedEvents.isEmpty());
153void tst_TouchGate::holdsEventsUntilGainsOwnership()
155 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
156 Q_ASSERT(touchGate);
157 QFETCH(bool, ownershipAfterTouchEnd);
159 TestItem *testItem = new TestItem;
160 testItem->setWidth(touchGate->width());
161 testItem->setHeight(touchGate->height());
162 testItem->setParentItem(view->rootObject());
163 testItem->setZ(0.0);
165 touchGate->setZ(1.0);
166 touchGate->setTargetItem(testItem);
168 // Put it in front of touchGate
169 CandidateItem *candidateItem = new CandidateItem;
170 candidateItem->setWidth(touchGate->width());
171 candidateItem->setHeight(touchGate->height());
172 candidateItem->setParentItem(view->rootObject());
173 candidateItem->setZ(2.0);
175 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
176 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
177 event->ignore();
178 };
180 QTest::touchEvent(view, device)
181 .press(0, QPoint(100,100));
183 QCOMPARE(testItem->touchEventsReceived.count(), 0);
185 QTest::touchEvent(view, device)
186 .move(0, QPoint(101,101));
188 QCOMPARE(testItem->touchEventsReceived.count(), 0);
190 if (!ownershipAfterTouchEnd) {
191 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
192#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
193 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
194 wp->flushDelayedTouchEvent();
195#endif
196 // TouchGate should now open its flood gates and let testItem get all
197 // events from touch 0 produced so far
198 QCOMPARE(testItem->touchEventsReceived.count(), 2);
199 }
201 QTest::touchEvent(view, device)
202 .release(0, QPoint(101,101));
204 if (ownershipAfterTouchEnd) {
205 QCOMPARE(testItem->touchEventsReceived.count(), 0);
206 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
207 // TouchGate should now open its flood gates and let testItem get all
208 // events from touch 0 produced so far
209 }
211 QCOMPARE(testItem->touchEventsReceived.count(), 3);
213 QVERIFY(touchGate->m_storedEvents.isEmpty());
214 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
217void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
219 QTest::addColumn<bool>("ownershipAfterTouchEnd");
221 QTest::newRow("touch end after touch ownership") << false;
222 QTest::newRow("touch ownership after touch end") << true;
225/*
226 A touch point of id 0 starts and ends. Then the next touch point is also given
227 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
228 points.
230 Note that this won't be a problem with Mir as it assigns unique ids for the touch
231 points it produces.
232 */
233void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
235 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
236 Q_ASSERT(touchGate);
238 TestItem *testItem = new TestItem;
239 testItem->setWidth(touchGate->width());
240 testItem->setHeight(touchGate->height());
241 testItem->setParentItem(view->rootObject());
242 testItem->setZ(0.0);
244 touchGate->setZ(1.0);
245 touchGate->setTargetItem(testItem);
247 QTest::touchEvent(view, device)
248 .press(0, QPoint(100,100));
249 QTest::touchEvent(view, device)
250 .move(0, QPoint(101,101));
251 QTest::touchEvent(view, device)
252 .release(0, QPoint(101,101));
254 QCOMPARE(testItem->touchEventsReceived.count(), 3);
255 testItem->touchEventsReceived.clear();
257 // Put it in front of touchGate
258 CandidateItem *candidateItem = new CandidateItem;
259 candidateItem->setWidth(touchGate->width());
260 candidateItem->setHeight(touchGate->height());
261 candidateItem->setParentItem(view->rootObject());
262 candidateItem->setZ(2.0);
264 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
265 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
266 event->ignore();
267 };
269 // A brand new touch, but with the same id as the previous one
270 QTest::touchEvent(view, device)
271 .press(0, QPoint(200,200));
272 QTest::touchEvent(view, device)
273 .move(0, QPoint(201,201));
274 QTest::touchEvent(view, device)
275 .release(0, QPoint(201,201));
277 QCOMPARE(testItem->touchEventsReceived.count(), 0);
279 touchRegistry->requestTouchOwnership(0, candidateItem);
281 QCOMPARE(testItem->touchEventsReceived.count(), 0);
283 QVERIFY(touchGate->m_storedEvents.isEmpty());
286void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
288 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
289 Q_ASSERT(touchGate);
291 TestItem *testItem = new TestItem;
292 testItem->setWidth(touchGate->width());
293 testItem->setHeight(touchGate->height());
294 testItem->setParentItem(view->rootObject());
295 testItem->setZ(0.0);
297 QFETCH(bool, isEnabled);
298 testItem->setEnabled(isEnabled);
300 QFETCH(bool, isVisible);
301 testItem->setVisible(isVisible);
303 touchGate->setZ(1.0);
304 touchGate->setTargetItem(testItem);
306 QTest::touchEvent(view, device)
307 .press(0, QPoint(100,100));
309 QCOMPARE(testItem->touchEventsReceived.count(), 0);
310 QVERIFY(touchGate->m_storedEvents.isEmpty());
313void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
315 QTest::addColumn<bool>("isEnabled");
316 QTest::addColumn<bool>("isVisible");
318 QTest::newRow("disabled visible") << false << true;
319 QTest::newRow("enabled invisible") << true << false;
320 QTest::newRow("disabled invisible") << false << false;
323void tst_TouchGate::disabledWhileHoldingTouch()
325 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
326 Q_ASSERT(touchGate);
328 TestItem *testItem = new TestItem;
329 testItem->setWidth(touchGate->width());
330 testItem->setHeight(touchGate->height());
331 testItem->setParentItem(view->rootObject());
332 testItem->setZ(0.0);
334 touchGate->setZ(1.0);
335 touchGate->setTargetItem(testItem);
337 QTest::touchEvent(view, device)
338 .press(0, QPoint(100,100));
340 QCOMPARE(testItem->touchEventsReceived.count(), 1);
341 testItem->touchEventsReceived.clear();
343 touchGate->setEnabled(false);
345 QTest::touchEvent(view, device)
346 .move(0, QPoint(101,101));
348 // Nothing new came as TouchGate didn't even get it because it's disabled
349 QCOMPARE(testItem->touchEventsReceived.count(), 0);
351 touchGate->setEnabled(true);
353 QTest::touchEvent(view, device)
354 .move(0, QPoint(102,102));
356 QTest::touchEvent(view, device)
357 .release(0, QPoint(102,102));
359 // Nothing new came because TouchGate has already discarded touch 0
360 QCOMPARE(testItem->touchEventsReceived.count(), 0);
362 QTest::touchEvent(view, device)
363 .press(1, QPoint(200,200));
365 QCOMPARE(testItem->touchEventsReceived.count(), 1);
366 {
367 // it got only the new touch point.
368 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
369 QCOMPARE(touchEvent->touchPoints().count(), 1);
370 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
371 }
374///////////// CandidateItem /////////////////////////////////////////////////////////////
376void CandidateItem::touchEvent(QTouchEvent *event)
378 touchEventHandler(event);
382QTEST_MAIN(tst_TouchGate)
384#include "tst_TouchGate.moc"