2 * Copyright (C) 2014-2015 Canonical, Ltd.
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.
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.
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/>.
17#include <qpa/qwindowsysteminterface.h>
21#include <QSharedPointer>
22#include <private/qquickanimatorcontroller_p.h>
23#include <private/qquickwindow_p.h>
29#include <UbuntuGestures/private/touchregistry_p.h>
37class CandidateItem : public QQuickItem
42 std::function<void(QTouchEvent*)> touchEventHandler;
45 void touchEvent(QTouchEvent *event) override;
48class tst_TouchGate : public QObject
52 tst_TouchGate(QObject *parent = nullptr);
54 void initTestCase(); // will be called before the first test function is executed
55 void cleanupTestCase(); // will be called after the last test function was executed.
57 void init(); // called right before each and every test function is executed
58 void cleanup(); // called right after each and every test function is executed
61 void onlyCandidate_passThrough();
62 void holdsEventsUntilGainsOwnership();
63 void holdsEventsUntilGainsOwnership_data();
64 void holdsEventsUntilGainsOwnership_repeatingTouchId();
65 void dontDispacthToDisabledOrInvisibleTarget();
66 void dontDispacthToDisabledOrInvisibleTarget_data();
69 void disabledWhileHoldingTouch();
72 QQuickView *createView();
73 TouchRegistry *touchRegistry;
78tst_TouchGate::tst_TouchGate(QObject *parent)
80 , touchRegistry(nullptr)
86void tst_TouchGate::initTestCase()
89 device = new QTouchDevice;
90 device->setType(QTouchDevice::TouchScreen);
91 QWindowSystemInterface::registerTouchDevice(device);
95void tst_TouchGate::cleanupTestCase()
99void tst_TouchGate::init()
101 touchRegistry = TouchRegistry::instance();
104 view->setSource(QUrl::fromLocalFile(testDataDir() + "/plugins/Ubuntu/Gestures/touchGateExample.qml"));
106 QVERIFY(QTest::qWaitForWindowExposed(view));
107 QVERIFY(view->rootObject() != 0);
108 qApp->processEvents();
111void tst_TouchGate::cleanup()
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);
130 Simplest case. TouchGate is the only candidate for the touch point, thus it
131 will instantly gain ownership causing the event to pass through it directly to
134void tst_TouchGate::onlyCandidate_passThrough()
136 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
139 TestItem *testItem = new TestItem;
140 testItem->setWidth(touchGate->width());
141 testItem->setHeight(touchGate->height());
142 testItem->setParentItem(view->rootObject());
145 touchGate->setZ(1.0);
146 touchGate->setTargetItem(testItem);
148 QTest::touchEvent(view, device)
149 .press(0, QPoint(100,100));
151 QCOMPARE(testItem->touchEventsReceived.count(), 1);
152 QVERIFY(touchGate->m_storedEvents.isEmpty());
155void tst_TouchGate::holdsEventsUntilGainsOwnership()
157 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
159 QFETCH(bool, ownershipAfterTouchEnd);
161 TestItem *testItem = new TestItem;
162 testItem->setWidth(touchGate->width());
163 testItem->setHeight(touchGate->height());
164 testItem->setParentItem(view->rootObject());
167 touchGate->setZ(1.0);
168 touchGate->setTargetItem(testItem);
170 // Put it in front of touchGate
171 CandidateItem *candidateItem = new CandidateItem;
172 candidateItem->setWidth(touchGate->width());
173 candidateItem->setHeight(touchGate->height());
174 candidateItem->setParentItem(view->rootObject());
175 candidateItem->setZ(2.0);
177 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
178 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
182 QTest::touchEvent(view, device)
183 .press(0, QPoint(100,100));
185 QCOMPARE(testItem->touchEventsReceived.count(), 0);
187 QTest::touchEvent(view, device)
188 .move(0, QPoint(101,101));
190 QCOMPARE(testItem->touchEventsReceived.count(), 0);
192 if (!ownershipAfterTouchEnd) {
193 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
194 QQuickWindowPrivate *wp = QQuickWindowPrivate::get(testItem->window());
195 if (wp->delayedTouch) {
196 wp->deliverDelayedTouchEvent();
198 // Touch events which constantly start animations (such as a behavior tracking
199 // the mouse point) need animations to start.
200 QQmlAnimationTimer *ut = QQmlAnimationTimer::instance();
201 if (ut && ut->hasStartAnimationPending())
202 ut->startAnimations();
204 // TouchGate should now open its flood gates and let testItem get all
205 // events from touch 0 produced so far
206 QCOMPARE(testItem->touchEventsReceived.count(), 2);
209 QTest::touchEvent(view, device)
210 .release(0, QPoint(101,101));
212 if (ownershipAfterTouchEnd) {
213 QCOMPARE(testItem->touchEventsReceived.count(), 0);
214 touchRegistry->removeCandidateOwnerForTouch(0, candidateItem);
215 // TouchGate should now open its flood gates and let testItem get all
216 // events from touch 0 produced so far
219 QCOMPARE(testItem->touchEventsReceived.count(), 3);
221 QVERIFY(touchGate->m_storedEvents.isEmpty());
222 QVERIFY(touchGate->m_touchInfoMap.isEmpty());
225void tst_TouchGate::holdsEventsUntilGainsOwnership_data()
227 QTest::addColumn<bool>("ownershipAfterTouchEnd");
229 QTest::newRow("touch end after touch ownership") << false;
230 QTest::newRow("touch ownership after touch end") << true;
234 A touch point of id 0 starts and ends. Then the next touch point is also given
235 id 0. Check that TouchGate behaves correcly recognizing them as two distinct touch
238 Note that this won't be a problem with Mir as it assigns unique ids for the touch
241void tst_TouchGate::holdsEventsUntilGainsOwnership_repeatingTouchId()
243 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
246 TestItem *testItem = new TestItem;
247 testItem->setWidth(touchGate->width());
248 testItem->setHeight(touchGate->height());
249 testItem->setParentItem(view->rootObject());
252 touchGate->setZ(1.0);
253 touchGate->setTargetItem(testItem);
255 QTest::touchEvent(view, device)
256 .press(0, QPoint(100,100));
257 QTest::touchEvent(view, device)
258 .move(0, QPoint(101,101));
259 QTest::touchEvent(view, device)
260 .release(0, QPoint(101,101));
262 QCOMPARE(testItem->touchEventsReceived.count(), 3);
263 testItem->touchEventsReceived.clear();
265 // Put it in front of touchGate
266 CandidateItem *candidateItem = new CandidateItem;
267 candidateItem->setWidth(touchGate->width());
268 candidateItem->setHeight(touchGate->height());
269 candidateItem->setParentItem(view->rootObject());
270 candidateItem->setZ(2.0);
272 candidateItem->touchEventHandler = [&](QTouchEvent* event) {
273 touchRegistry->addCandidateOwnerForTouch(0, candidateItem);
277 // A brand new touch, but with the same id as the previous one
278 QTest::touchEvent(view, device)
279 .press(0, QPoint(200,200));
280 QTest::touchEvent(view, device)
281 .move(0, QPoint(201,201));
282 QTest::touchEvent(view, device)
283 .release(0, QPoint(201,201));
285 QCOMPARE(testItem->touchEventsReceived.count(), 0);
287 touchRegistry->requestTouchOwnership(0, candidateItem);
289 QCOMPARE(testItem->touchEventsReceived.count(), 0);
291 QVERIFY(touchGate->m_storedEvents.isEmpty());
294void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget()
296 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
299 TestItem *testItem = new TestItem;
300 testItem->setWidth(touchGate->width());
301 testItem->setHeight(touchGate->height());
302 testItem->setParentItem(view->rootObject());
305 QFETCH(bool, isEnabled);
306 testItem->setEnabled(isEnabled);
308 QFETCH(bool, isVisible);
309 testItem->setVisible(isVisible);
311 touchGate->setZ(1.0);
312 touchGate->setTargetItem(testItem);
314 QTest::touchEvent(view, device)
315 .press(0, QPoint(100,100));
317 QCOMPARE(testItem->touchEventsReceived.count(), 0);
318 QVERIFY(touchGate->m_storedEvents.isEmpty());
321void tst_TouchGate::dontDispacthToDisabledOrInvisibleTarget_data()
323 QTest::addColumn<bool>("isEnabled");
324 QTest::addColumn<bool>("isVisible");
326 QTest::newRow("disabled visible") << false << true;
327 QTest::newRow("enabled invisible") << true << false;
328 QTest::newRow("disabled invisible") << false << false;
331void tst_TouchGate::disabledWhileHoldingTouch()
333 TouchGate *touchGate = view->rootObject()->findChild<TouchGate*>("touchGate");
336 TestItem *testItem = new TestItem;
337 testItem->setWidth(touchGate->width());
338 testItem->setHeight(touchGate->height());
339 testItem->setParentItem(view->rootObject());
342 touchGate->setZ(1.0);
343 touchGate->setTargetItem(testItem);
345 QTest::touchEvent(view, device)
346 .press(0, QPoint(100,100));
348 QCOMPARE(testItem->touchEventsReceived.count(), 1);
349 testItem->touchEventsReceived.clear();
351 touchGate->setEnabled(false);
353 QTest::touchEvent(view, device)
354 .move(0, QPoint(101,101));
356 // Nothing new came as TouchGate didn't even get it because it's disabled
357 QCOMPARE(testItem->touchEventsReceived.count(), 0);
359 touchGate->setEnabled(true);
361 QTest::touchEvent(view, device)
362 .move(0, QPoint(102,102));
364 QTest::touchEvent(view, device)
365 .release(0, QPoint(102,102));
367 // Nothing new came because TouchGate has already discarded touch 0
368 QCOMPARE(testItem->touchEventsReceived.count(), 0);
370 QTest::touchEvent(view, device)
371 .press(1, QPoint(200,200));
373 QCOMPARE(testItem->touchEventsReceived.count(), 1);
375 // it got only the new touch point.
376 QSharedPointer<QTouchEvent> touchEvent = testItem->touchEventsReceived[0];
377 QCOMPARE(touchEvent->touchPoints().count(), 1);
378 QCOMPARE(touchEvent->touchPoints()[0].pos(), QPointF(200, 200));
382///////////// CandidateItem /////////////////////////////////////////////////////////////
384void CandidateItem::touchEvent(QTouchEvent *event)
386 touchEventHandler(event);
390QTEST_MAIN(tst_TouchGate)
392#include "tst_TouchGate.moc"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list