on xenial help sign in
[ CI Train Bot ]

* New rebuild forced. [ Daniel d'Andrada ] * Tapping home key shows unity8-dash home added: plugins/Utils/ElapsedTimer.h plugins/Utils/HomeKeyWatcher.cpp plugins/Utils/HomeKeyWatcher.h plugins/Utils/Timer.cpp plugins/Utils/Timer.h tests/plugins/Utils/homekeywatchertest.cpp [ Michał Sawicz ] * Tapping home key shows unity8-dash home added: plugins/Utils/ElapsedTimer.h plugins/Utils/HomeKeyWatcher.cpp plugins/Utils/HomeKeyWatcher.h plugins/Utils/Timer.cpp plugins/Utils/Timer.h tests/plugins/Utils/homekeywatchertest.cpp

commit1dc7b13827e11923ce8af0fb6145457cb3eb77c9 authorMichael Zanetti <michael.zanetti@canonical.com> dateThu 23 Apr 2015, 18:34 (11 years ago) parent16d5266e1fdd20
11 files changed+730−3
debian/changelog+19 plugins/Utils/CMakeLists.txt+2 plugins/Utils/ElapsedTimer.h+51 plugins/Utils/HomeKeyWatcher.cpp+116 plugins/Utils/HomeKeyWatcher.h+74 plugins/Utils/Timer.cpp+59 plugins/Utils/Timer.h+79 plugins/Utils/plugin.cpp+2−3 qml/Shell.qml+4 tests/plugins/Utils/CMakeLists.txt+1 tests/plugins/Utils/homekeywatchertest.cpp+323
debian/changelog+19
@@ -4,6 +4,25 @@ unity8 (8.10-0ubuntu1) UNRELEASED; urgency=medium
44
55 -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 15 Apr 2015 14:47:17 +0200
66
7+unity8 (8.02+15.04.20150423-0ubuntu1) vivid; urgency=medium
8+
9+ [ CI Train Bot ]
10+ * New rebuild forced.
11+
12+ [ Daniel d'Andrada ]
13+ * Tapping home key shows unity8-dash home added:
14+ plugins/Utils/ElapsedTimer.h plugins/Utils/HomeKeyWatcher.cpp
15+ plugins/Utils/HomeKeyWatcher.h plugins/Utils/Timer.cpp
16+ plugins/Utils/Timer.h tests/plugins/Utils/homekeywatchertest.cpp
17+
18+ [ Michał Sawicz ]
19+ * Tapping home key shows unity8-dash home added:
20+ plugins/Utils/ElapsedTimer.h plugins/Utils/HomeKeyWatcher.cpp
21+ plugins/Utils/HomeKeyWatcher.h plugins/Utils/Timer.cpp
22+ plugins/Utils/Timer.h tests/plugins/Utils/homekeywatchertest.cpp
23+
24+ -- CI Train Bot <ci-train-bot@canonical.com> Thu, 23 Apr 2015 12:52:51 +0000
25+
726unity8 (8.02+15.04.20150422-0ubuntu1) vivid; urgency=medium
827
928 [ Albert Astals Cid ]
plugins/Utils/CMakeLists.txt+2
@@ -9,11 +9,13 @@ include_directories(
99
1010set(QMLPLUGIN_SRC
1111 constants.cpp
12+ HomeKeyWatcher.cpp
1213 inputwatcher.cpp
1314 qlimitproxymodelqml.cpp
1415 unitysortfilterproxymodelqml.cpp
1516 relativetimeformatter.cpp
1617 timeformatter.cpp
18+ Timer.cpp
1719 unitymenumodelpaths.cpp
1820 windowkeysfilter.cpp
1921 windowscreenshotprovider.cpp
plugins/Utils/ElapsedTimer.hnew file+51
@@ -0,0 +1,51 @@
1+/*
2+ * Copyright (C) 2015 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ */
18+
19+#ifndef UNITYUTIL_ELAPSEDTIMER_H
20+#define UNITYUTIL_ELAPSEDTIMER_H
21+
22+#include <QElapsedTimer>
23+
24+namespace UnityUtil {
25+
26+/**
27+ Interface for ElapsedTimer implementations
28+ */
29+class AbstractElapsedTimer {
30+public:
31+ virtual ~AbstractElapsedTimer() {}
32+ virtual void start() = 0;
33+ virtual qint64 msecsSinceReference() const = 0;
34+ virtual qint64 elapsed() const = 0;
35+};
36+
37+/**
38+ A QElapsedTimer wrapper
39+ */
40+class ElapsedTimer : public AbstractElapsedTimer {
41+public:
42+ void start() override { m_timer.start(); }
43+ qint64 msecsSinceReference() const override { return m_timer.msecsSinceReference(); }
44+ qint64 elapsed() const override { return m_timer.elapsed(); }
45+private:
46+ QElapsedTimer m_timer;
47+};
48+
49+} // namespace UnityUtil
50+
51+#endif // UNITYUTIL_ELAPSEDTIMER_H
plugins/Utils/HomeKeyWatcher.cppnew file+116
@@ -0,0 +1,116 @@
1+/*
2+ * Copyright (C) 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+ */
16+
17+#include "HomeKeyWatcher.h"
18+
19+#include <QQuickWindow>
20+
21+using namespace UnityUtil;
22+
23+HomeKeyWatcher::HomeKeyWatcher(QQuickItem *parent)
24+ : HomeKeyWatcher(new Timer, new ElapsedTimer, parent)
25+{
26+}
27+
28+HomeKeyWatcher::HomeKeyWatcher(UnityUtil::AbstractTimer *timer,
29+ UnityUtil::AbstractElapsedTimer *elapsedTimer,
30+ QQuickItem *parent)
31+ : QQuickItem(parent)
32+ , m_windowBeingTouched(false)
33+ , m_homeKeyPressed(false)
34+ , m_windowLastTouchedTimer(elapsedTimer)
35+ , m_activationTimer(timer)
36+{
37+ m_windowLastTouchedTimer->start();
38+
39+ connect(this, &QQuickItem::windowChanged,
40+ this, &HomeKeyWatcher::setupFilterOnWindow);
41+
42+ connect(m_activationTimer, &UnityUtil::AbstractTimer::timeout,
43+ this, &HomeKeyWatcher::emitActivatedIfNoTouchesAround);
44+ m_activationTimer->setInterval(msecsWithoutTouches);
45+}
46+
47+HomeKeyWatcher::~HomeKeyWatcher()
48+{
49+ delete m_windowLastTouchedTimer;
50+ delete m_activationTimer;
51+}
52+
53+bool HomeKeyWatcher::eventFilter(QObject *watched, QEvent *event)
54+{
55+ Q_ASSERT(!m_filteredWindow.isNull());
56+ Q_ASSERT(watched == static_cast<QObject*>(m_filteredWindow.data()));
57+ Q_UNUSED(watched);
58+
59+ update(event);
60+
61+ // We're only monitoring, never filtering out events
62+ return false;
63+}
64+
65+void HomeKeyWatcher::update(QEvent *event)
66+{
67+ if (event->type() == QEvent::KeyPress) {
68+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
69+
70+ m_homeKeyPressed = true;
71+
72+ if (keyEvent->key() == Qt::Key_Super_L && !keyEvent->isAutoRepeat()
73+ && !m_windowBeingTouched
74+ && m_windowLastTouchedTimer->elapsed() >= msecsWithoutTouches) {
75+ m_activationTimer->start();
76+ }
77+
78+ } else if (event->type() == QEvent::KeyRelease) {
79+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
80+
81+ if (keyEvent->key() == Qt::Key_Super_L) {
82+ m_homeKeyPressed = false;
83+ }
84+
85+ } else if (event->type() == QEvent::TouchBegin) {
86+
87+ m_activationTimer->stop();
88+ m_windowBeingTouched = true;
89+
90+ } else if (event->type() == QEvent::TouchEnd) {
91+
92+ m_windowBeingTouched = false;
93+ m_windowLastTouchedTimer->start();
94+ }
95+}
96+
97+void HomeKeyWatcher::setupFilterOnWindow(QQuickWindow *window)
98+{
99+ if (!m_filteredWindow.isNull()) {
100+ m_filteredWindow->removeEventFilter(this);
101+ m_filteredWindow.clear();
102+ }
103+
104+ if (window) {
105+ window->installEventFilter(this);
106+ m_filteredWindow = window;
107+ }
108+}
109+
110+void HomeKeyWatcher::emitActivatedIfNoTouchesAround()
111+{
112+ if (!m_homeKeyPressed && !m_windowBeingTouched &&
113+ (m_windowLastTouchedTimer->elapsed() > msecsWithoutTouches)) {
114+ Q_EMIT activated();
115+ }
116+}
plugins/Utils/HomeKeyWatcher.hnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright (C) 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+ */
16+
17+#ifndef UNITY_HOMEKEYWATCHER_H
18+#define UNITY_HOMEKEYWATCHER_H
19+
20+#include <QQuickItem>
21+#include <QPointer>
22+
23+#include "Timer.h"
24+#include "ElapsedTimer.h"
25+
26+/*
27+ Signals when the home key seems to be have been intentionally tapped.
28+
29+ It only says the home key has been activated if it has been tapped in isolation,
30+ that is, without being accompanied by touches on the screen. Home key taps that
31+ happen along with (or immediately after, or immediately before) touches on the
32+ screen are considered to have happened unintentionally and are thus ignored.
33+
34+ Rationale being that it's easy to accidentally hit the home key while performing
35+ a swipe from a screen edge, for instance. That's particularly the case when the
36+ home key is a capacitive key.
37+ */
38+class HomeKeyWatcher : public QQuickItem
39+{
40+ Q_OBJECT
41+public:
42+
43+ HomeKeyWatcher(QQuickItem *parent = 0);
44+
45+ // for testing
46+ HomeKeyWatcher(UnityUtil::AbstractTimer *timer,
47+ UnityUtil::AbstractElapsedTimer *elapsedTimer,
48+ QQuickItem *parent = 0);
49+
50+ virtual ~HomeKeyWatcher();
51+
52+ bool eventFilter(QObject *watched, QEvent *event);
53+
54+ void update(QEvent *event);
55+
56+ const qint64 msecsWithoutTouches = 150;
57+
58+Q_SIGNALS:
59+ // Emitted when the home key has been intentionally tapped
60+ void activated();
61+
62+private Q_SLOTS:
63+ void setupFilterOnWindow(QQuickWindow *window);
64+ void emitActivatedIfNoTouchesAround();
65+
66+private:
67+ QPointer<QQuickWindow> m_filteredWindow;
68+ bool m_windowBeingTouched;
69+ bool m_homeKeyPressed;
70+ UnityUtil::AbstractElapsedTimer *m_windowLastTouchedTimer;
71+ UnityUtil::AbstractTimer *m_activationTimer;
72+};
73+
74+#endif // UNITY_HOMEKEYWATCHER_H
plugins/Utils/Timer.cppnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 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+ */
16+
17+#include "Timer.h"
18+
19+namespace UnityUtil {
20+
21+Timer::Timer(QObject *parent) : AbstractTimer(parent)
22+{
23+ m_timer.setSingleShot(true);
24+ connect(&m_timer, &QTimer::timeout, this, &AbstractTimer::timeout);
25+}
26+
27+int Timer::interval() const
28+{
29+ return m_timer.interval();
30+}
31+
32+void Timer::setInterval(int msecs)
33+{
34+ m_timer.setInterval(msecs);
35+}
36+
37+void Timer::start()
38+{
39+ m_timer.start();
40+ AbstractTimer::start();
41+}
42+
43+void Timer::stop()
44+{
45+ m_timer.stop();
46+ AbstractTimer::stop();
47+}
48+
49+bool Timer::isSingleShot() const
50+{
51+ return m_timer.isSingleShot();
52+}
53+
54+void Timer::setSingleShot(bool value)
55+{
56+ m_timer.setSingleShot(value);
57+}
58+
59+} // namespace UnityUtil
plugins/Utils/Timer.hnew file+79
@@ -0,0 +1,79 @@
1+/*
2+ * Copyright (C) 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+ */
16+
17+#ifndef UNITYUTIL_TIMER_H
18+#define UNITYUTIL_TIMER_H
19+
20+#include "ElapsedTimer.h"
21+
22+#include <QObject>
23+#include <QPointer>
24+#include <QTimer>
25+
26+namespace UnityUtil {
27+
28+/** Defines an interface for a Timer. Useful for tests. */
29+class AbstractTimer : public QObject
30+{
31+ Q_OBJECT
32+public:
33+ AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}
34+ virtual int interval() const = 0;
35+ virtual void setInterval(int msecs) = 0;
36+ virtual void start() { m_isRunning = true; }
37+ virtual void stop() { m_isRunning = false; }
38+ bool isRunning() const { return m_isRunning; }
39+ virtual bool isSingleShot() const = 0;
40+ virtual void setSingleShot(bool value) = 0;
41+Q_SIGNALS:
42+ void timeout();
43+private:
44+ bool m_isRunning;
45+};
46+
47+/** A QTimer wrapper */
48+class Timer : public AbstractTimer
49+{
50+ Q_OBJECT
51+public:
52+ Timer(QObject *parent = nullptr);
53+
54+ int interval() const override;
55+ void setInterval(int msecs) override;
56+ void start() override;
57+ void stop() override;
58+ bool isSingleShot() const override;
59+ void setSingleShot(bool value) override;
60+private:
61+ QTimer m_timer;
62+};
63+
64+class AbstractTimerFactory
65+{
66+public:
67+ virtual ~AbstractTimerFactory() {}
68+ virtual AbstractTimer *create(QObject *parent = nullptr) = 0;
69+};
70+
71+class TimerFactory : public AbstractTimerFactory
72+{
73+public:
74+ AbstractTimer *create(QObject *parent = nullptr) override { return new Timer(parent); }
75+};
76+
77+} // namespace UnityUtil
78+
79+#endif // UNITYUTIL_TIMER_H
plugins/Utils/plugin.cpp+2−3
@@ -12,8 +12,6 @@
1212 *
1313 * You should have received a copy of the GNU General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Michał Sawicz <michal.sawicz@canonical.com>
1715 */
1816
1917// Qt
@@ -21,12 +19,12 @@
2119#include <QDBusConnection>
2220#include <QQmlContext>
2321#include <QtQuick/QQuickWindow>
24−#include <QDebug>
2522// self
2623#include "plugin.h"
2724
2825// local
2926#include "easingcurve.h"
27+#include "HomeKeyWatcher.h"
3028#include "inputwatcher.h"
3129#include "qlimitproxymodelqml.h"
3230#include "unitysortfilterproxymodelqml.h"
@@ -55,6 +53,7 @@ static QObject *createConstants(QQmlEngine *engine, QJSEngine *scriptEngine)
5553void UtilsPlugin::registerTypes(const char *uri)
5654{
5755 Q_ASSERT(uri == QLatin1String("Utils"));
56+ qmlRegisterType<HomeKeyWatcher>(uri, 0, 1, "HomeKeyWatcher");
5857 qmlRegisterType<QAbstractItemModel>();
5958 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
6059 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
qml/Shell.qml+4
@@ -202,6 +202,10 @@ Item {
202202 Keys.onReleased: physicalKeysMapper.onKeyReleased(event);
203203 }
204204
205+ HomeKeyWatcher {
206+ onActivated: { launcher.fadeOut(); shell.showHome(); }
207+ }
208+
205209 Item {
206210 id: stages
207211 objectName: "stages"
tests/plugins/Utils/CMakeLists.txt+1
@@ -25,6 +25,7 @@ run_tests(
2525 qlimitproxymodeltest
2626 unitysortfilterproxymodeltest
2727 timeformattertest
28+ homekeywatchertest
2829 )
2930
3031# plain qml test
tests/plugins/Utils/homekeywatchertest.cppnew file+323
@@ -0,0 +1,323 @@
1+/*
2+ * Copyright (C) 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+ */
16+
17+#include "HomeKeyWatcher.h"
18+
19+#include <QTest>
20+#include <QSignalSpy>
21+
22+
23+namespace UnityUtil {
24+class FakeElapsedTimer : public AbstractElapsedTimer {
25+public:
26+ static qint64 msecsSinceEpoch;
27+
28+ FakeElapsedTimer() { start(); }
29+
30+ void start() override { m_msecsSinceReference = msecsSinceEpoch; }
31+ qint64 msecsSinceReference() const override { return m_msecsSinceReference; }
32+ qint64 elapsed() const override { return msecsSinceEpoch - m_msecsSinceReference; }
33+
34+private:
35+ qint64 m_msecsSinceReference;
36+};
37+qint64 FakeElapsedTimer::msecsSinceEpoch = 0;
38+
39+class FakeTimer : public AbstractTimer
40+{
41+ Q_OBJECT
42+public:
43+ FakeTimer(QObject *parent = nullptr);
44+
45+ void update();
46+ qint64 nextTimeoutTime() const { return m_nextTimeoutTime; }
47+
48+ int interval() const override;
49+ void setInterval(int msecs) override;
50+ void start() override;
51+ bool isSingleShot() const override;
52+ void setSingleShot(bool value) override;
53+private:
54+ int m_interval;
55+ bool m_singleShot;
56+ qint64 m_nextTimeoutTime;
57+};
58+
59+class FakeTimerFactory : public AbstractTimerFactory
60+{
61+public:
62+ FakeTimerFactory();
63+ virtual ~FakeTimerFactory();
64+
65+ void updateTime(qint64 targetTime);
66+
67+ AbstractTimer *create(QObject *parent = nullptr) override;
68+ QList<QPointer<FakeTimer>> timers;
69+};
70+} // namespace UnityUtil
71+
72+using namespace UnityUtil;
73+
74+class HomeKeyWatcherTest : public QObject {
75+ Q_OBJECT
76+private Q_SLOTS:
77+ void init(); // called right before each and every test function is executed
78+ void cleanup(); // called right after each and every test function is executed
79+
80+ void touchTapTouch_data();
81+ void touchTapTouch();
82+
83+ void tapWhileTouching();
84+
85+private:
86+ void passTime(qint64 timeSpanMs);
87+
88+ FakeTimerFactory *m_fakeTimerFactory;
89+};
90+
91+void HomeKeyWatcherTest::init()
92+{
93+ m_fakeTimerFactory = new FakeTimerFactory;
94+}
95+
96+void HomeKeyWatcherTest::cleanup()
97+{
98+ delete m_fakeTimerFactory;
99+ m_fakeTimerFactory = nullptr;
100+}
101+
102+
103+void HomeKeyWatcherTest::passTime(qint64 timeSpanMs)
104+{
105+ qint64 finalTime = FakeElapsedTimer::msecsSinceEpoch + timeSpanMs;
106+ m_fakeTimerFactory->updateTime(finalTime);
107+}
108+
109+void HomeKeyWatcherTest::touchTapTouch_data()
110+{
111+ QTest::addColumn<int>("silenceBeforeTap");
112+ QTest::addColumn<int>("tapDuration");
113+ QTest::addColumn<int>("silenceAfterTap");
114+ QTest::addColumn<int>("expectedActivatedCount");
115+
116+ QTest::newRow("tap followed by touch") << 2000 << 50 << 10 << 0;
117+ QTest::newRow("touch, tap and touch") << 10 << 50 << 10 << 0;
118+ QTest::newRow("touch followed by tap") << 10 << 50 << 2000 << 0;
119+ QTest::newRow("touch followed by long tap") << 10 << 500 << 2000 << 0;
120+ QTest::newRow("isolated tap") << 1000 << 50 << 1000 << 1;
121+ QTest::newRow("isolated long press") << 1000 << 200 << 1000 << 0;
122+}
123+
124+void HomeKeyWatcherTest::touchTapTouch()
125+{
126+ QFETCH(int, silenceBeforeTap);
127+ QFETCH(int, tapDuration);
128+ QFETCH(int, silenceAfterTap);
129+ QFETCH(int, expectedActivatedCount);
130+ HomeKeyWatcher homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
131+ QSignalSpy activatedSpy(&homeKeyWatcher, SIGNAL(activated()));
132+ QVERIFY(activatedSpy.isValid());
133+
134+ {
135+ QTouchEvent touchEvent(QEvent::TouchBegin);
136+ homeKeyWatcher.update(&touchEvent);
137+ }
138+ passTime(100);
139+ {
140+ QTouchEvent touchEvent(QEvent::TouchUpdate);
141+ homeKeyWatcher.update(&touchEvent);
142+ }
143+ passTime(100);
144+ {
145+ QTouchEvent touchEvent(QEvent::TouchEnd);
146+ homeKeyWatcher.update(&touchEvent);
147+ }
148+
149+ passTime(silenceBeforeTap);
150+
151+ {
152+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
153+ homeKeyWatcher.update(&keyEvent);
154+ }
155+ int tapTime = 0;
156+ while (tapTime < tapDuration) {
157+ passTime(10);
158+ tapTime += 10;
159+ if (tapTime + 10 >= tapDuration) {
160+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
161+ homeKeyWatcher.update(&keyEvent);
162+ } else {
163+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier, QString(), true /*autorepeat*/);
164+ homeKeyWatcher.update(&keyEvent);
165+ }
166+ }
167+
168+ passTime(silenceAfterTap);
169+
170+ {
171+ QTouchEvent touchEvent(QEvent::TouchBegin);
172+ homeKeyWatcher.update(&touchEvent);
173+ }
174+ passTime(100);
175+ {
176+ QTouchEvent touchEvent(QEvent::TouchUpdate);
177+ homeKeyWatcher.update(&touchEvent);
178+ }
179+ passTime(100);
180+ {
181+ QTouchEvent touchEvent(QEvent::TouchEnd);
182+ homeKeyWatcher.update(&touchEvent);
183+ }
184+ passTime(1000);
185+
186+ QCOMPARE(activatedSpy.count(), expectedActivatedCount);
187+}
188+
189+void HomeKeyWatcherTest::tapWhileTouching()
190+{
191+ HomeKeyWatcher homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
192+ QSignalSpy activatedSpy(&homeKeyWatcher, SIGNAL(activated()));
193+ QVERIFY(activatedSpy.isValid());
194+
195+ {
196+ QTouchEvent touchEvent(QEvent::TouchBegin);
197+ homeKeyWatcher.update(&touchEvent);
198+ }
199+ passTime(1000);
200+ {
201+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
202+ homeKeyWatcher.update(&keyEvent);
203+ }
204+ passTime(100);
205+ {
206+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
207+ homeKeyWatcher.update(&keyEvent);
208+ }
209+ passTime(1000);
210+ {
211+ QTouchEvent touchEvent(QEvent::TouchEnd);
212+ homeKeyWatcher.update(&touchEvent);
213+ }
214+ passTime(1000);
215+
216+
217+ QCOMPARE(activatedSpy.count(), 0);
218+}
219+
220+/////////////////////////////////// FakeTimer //////////////////////////////////
221+
222+FakeTimer::FakeTimer(QObject *parent)
223+ : UnityUtil::AbstractTimer(parent)
224+ , m_interval(0)
225+ , m_singleShot(true)
226+{
227+}
228+
229+void FakeTimer::update()
230+{
231+ if (!isRunning()) {
232+ return;
233+ }
234+
235+ if (m_nextTimeoutTime <= FakeElapsedTimer::msecsSinceEpoch) {
236+ if (isSingleShot()) {
237+ stop();
238+ } else {
239+ m_nextTimeoutTime += interval();
240+ }
241+ Q_EMIT timeout();
242+ }
243+}
244+
245+void FakeTimer::start()
246+{
247+ AbstractTimer::start();
248+ m_nextTimeoutTime = FakeElapsedTimer::msecsSinceEpoch + (qint64)interval();
249+}
250+
251+int FakeTimer::interval() const
252+{
253+ return m_interval;
254+}
255+
256+void FakeTimer::setInterval(int msecs)
257+{
258+ m_interval = msecs;
259+}
260+
261+bool FakeTimer::isSingleShot() const
262+{
263+ return m_singleShot;
264+}
265+
266+void FakeTimer::setSingleShot(bool value)
267+{
268+ m_singleShot = value;
269+}
270+
271+/////////////////////////////////// FakeTimerFactory //////////////////////////////////
272+
273+FakeTimerFactory::FakeTimerFactory()
274+{
275+}
276+
277+FakeTimerFactory::~FakeTimerFactory()
278+{
279+ for (int i = 0; i < timers.count(); ++i) {
280+ FakeTimer *timer = timers[i].data();
281+ if (timer) {
282+ delete timer;
283+ }
284+ }
285+}
286+
287+void FakeTimerFactory::updateTime(qint64 targetTime)
288+{
289+ qint64 minTimeoutTime = targetTime;
290+
291+ for (int i = 0; i < timers.count(); ++i) {
292+ FakeTimer *timer = timers[i].data();
293+ if (timer && timer->isRunning() && timer->nextTimeoutTime() < minTimeoutTime) {
294+ minTimeoutTime = timer->nextTimeoutTime();
295+ }
296+ }
297+
298+ FakeElapsedTimer::msecsSinceEpoch = minTimeoutTime;
299+
300+ for (int i = 0; i < timers.count(); ++i) {
301+ FakeTimer *timer = timers[i].data();
302+ if (timer) {
303+ timer->update();
304+ }
305+ }
306+
307+ if (FakeElapsedTimer::msecsSinceEpoch < targetTime) {
308+ updateTime(targetTime);
309+ }
310+}
311+
312+AbstractTimer *FakeTimerFactory::create(QObject *parent)
313+{
314+ FakeTimer *fakeTimer = new FakeTimer(parent);
315+
316+ timers.append(fakeTimer);
317+
318+ return fakeTimer;
319+}
320+
321+QTEST_GUILESS_MAIN(HomeKeyWatcherTest)
322+
323+#include "homekeywatchertest.moc"