Merge lp:~vicamo/qtubuntu-sensors/reimplement-haptics-backend into lp:qtubuntu-sensors

Proposed by You-Sheng Yang
Status: Merged
Merged at revision: 93
Proposed branch: lp:~vicamo/qtubuntu-sensors/reimplement-haptics-backend
Merge into: lp:qtubuntu-sensors
Diff against target: 248 lines (+93/-46)
3 files modified
plugins/feedback/CMakeLists.txt (+3/-5)
plugins/feedback/core_feedback.cpp (+84/-38)
plugins/feedback/core_feedback.h (+6/-3)
To merge this branch: bzr merge lp:~vicamo/qtubuntu-sensors/reimplement-haptics-backend
Reviewer Review Type Date Requested Status
Thomas Voß Pending
Review via email: mp+300839@code.launchpad.net

Commit message

This change rewrites QtFeedbackHapticsEffect backend for ubuntu.

The original implementation is to call APIs in libubuntu-platform-api, which then issue D-Bus calls to usensord. However, it seems in some cases instantiating a D-Bus call in such Qt module may result in segmentation fault. This change rewrites QtFeedbackHapticsEffect backend with QtDBus directly and works around this issue.

This change also tries to conform to QtFeedbackHaptics features definitions. Duration/period is now correctly supported, although this doesn't mean much because usensord does not support variable vibration intensity. It also provides a chance to stop a periodical vibration. The enable/state properties are now correctly set and returned.

Description of the change

This change rewrites QtFeedbackHapticsEffect backend for ubuntu.

The original implementation is to call APIs in libubuntu-platform-api, which then issue D-Bus calls to usensord. However, it seems in some cases instantiating a D-Bus call in such Qt module may result in segmentation fault. This change rewrites QtFeedbackHapticsEffect backend with QtDBus directly and works around this issue.

This change also tries to conform to QtFeedbackHaptics features definitions. Duration/period is now correctly supported, although this doesn't mean much because usensord does not support variable vibration intensity. It also provides a chance to stop a periodical vibration. The enable/state properties are now correctly set and returned.

