on bd49d29 help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp
345 lines 10 kB history raw
1/*
2 * Copyright (C) 2014 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>
23// C++ std lib
24#include <functional>
26#include <TouchGate.h>
27#include <TouchRegistry.h>
29class TestItem : public QQuickItem
31 Q_OBJECT
33public:
34 QList<QSharedPointer<QTouchEvent>> touchEventsReceived;
36protected:
37 void touchEvent(QTouchEvent *event) override;
38};
40class CandidateItem : public QQuickItem
42 Q_OBJECT
44public:
45 std::function<void(QTouchEvent*)> touchEventHandler;
47protected:
48 void touchEvent(QTouchEvent *event) override;
49};
51class tst_TouchGate : public QObject
53 Q_OBJECT
54public:
55 tst_TouchGate(QObject *parent = nullptr);
56private Q_SLOTS:
57 void initTestCase(); // will be called before the first test function is executed
58 void cleanupTestCase(); // will be called after the last test function was executed.
60 void init(); // called right before each and every test function is executed
61 void cleanup(); // called right after each and every test function is executed
63 void onlyCandidate_passThrough();
64 void holdsEventsUntilGainsOwnership();
65 void holdsEventsUntilGainsOwnership_data();
66 void holdsEventsUntilGainsOwnership_repeatingTouchId();
67 void dontDispacthToDisabledOrInvisibleTarget();
68 void dontDispacthToDisabledOrInvisibleTarget_data();
70private:
71 QQuickView *createView();
72 TouchRegistry *touchRegistry;
73 QQuickView *view;
74 QTouchDevice *device;
75};
77tst_TouchGate::tst_TouchGate(QObject *parent)
78 : QObject(parent)
79 , touchRegistry(nullptr)
80 , view(nullptr)
81 , device(nullptr)
85void tst_TouchGate::initTestCase()
87 if (!device) {
88 device = new QTouchDevice;
89 device->setType(QTouchDevice::TouchScreen);
90 QWindowSystemInterface::registerTouchDevice(device);
91 }
94void tst_TouchGate::cleanupTestCase()
98void tst_TouchGate::init()
100 touchRegistry = new TouchRegistry;
102 view = createView();
103 view->installEventFilter(touchRegistry);
104 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
105 view->show();
106 QVERIFY(QTest::qWaitForWindowExposed(view));
107 QVERIFY(view->rootObject() != 0);
108 qApp->processEvents();
111void tst_TouchGate::cleanup()
113 delete view;
114 view = 0;
116 delete touchRegistry;
117 touchRegistry = nullptr;
120QQuickView *tst_TouchGate::createView()
122 QQuickView *window = new QQuickView(0);
123 window->setResizeMode(QQuickView::SizeRootObjectToView);
124 window->resize(720, 720);
125 window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
127 return window;
130/*
131 Simplest case. TouchGate is the only candidate for the touch point, thus it
132 will instantly gain ownership causing the event to pass through it directly to
133 its child.
134 */
135void tst_TouchGate::onlyCandidate_passThrough()
137 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
138 Q_ASSERT(touchGate);
140 TestItem *testItem = new TestItem;
141 testItem->setWidth(touchGate->width());
142 testItem->setHeight(touchGate->height());
143 testItem->setParentItem(view->rootObject());
144 testItem->setZ(0.0);
146 touchGate->setZ(1.0);
147 touchGate->setTargetItem(testItem);
149 QTest::touchEvent(view, device)
150 .press(0, QPoint(100,100));
152 QCOMPARE(testItem->touchEventsReceived.count(), 1);
153 QVERIFY(touchGate->m_storedEvents.isEmpty());
156void tst_TouchGate::holdsEventsUntilGainsOwnership()
158 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
159 Q_ASSERT(touchGate);
160 QFETCH(bool, ownershipAfterTouchEnd);
162 TestItem *testItem = new TestItem;
163 testItem->setWidth(touchGate->width());
164 testItem->setHeight(touchGate->height());
165 testItem->setParentItem(view->rootObject());
166 testItem->setZ(0.0);
168 touchGate->setZ(1.0);
169 touchGate->setTargetItem(testItem);
171 // Put it in front of touchGate
172 CandidateItem *candidateItem = new CandidateItem;
173 candidateItem->setWidth(touchGate->width());
174 candidateItem->setHeight(touchGate->height());
175 candidateItem->setParentItem(view->rootObject());
176 candidateItem->setZ(2.0);
178 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
179 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
180 event->ignore();
181 };
183 QTest::touchEvent(view, device)
184 .press(0, QPoint(100,100));
186 QCOMPARE(testItem->touchEventsReceived.count(), 0);
188 QTest::touchEvent(view, device)
189 .move(0, QPoint(101,101));
191 QCOMPARE(testItem->touchEventsReceived.count(), 0);
193 if (!ownershipAfterTouchEnd) {
194 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
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;
322///////////// TestItem /////////////////////////////////////////////////////////////
324void TestItem::touchEvent(QTouchEvent *event)
326 QTouchEvent *clonedEvent = new QTouchEvent(event->type(),
327 event->device(),
328 event->modifiers(),
329 event->touchPointStates(),
330 event->touchPoints());
332 touchEventsReceived.append(QSharedPointer<QTouchEvent>(clonedEvent));
335///////////// CandidateItem /////////////////////////////////////////////////////////////
337void CandidateItem::touchEvent(QTouchEvent *event)
339 touchEventHandler(event);
343QTEST_MAIN(tst_TouchGate)
345#include "tst_TouchGate.moc"