on 276c910 help sign in
unity8/tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp
351 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>
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>
32class TestItem : public QQuickItem
34 Q_OBJECT
36public:
37 QList<QSharedPointer<QTouchEvent>> touchEventsReceived;
39protected:
40 void touchEvent(QTouchEvent *event) override;
41};
43class CandidateItem : public QQuickItem
45 Q_OBJECT
47public:
48 std::function<void(QTouchEvent*)> touchEventHandler;
50protected:
51 void touchEvent(QTouchEvent *event) override;
52};
54class tst_TouchGate : public QObject
56 Q_OBJECT
57public:
58 tst_TouchGate(QObject *parent = nullptr);
59private Q_SLOTS:
60 void initTestCase(); // will be called before the first test function is executed
61 void cleanupTestCase(); // will be called after the last test function was executed.
63 void init(); // called right before each and every test function is executed
64 void cleanup(); // called right after each and every test function is executed
66 void onlyCandidate_passThrough();
67 void holdsEventsUntilGainsOwnership();
68 void holdsEventsUntilGainsOwnership_data();
69 void holdsEventsUntilGainsOwnership_repeatingTouchId();
70 void dontDispacthToDisabledOrInvisibleTarget();
71 void dontDispacthToDisabledOrInvisibleTarget_data();
73private:
74 QQuickView *createView();
75 TouchRegistry *touchRegistry;
76 QQuickView *view;
77 QTouchDevice *device;
78};
80tst_TouchGate::tst_TouchGate(QObject *parent)
81 : QObject(parent)
82 , touchRegistry(nullptr)
83 , view(nullptr)
84 , device(nullptr)
88void tst_TouchGate::initTestCase()
90 if (!device) {
91 device = new QTouchDevice;
92 device->setType(QTouchDevice::TouchScreen);
93 QWindowSystemInterface::registerTouchDevice(device);
94 }
97void tst_TouchGate::cleanupTestCase()
101void tst_TouchGate::init()
103 touchRegistry = new TouchRegistry;
105 view = createView();
106 view->installEventFilter(touchRegistry);
107 view->setSource(QUrl::fromLocalFile("touchGateExample.qml"));
108 view->show();
109 QVERIFY(QTest::qWaitForWindowExposed(view));
110 QVERIFY(view->rootObject() != 0);
111 qApp->processEvents();
114void tst_TouchGate::cleanup()
116 delete view;
117 view = 0;
119 delete touchRegistry;
120 touchRegistry = nullptr;
123QQuickView *tst_TouchGate::createView()
125 QQuickView *window = new QQuickView(0);
126 window->setResizeMode(QQuickView::SizeRootObjectToView);
127 window->resize(720, 720);
129 return window;
132/*
133 Simplest case. TouchGate is the only candidate for the touch point, thus it
134 will instantly gain ownership causing the event to pass through it directly to
135 its child.
136 */
137void tst_TouchGate::onlyCandidate_passThrough()
139 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
140 Q_ASSERT(touchGate);
142 TestItem *testItem = new TestItem;
143 testItem->setWidth(touchGate->width());
144 testItem->setHeight(touchGate->height());
145 testItem->setParentItem(view->rootObject());
146 testItem->setZ(0.0);
148 touchGate->setZ(1.0);
149 touchGate->setTargetItem(testItem);
151 QTest::touchEvent(view, device)
152 .press(0, QPoint(100,100));
154 QCOMPARE(testItem->touchEventsReceived.count(), 1);
155 QVERIFY(touchGate->m_storedEvents.isEmpty());
158void tst_TouchGate::holdsEventsUntilGainsOwnership()
160 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
161 Q_ASSERT(touchGate);
162 QFETCH(bool, ownershipAfterTouchEnd);
164 TestItem *testItem = new TestItem;
165 testItem->setWidth(touchGate->width());
166 testItem->setHeight(touchGate->height());
167 testItem->setParentItem(view->rootObject());
168 testItem->setZ(0.0);
170 touchGate->setZ(1.0);
171 touchGate->setTargetItem(testItem);
173 // Put it in front of touchGate
174 CandidateItem *candidateItem = new CandidateItem;
175 candidateItem->setWidth(touchGate->width());
176 candidateItem->setHeight(touchGate->height());
177 candidateItem->setParentItem(view->rootObject());
178 candidateItem->setZ(2.0);
180 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
181 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
182 event->ignore();
183 };
185 QTest::touchEvent(view, device)
186 .press(0, QPoint(100,100));
188 QCOMPARE(testItem->touchEventsReceived.count(), 0);
190 QTest::touchEvent(view, device)
191 .move(0, QPoint(101,101));
193 QCOMPARE(testItem->touchEventsReceived.count(), 0);
195 if (!ownershipAfterTouchEnd) {
196 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
197#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
198 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
199 wp->flushDelayedTouchEvent();
200#endif
201 // TouchGate should now open its flood gates and let testItem get all
202 // events from touch 0 produced so far
203 QCOMPARE(testItem->touchEventsReceived.count(), 2);
204 }
206 QTest::touchEvent(view, device)
207 .release(0, QPoint(101,101));
209 if (ownershipAfterTouchEnd) {
210 QCOMPARE(testItem->touchEventsReceived.count(), 0);
211 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
212 // TouchGate should now open its flood gates and let testItem get all
213 // events from touch 0 produced so far
214 }
216 QCOMPARE(testItem->touchEventsReceived.count(), 3);
218 QVERIFY(touchGate->m_storedEvents.isEmpty());
219 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
222void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
224 QTest::addColumn<bool>("ownershipAfterTouchEnd");
226 QTest::newRow("touch end after touch ownership") << false;
227 QTest::newRow("touch ownership after touch end") << true;
230/*
231 A touch point of id 0 starts and ends. Then the next touch point is also given
232 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
233 points.
235 Note that this won't be a problem with Mir as it assigns unique ids for the touch
236 points it produces.
237 */
238void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
240 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
241 Q_ASSERT(touchGate);
243 TestItem *testItem = new TestItem;
244 testItem->setWidth(touchGate->width());
245 testItem->setHeight(touchGate->height());
246 testItem->setParentItem(view->rootObject());
247 testItem->setZ(0.0);
249 touchGate->setZ(1.0);
250 touchGate->setTargetItem(testItem);
252 QTest::touchEvent(view, device)
253 .press(0, QPoint(100,100));
254 QTest::touchEvent(view, device)
255 .move(0, QPoint(101,101));
256 QTest::touchEvent(view, device)
257 .release(0, QPoint(101,101));
259 QCOMPARE(testItem->touchEventsReceived.count(), 3);
260 testItem->touchEventsReceived.clear();
262 // Put it in front of touchGate
263 CandidateItem *candidateItem = new CandidateItem;
264 candidateItem->setWidth(touchGate->width());
265 candidateItem->setHeight(touchGate->height());
266 candidateItem->setParentItem(view->rootObject());
267 candidateItem->setZ(2.0);
269 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
270 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
271 event->ignore();
272 };
274 // A brand new touch, but with the same id as the previous one
275 QTest::touchEvent(view, device)
276 .press(0, QPoint(200,200));
277 QTest::touchEvent(view, device)
278 .move(0, QPoint(201,201));
279 QTest::touchEvent(view, device)
280 .release(0, QPoint(201,201));
282 QCOMPARE(testItem->touchEventsReceived.count(), 0);
284 touchRegistry->requestTouchOwnership(0, candidateItem);
286 QCOMPARE(testItem->touchEventsReceived.count(), 0);
288 QVERIFY(touchGate->m_storedEvents.isEmpty());
291void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
293 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
294 Q_ASSERT(touchGate);
296 TestItem *testItem = new TestItem;
297 testItem->setWidth(touchGate->width());
298 testItem->setHeight(touchGate->height());
299 testItem->setParentItem(view->rootObject());
300 testItem->setZ(0.0);
302 QFETCH(bool, isEnabled);
303 testItem->setEnabled(isEnabled);
305 QFETCH(bool, isVisible);
306 testItem->setVisible(isVisible);
308 touchGate->setZ(1.0);
309 touchGate->setTargetItem(testItem);
311 QTest::touchEvent(view, device)
312 .press(0, QPoint(100,100));
314 QCOMPARE(testItem->touchEventsReceived.count(), 0);
315 QVERIFY(touchGate->m_storedEvents.isEmpty());
318void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
320 QTest::addColumn<bool>("isEnabled");
321 QTest::addColumn<bool>("isVisible");
323 QTest::newRow("disabled visible") << false << true;
324 QTest::newRow("enabled invisible") << true << false;
325 QTest::newRow("disabled invisible") << false << false;
328///////////// TestItem /////////////////////////////////////////////////////////////
330void TestItem::touchEvent(QTouchEvent *event)
332 QTouchEvent *clonedEvent = new QTouchEvent(event->type(),
333 event->device(),
334 event->modifiers(),
335 event->touchPointStates(),
336 event->touchPoints());
338 touchEventsReceived.append(QSharedPointer<QTouchEvent>(clonedEvent));
341///////////// CandidateItem /////////////////////////////////////////////////////////////
343void CandidateItem::touchEvent(QTouchEvent *event)
345 touchEventHandler(event);
349QTEST_MAIN(tst_TouchGate)
351#include "tst_TouchGate.moc"