To post a comment you must log in.
Revision history for this message
You-Sheng Yang (vicamo) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/feedback/CMakeLists.txt'
2--- plugins/feedback/CMakeLists.txt 2014-06-24 12:17:06 +0000
3+++ plugins/feedback/CMakeLists.txt 2016-07-22 06:49:35 +0000
4@@ -1,9 +1,8 @@
5 find_package(PkgConfig)
6 find_package(Qt5Core REQUIRED)
7+find_package(Qt5DBus REQUIRED)
8 find_package(Qt5Feedback REQUIRED)
9
10-pkg_check_modules(UBUNTU_PLATFORM_API ubuntu-platform-api REQUIRED)
11-
12 qt5_add_resources(FEEDBACK_RESOURCES feedback.qrc)
13
14 add_library(
15@@ -22,7 +21,7 @@
16
17 message(STATUS "Installing Qt5 feedback plugin to: ${PLUGIN_INSTALL_LOCATION}")
18
19-qt5_use_modules(qtfeedback_ubuntu Core Feedback)
20+qt5_use_modules(qtfeedback_ubuntu Core DBus Feedback)
21
22 target_link_libraries(
23 qtfeedback_ubuntu
24@@ -30,9 +29,8 @@
25 ${CMAKE_THREAD_LIBS_INIT}
26
27 Qt5::Core
28+ Qt5::DBus
29 Qt5::Feedback
30-
31- ${UBUNTU_PLATFORM_API_LIBRARIES}
32 )
33
34 install(
35
36=== modified file 'plugins/feedback/core_feedback.cpp'
37--- plugins/feedback/core_feedback.cpp 2015-09-29 12:53:18 +0000
38+++ plugins/feedback/core_feedback.cpp 2016-07-22 06:49:35 +0000
39@@ -29,24 +29,20 @@
40 #include <QtCore/QTimer>
41 #include <QtCore/QProcess>
42 #include <QtCore/QFileInfo>
43+#include <QDBusInterface>
44+#include <QDBusPendingCall>
45+#include <QDBusPendingCallWatcher>
46+#include <QDBusPendingReply>
47
48 core::Feedback::Feedback() : QObject(),
49- m_vibrator(NULL)
50+ enabled(false),
51+ state(QFeedbackEffect::Stopped)
52 {
53 actuatorList << createFeedbackActuator(this, 42);
54-
55- if (qgetenv("UBUNTU_PLATFORM_API_BACKEND").isNull())
56- return;
57-
58- m_vibrator = ua_sensors_haptic_new();
59- ua_sensors_haptic_enable(m_vibrator);
60 }
61
62 core::Feedback::~Feedback()
63 {
64- if (m_vibrator) {
65- ua_sensors_haptic_destroy(m_vibrator);
66- }
67 }
68
69 QFeedbackInterface::PluginPriority core::Feedback::pluginPriority()
70@@ -59,11 +55,12 @@
71 return actuatorList;
72 }
73
74-void core::Feedback::setActuatorProperty(const QFeedbackActuator&, ActuatorProperty prop, const QVariant &)
75+void core::Feedback::setActuatorProperty(const QFeedbackActuator&, ActuatorProperty prop, const QVariant &value)
76 {
77 switch (prop)
78 {
79 case Enabled:
80+ enabled = value.toBool();
81 break;
82 default:
83 break;
84@@ -78,7 +75,7 @@
85 {
86 case Name: result = QString::fromLocal8Bit("Ubuntu Vibrator"); break;
87 case State: result = actuator.isValid() ? QFeedbackActuator::Ready : QFeedbackActuator::Unknown; break;
88- case Enabled: result = true; break;
89+ case Enabled: result = enabled; break;
90 }
91
92 return result;
93@@ -90,37 +87,88 @@
94
95 switch(cap)
96 {
97- case QFeedbackActuator::Envelope:
98- case QFeedbackActuator::Period: result = true; break;
99+ case QFeedbackActuator::Envelope: result = true; break;
100+ case QFeedbackActuator::Period: result = false; break;
101 }
102
103 return result;
104 }
105
106-void core::Feedback::updateEffectProperty(const QFeedbackHapticsEffect *effect, EffectProperty)
107-{
108- if (effect->period() != -1) {
109- /* Not currently supported */
110- reportError(effect, QFeedbackEffect::UnknownError);
111- }
112-}
113-
114-void core::Feedback::vibrateOnce(const QFeedbackEffect* effect)
115-{
116- int effectiveDuration = effect->duration();
117- switch (effectiveDuration)
118- {
119- case QFeedbackEffect::Infinite:
120- case 0:
121- effectiveDuration = 150;
122- }
123-
124- if (m_vibrator)
125- ua_sensors_haptic_vibrate_once(m_vibrator, effectiveDuration);
126+void core::Feedback::updateEffectProperty(const QFeedbackHapticsEffect *, EffectProperty)
127+{
128+}
129+
130+void core::Feedback::hapticsVibrateReply(QDBusPendingCallWatcher *watcher, int period, int repeat)
131+{
132+ QDBusPendingReply<> reply = *watcher;
133+ if (reply.isError()) {
134+ qWarning() << "Failed to vibrate with pattern:" << reply.error().message();
135+ state = QFeedbackEffect::Stopped;
136+ } else {
137+ if ((repeat == QFeedbackEffect::Infinite) || (--repeat > 0))
138+ QTimer::singleShot(period, [=]() { vibrate(period, repeat); });
139+ else
140+ state = QFeedbackEffect::Stopped;
141+ }
142+
143+ watcher->deleteLater();
144+}
145+
146+void core::Feedback::vibrate(int period, int repeat)
147+{
148+ if (!(period && repeat))
149+ state = QFeedbackEffect::Stopped;
150+
151+ if (state != QFeedbackEffect::Running) {
152+ // Maybe stopped/paused before this async call.
153+ return;
154+ }
155+
156+
157+ QDBusInterface iface("com.canonical.usensord",
158+ "/com/canonical/usensord/haptic",
159+ "com.canonical.usensord.haptic");
160+
161+ QDBusPendingCall call = iface.asyncCall("Vibrate", (uint)period);
162+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
163+ connect(watcher, &QDBusPendingCallWatcher::finished,
164+ [=](){ hapticsVibrateReply(watcher, period, repeat); });
165+}
166+
167+void core::Feedback::startVibration(const QFeedbackHapticsEffect *effect)
168+{
169+ int duration = effect->duration();
170+ if (duration == 0)
171+ duration = 150;
172+
173+ int period = effect->period();
174+ int repeat;
175+ if ((duration == QFeedbackEffect::Infinite) || (duration < 0)) {
176+ // If duration is set to QFeedbackEffect::Infinite or a negative
177+ // value, we repeat this effect forever until stopped. The
178+ // effective period should have been set to a positive value or
179+ // 150ms by default.
180+ duration = QFeedbackEffect::Infinite;
181+ repeat = QFeedbackEffect::Infinite;
182+ if (period <= 0)
183+ period = 150;
184+ } else if (period <= 0) {
185+ // If duration is set to a positive value and period is invalid,
186+ // then use duration as period.
187+ repeat = 1;
188+ period = duration;
189+ } else {
190+ // Otherwise, repeat this effect as many times as the duration
191+ // may cover the effect period.
192+ repeat = (duration + period - 1) / period;
193+ }
194+
195+ vibrate(period, repeat);
196 }
197
198 void core::Feedback::setEffectState(const QFeedbackHapticsEffect *effect, QFeedbackEffect::State state)
199 {
200+ this->state = state;
201 switch (state)
202 {
203 case QFeedbackEffect::Stopped:
204@@ -128,7 +176,7 @@
205 case QFeedbackEffect::Paused:
206 break;
207 case QFeedbackEffect::Running:
208- vibrateOnce(effect);
209+ QTimer::singleShot(0, [=]() { startVibration(effect); });
210 break;
211 case QFeedbackEffect::Loading:
212 break;
213@@ -137,7 +185,5 @@
214
215 QFeedbackEffect::State core::Feedback::effectState(const QFeedbackHapticsEffect *)
216 {
217- // We don't currently support on-going vibrations
218- // This can be added when moving to a vibration service
219- return QFeedbackEffect::Stopped;
220+ return state;
221 }
222
223=== modified file 'plugins/feedback/core_feedback.h'
224--- plugins/feedback/core_feedback.h 2015-09-29 12:53:18 +0000
225+++ plugins/feedback/core_feedback.h 2016-07-22 06:49:35 +0000
226@@ -24,7 +24,7 @@
227
228 #include <qfeedbackplugininterfaces.h>
229
230-#include <ubuntu/application/sensors/haptic.h>
231+class QDBusPendingCallWatcher;
232
233 namespace core
234 {
235@@ -56,9 +56,12 @@
236 private:
237 QList<QFeedbackActuator*> actuatorList;
238
239- void vibrateOnce(const QFeedbackEffect* effect);
240+ void hapticsVibrateReply(QDBusPendingCallWatcher *watcher, int period, int repeat);
241+ void vibrate(int period, int repeat);
242+ void startVibration(const QFeedbackHapticsEffect *effect);
243
244- UASensorsHaptic* m_vibrator;
245+ bool enabled;
246+ QFeedbackEffect::State state;
247 };
248 }
249

Subscribers

People subscribed via source and target branches