on 7d7cfae help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp
381 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 <UbuntuGestures/private/touchregistry_p.h>
30#include "TestItem.h"
32UG_USE_NAMESPACE
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 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
192 wp->flushDelayedTouchEvent();
193 // TouchGate should now open its flood gates and let testItem get all
194 // events from touch 0 produced so far
195 QCOMPARE(testItem->touchEventsReceived.count(), 2);
196 }
198 QTest::touchEvent(view, device)
199 .release(0, QPoint(101,101));
201 if (ownershipAfterTouchEnd) {
202 QCOMPARE(testItem->touchEventsReceived.count(), 0);
203 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
204 // TouchGate should now open its flood gates and let testItem get all
205 // events from touch 0 produced so far
206 }
208 QCOMPARE(testItem->touchEventsReceived.count(), 3);
210 QVERIFY(touchGate->m_storedEvents.isEmpty());
211 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
214void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
216 QTest::addColumn<bool>("ownershipAfterTouchEnd");
218 QTest::newRow("touch end after touch ownership") << false;
219 QTest::newRow("touch ownership after touch end") << true;
222/*
223 A touch point of id 0 starts and ends. Then the next touch point is also given
224 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
225 points.
227 Note that this won't be a problem with Mir as it assigns unique ids for the touch
228 points it produces.
229 */
230void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
232 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
233 Q_ASSERT(touchGate);
235 TestItem *testItem = new TestItem;
236 testItem->setWidth(touchGate->width());
237 testItem->setHeight(touchGate->height());
238 testItem->setParentItem(view->rootObject());
239 testItem->setZ(0.0);
241 touchGate->setZ(1.0);
242 touchGate->setTargetItem(testItem);
244 QTest::touchEvent(view, device)
245 .press(0, QPoint(100,100));
246 QTest::touchEvent(view, device)
247 .move(0, QPoint(101,101));
248 QTest::touchEvent(view, device)
249 .release(0, QPoint(101,101));
251 QCOMPARE(testItem->touchEventsReceived.count(), 3);
252 testItem->touchEventsReceived.clear();
254 // Put it in front of touchGate
255 CandidateItem *candidateItem = new CandidateItem;
256 candidateItem->setWidth(touchGate->width());
257 candidateItem->setHeight(touchGate->height());
258 candidateItem->setParentItem(view->rootObject());
259 candidateItem->setZ(2.0);
261 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
262 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
263 event->ignore();
264 };
266 // A brand new touch, but with the same id as the previous one
267 QTest::touchEvent(view, device)
268 .press(0, QPoint(200,200));
269 QTest::touchEvent(view, device)
270 .move(0, QPoint(201,201));
271 QTest::touchEvent(view, device)
272 .release(0, QPoint(201,201));
274 QCOMPARE(testItem->touchEventsReceived.count(), 0);
276 touchRegistry->requestTouchOwnership(0, candidateItem);
278 QCOMPARE(testItem->touchEventsReceived.count(), 0);
280 QVERIFY(touchGate->m_storedEvents.isEmpty());
283void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
285 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
286 Q_ASSERT(touchGate);
288 TestItem *testItem = new TestItem;
289 testItem->setWidth(touchGate->width());
290 testItem->setHeight(touchGate->height());
291 testItem->setParentItem(view->rootObject());
292 testItem->setZ(0.0);
294 QFETCH(bool, isEnabled);
295 testItem->setEnabled(isEnabled);
297 QFETCH(bool, isVisible);
298 testItem->setVisible(isVisible);
300 touchGate->setZ(1.0);
301 touchGate->setTargetItem(testItem);
303 QTest::touchEvent(view, device)
304 .press(0, QPoint(100,100));
306 QCOMPARE(testItem->touchEventsReceived.count(), 0);
307 QVERIFY(touchGate->m_storedEvents.isEmpty());
310void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
312 QTest::addColumn<bool>("isEnabled");
313 QTest::addColumn<bool>("isVisible");
315 QTest::newRow("disabled visible") << false << true;
316 QTest::newRow("enabled invisible") << true << false;
317 QTest::newRow("disabled invisible") << false << false;
320void tst_TouchGate::disabledWhileHoldingTouch()
322 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
323 Q_ASSERT(touchGate);
325 TestItem *testItem = new TestItem;
326 testItem->setWidth(touchGate->width());
327 testItem->setHeight(touchGate->height());
328 testItem->setParentItem(view->rootObject());
329 testItem->setZ(0.0);
331 touchGate->setZ(1.0);
332 touchGate->setTargetItem(testItem);
334 QTest::touchEvent(view, device)
335 .press(0, QPoint(100,100));
337 QCOMPARE(testItem->touchEventsReceived.count(), 1);
338 testItem->touchEventsReceived.clear();
340 touchGate->setEnabled(false);
342 QTest::touchEvent(view, device)
343 .move(0, QPoint(101,101));
345 // Nothing new came as TouchGate didn't even get it because it's disabled
346 QCOMPARE(testItem->touchEventsReceived.count(), 0);
348 touchGate->setEnabled(true);
350 QTest::touchEvent(view, device)
351 .move(0, QPoint(102,102));
353 QTest::touchEvent(view, device)
354 .release(0, QPoint(102,102));
356 // Nothing new came because TouchGate has already discarded touch 0
357 QCOMPARE(testItem->touchEventsReceived.count(), 0);
359 QTest::touchEvent(view, device)
360 .press(1, QPoint(200,200));
362 QCOMPARE(testItem->touchEventsReceived.count(), 1);
363 {
364 // it got only the new touch point.
365 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
366 QCOMPARE(touchEvent->touchPoints().count(), 1);
367 QCOMPARE(touchEvent->touchPoints()[0].id(), 1);
368 }
371///////////// CandidateItem /////////////////////////////////////////////////////////////
373void CandidateItem::touchEvent(QTouchEvent *event)
375 touchEventHandler(event);
379QTEST_MAIN(tst_TouchGate)
381#include "tst_TouchGate.moc"