Merge lp:~cyphermox/ubuntu-system-settings/discoverability-annd-fixes into lp:ubuntu-system-settings

Proposed by Mathieu Trudel-Lapierre
Status: Merged
Approved by: Charles Kerr
Approved revision: 750
Merged at revision: 744
Proposed branch: lp:~cyphermox/ubuntu-system-settings/discoverability-annd-fixes
Merge into: lp:ubuntu-system-settings
Diff against target: 452 lines (+201/-6)
7 files modified
plugins/bluetooth/PageComponent.qml (+45/-1)
plugins/bluetooth/bluetooth.cpp (+20/-2)
plugins/bluetooth/bluetooth.h (+10/-0)
plugins/bluetooth/device.cpp (+25/-0)
plugins/bluetooth/device.h (+9/-0)
plugins/bluetooth/devicemodel.cpp (+74/-0)
plugins/bluetooth/devicemodel.h (+18/-3)
To merge this branch: bzr merge lp:~cyphermox/ubuntu-system-settings/discoverability-annd-fixes
Reviewer Review Type Date Requested Status
Charles Kerr (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+223955@code.launchpad.net

Commit message

Implement discoverability and some bluetooth fixes:
  - Discoverability: make the system visible to other bluetooth devices
  - Trusted: when successfully paired and connected, mark device as Trusted so it can automatically connect again.
  - Connect the Audio interface for all audio devices, including Headsets. Some bluetooth audio devices that don't contain a microphone still show up as Headsets, and won't connect successfully otherwise. This will still work for standard headsets, since Audio connects all audio interfaces.
  - Stop discovery when a device is selected for connection, and it sometimes causes connection attempts to fail.

Description of the change

Implement discoverability and some bluetooth fixes:
  - Discoverability: make the system visible to other bluetooth devices
  - Trusted: when successfully paired and connected, mark device as Trusted so it can automatically connect again.
  - Connect the Audio interface for all audio devices, including Headsets. Some bluetooth audio devices that don't contain a microphone still show up as Headsets, and won't connect successfully otherwise. This will still work for standard headsets, since Audio connects all audio interfaces.
  - Stop discovery when a device is selected for connection, and it sometimes causes connection attempts to fail.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:747
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~mathieu-tl/ubuntu-system-settings/discoverability-annd-fixes/+merge/223955/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-ci/883/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/1073
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/963
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-utopic-amd64-ci/75
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-utopic-armhf-ci/75
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-utopic-armhf-ci/75/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-utopic-i386-ci/75
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/1443
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/1877
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/1877/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/8682
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/831
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1106
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1106/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-system-settings-ci/883/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

There are a couple of things I'd like to see fixed here, but they're small.

Overall, looks very good! Nice work.

review: Needs Fixing
Revision history for this message
Charles Kerr (charlesk) wrote :

There are a couple of things I'd like to see fixed here, but they're small.

Overall, looks very good! Nice work.

review: Needs Fixing
748. By Mathieu Trudel-Lapierre

Remove qWarning's used as debug.

749. By Mathieu Trudel-Lapierre

Keep the discoverability timer as a private member, so it can be explicitly stopped.

750. By Mathieu Trudel-Lapierre

Follow proper convention for returning adapterName; make it const too.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:750
http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-ci/884/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/1081
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/969
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-utopic-amd64-ci/76
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-utopic-armhf-ci/76
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-utopic-armhf-ci/76/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-system-settings-utopic-i386-ci/76
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/1451
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/1891
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/1891/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/8694
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/835
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1112
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1112/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-system-settings-ci/884/rebuild

review: Approve (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/bluetooth/PageComponent.qml'
2--- plugins/bluetooth/PageComponent.qml 2014-06-09 15:12:34 +0000
3+++ plugins/bluetooth/PageComponent.qml 2014-06-20 22:19:44 +0000
4@@ -142,8 +142,51 @@
5 value: bluetoothActionGroup.enabled.state
6 }
7
8+ // Discoverability
9+ ListItem.Subtitled {
10+ enabled: bluetoothActionGroup.enabled
11+
12+ Rectangle {
13+ color: "transparent"
14+ anchors.fill: parent
15+ anchors.topMargin: units.gu(1)
16+
17+ Label {
18+ anchors {
19+ top: parent.top
20+ left: parent.left
21+ topMargin: units.gu(1)
22+ }
23+ height: units.gu(3)
24+ text: backend.discoverable ? i18n.tr("Discoverable") : i18n.tr("Not discoverable")
25+ }
26+
27+ Label {
28+ anchors {
29+ top: parent.top
30+ right: parent.right
31+ topMargin: units.gu(1)
32+ }
33+ height: units.gu(3)
34+ text: backend.discoverable ? backend.adapterName() : ""
35+ color: "darkgrey"
36+ visible: backend.discoverable
37+ enabled: false
38+ }
39+
40+ ActivityIndicator {
41+ anchors {
42+ top: parent.top
43+ right: parent.right
44+ topMargin: units.gu(1)
45+ }
46+ visible: !backend.discoverable
47+ running: !backend.discoverable
48+ }
49+ }
50+ }
51+
52 // Connnected Headset(s)
53-
54 ListItem.Standard {
55 id: connectedHeader
56 text: i18n.tr("Connected devices:")
57@@ -194,6 +237,7 @@
58 iconName: iconName
59 text: getDisplayName(connection, displayName)
60 onClicked: {
61+ backend.stopDiscovery();
62 backend.connectDevice(addressName);
63 }
64 }
65
66=== modified file 'plugins/bluetooth/bluetooth.cpp'
67--- plugins/bluetooth/bluetooth.cpp 2014-06-09 15:12:34 +0000
68+++ plugins/bluetooth/bluetooth.cpp 2014-06-20 22:19:44 +0000
69@@ -53,6 +53,9 @@
70 QObject::connect(&m_devices, SIGNAL(discoveringChanged(bool)),
71 this, SIGNAL(discoveringChanged(bool)));
72
73+ QObject::connect(&m_devices, SIGNAL(discoverableChanged(bool)),
74+ this, SIGNAL(discoverableChanged(bool)));
75+
76 QObject::connect(&m_agent, SIGNAL(onPairingDone()),
77 this, SLOT(onPairingDone()));
78 }
79@@ -65,6 +68,21 @@
80 }
81 }
82
83+void Bluetooth::toggleDiscovery()
84+{
85+ m_devices.toggleDiscovery();
86+}
87+
88+void Bluetooth::startDiscovery()
89+{
90+ m_devices.startDiscovery();
91+}
92+
93+void Bluetooth::stopDiscovery()
94+{
95+ m_devices.stopDiscovery();
96+}
97+
98 /***
99 ****
100 ***/
101@@ -113,7 +131,7 @@
102 if (m_selectedDevice)
103 type = m_selectedDevice->getType();
104 if (type == Device::Type::Headset)
105- m_selectedDevice->disconnect(Device::ConnectionMode::HeadsetMode);
106+ m_selectedDevice->disconnect(Device::ConnectionMode::Audio);
107 else if (type == Device::Type::Headphones)
108 m_selectedDevice->disconnect(Device::ConnectionMode::Audio);
109 else if (type == Device::Type::OtherAudio)
110@@ -131,7 +149,7 @@
111
112 type = device->getType();
113 if (type == Device::Type::Headset)
114- connMode = Device::ConnectionMode::HeadsetMode;
115+ connMode = Device::ConnectionMode::Audio;
116 else if (type == Device::Type::Headphones)
117 connMode = Device::ConnectionMode::Audio;
118 else if (type == Device::Type::OtherAudio)
119
120=== modified file 'plugins/bluetooth/bluetooth.h'
121--- plugins/bluetooth/bluetooth.h 2014-05-30 06:53:11 +0000
122+++ plugins/bluetooth/bluetooth.h 2014-06-20 22:19:44 +0000
123@@ -50,9 +50,14 @@
124 READ isDiscovering
125 NOTIFY discoveringChanged);
126
127+ Q_PROPERTY (bool discoverable
128+ READ isDiscoverable
129+ NOTIFY discoverableChanged);
130+
131 Q_SIGNALS:
132 void selectedDeviceChanged();
133 void discoveringChanged(bool isActive);
134+ void discoverableChanged(bool isActive);
135
136 private Q_SLOTS:
137 void onPairingDone();
138@@ -61,9 +66,13 @@
139 Bluetooth(QObject *parent = 0);
140 ~Bluetooth() {}
141
142+ Q_INVOKABLE QString adapterName() const { return m_devices.adapterName(); }
143 Q_INVOKABLE void setSelectedDevice(const QString &address);
144 Q_INVOKABLE void connectDevice(const QString &address);
145 Q_INVOKABLE void disconnectDevice();
146+ Q_INVOKABLE void toggleDiscovery();
147+ Q_INVOKABLE void startDiscovery();
148+ Q_INVOKABLE void stopDiscovery();
149
150 public:
151 Agent * getAgent();
152@@ -72,6 +81,7 @@
153 QAbstractItemModel * getDisconnectedDevices();
154
155 bool isDiscovering() const { return m_devices.isDiscovering(); }
156+ bool isDiscoverable() const { return m_devices.isDiscoverable(); }
157
158 private:
159 QDBusConnection m_dbus;
160
161=== modified file 'plugins/bluetooth/device.cpp'
162--- plugins/bluetooth/device.cpp 2014-06-09 15:12:34 +0000
163+++ plugins/bluetooth/device.cpp 2014-06-20 22:19:44 +0000
164@@ -35,6 +35,7 @@
165 QObject::connect(this, SIGNAL(iconNameChanged()), this, SIGNAL(deviceChanged()));
166 QObject::connect(this, SIGNAL(addressChanged()), this, SIGNAL(deviceChanged()));
167 QObject::connect(this, SIGNAL(pairedChanged()), this, SIGNAL(deviceChanged()));
168+ QObject::connect(this, SIGNAL(trustedChanged()), this, SIGNAL(deviceChanged()));
169 QObject::connect(this, SIGNAL(typeChanged()), this, SIGNAL(deviceChanged()));
170 QObject::connect(this, SIGNAL(connectionChanged()), this, SIGNAL(deviceChanged()));
171 QObject::connect(this, SIGNAL(strengthChanged()), this, SIGNAL(deviceChanged()));
172@@ -117,6 +118,16 @@
173 qWarning() << "Unhandled connection mode" << mode;
174 }
175
176+void Device::makeTrusted()
177+{
178+ QVariant value;
179+ QDBusVariant trusted(true);
180+
181+ value.setValue(trusted);
182+
183+ m_deviceInterface->asyncCall("SetProperty", "Trusted", value);
184+}
185+
186 /***
187 ****
188 ***/
189@@ -162,6 +173,14 @@
190 }
191 }
192
193+void Device::setTrusted(bool trusted)
194+{
195+ if (m_trusted != trusted) {
196+ m_trusted = trusted;
197+ Q_EMIT(trustedChanged());
198+ }
199+}
200+
201 void Device::setConnection(Connection connection)
202 {
203 if (m_connection != connection) {
204@@ -204,6 +223,9 @@
205 else
206 c = m_isConnected ? Connection::Connected : Connection::Disconnected;
207
208+ if (m_isConnected && m_paired && !m_trusted)
209+ makeTrusted();
210+
211 setConnection(c);
212 }
213
214@@ -223,6 +245,9 @@
215 setType(getTypeFromClass(value.toUInt()));
216 } else if (key == "Paired") { // org.bluez.Device
217 setPaired(value.toBool());
218+ updateConnection();
219+ } else if (key == "Trusted") { // org.bluez.Device
220+ setTrusted(value.toBool());
221 } else if (key == "Icon") { // org.bluez.Device
222 m_fallbackIconName = value.toString();
223 updateIcon ();
224
225=== modified file 'plugins/bluetooth/device.h'
226--- plugins/bluetooth/device.h 2014-05-30 06:53:11 +0000
227+++ plugins/bluetooth/device.h 2014-06-20 22:19:44 +0000
228@@ -49,6 +49,10 @@
229 READ isPaired
230 NOTIFY pairedChanged)
231
232+ Q_PROPERTY(bool trusted
233+ READ isTrusted
234+ NOTIFY trustedChanged)
235+
236 Q_PROPERTY(Connection connection
237 READ getConnection
238 NOTIFY connectionChanged)
239@@ -81,6 +85,7 @@
240 void addressChanged();
241 void typeChanged();
242 void pairedChanged();
243+ void trustedChanged();
244 void connectionChanged();
245 void strengthChanged();
246 void deviceChanged(); // catchall for any change
247@@ -91,6 +96,7 @@
248 const QString& getIconName() const { return m_iconName; }
249 Type getType() const { return m_type; }
250 bool isPaired() const { return m_paired; }
251+ bool isTrusted() const { return m_trusted; }
252 Connection getConnection() const { return m_connection; }
253 Strength getStrength() const { return m_strength; }
254 QString getPath() const { return m_deviceInterface->path(); }
255@@ -103,6 +109,7 @@
256 QString m_fallbackIconName;
257 Type m_type = Type::Other;
258 bool m_paired = false;
259+ bool m_trusted = false;
260 Connection m_connection = Connection::Disconnected;
261 Strength m_strength = Strength::Fair;
262 bool m_isConnected = false;
263@@ -118,6 +125,7 @@
264 void setAddress(const QString &address);
265 void setType(Type type);
266 void setPaired(bool paired);
267+ void setTrusted(bool trusted);
268 void setConnection(Connection connection);
269 void setStrength(Strength strength);
270 void updateIcon();
271@@ -129,6 +137,7 @@
272 Device(const QString &path, QDBusConnection &bus);
273 bool isValid() const { return getType() != Type::Other; }
274 void connect(ConnectionMode);
275+ void makeTrusted();
276 void disconnect(ConnectionMode);
277 void setProperties(const QMap<QString,QVariant> &properties);
278
279
280=== modified file 'plugins/bluetooth/devicemodel.cpp'
281--- plugins/bluetooth/devicemodel.cpp 2014-05-30 06:53:11 +0000
282+++ plugins/bluetooth/devicemodel.cpp 2014-06-20 22:19:44 +0000
283@@ -19,6 +19,7 @@
284 */
285
286 #include <QDBusReply>
287+#include <QDebug>
288
289 #include "devicemodel.h"
290 #include "dbus-shared.h"
291@@ -135,6 +136,8 @@
292 const QString interface = m_bluezAdapter->interface();
293
294 stopDiscovery();
295+ m_discoverableTimer.stop();
296+ trySetDiscoverable(false);
297
298 bus.disconnect(service, path, interface, "DeviceCreated",
299 this, SLOT(slotDeviceCreated(const QDBusObjectPath&)));
300@@ -144,8 +147,11 @@
301 this, SLOT(slotDeviceFound(const QString&, const QMap<QString,QVariant>&)));
302 bus.disconnect(service, path, interface, "DeviceDisappeared",
303 this, SLOT(slotDeviceDisappeared(const QString&)));
304+ bus.disconnect(service, path, interface, "PropertyChanged",
305+ this, SLOT(slotPropertyChanged(const QString&, const QDBusVariant&)));
306
307 m_bluezAdapter.reset(0);
308+ m_adapterName.clear();
309
310 beginResetModel();
311 m_devices.clear();
312@@ -171,10 +177,22 @@
313 this, SLOT(slotDeviceFound(const QString&, const QMap<QString,QVariant>&)));
314 m_dbus.connect(service, path, interface, "DeviceDisappeared",
315 this, SLOT(slotDeviceDisappeared(const QString&)));
316+ m_dbus.connect(service, path, interface, "PropertyChanged",
317+ this, SLOT(slotPropertyChanged(const QString&, const QDBusVariant&)));
318
319 m_bluezAdapter.reset(i);
320 startDiscovery();
321 updateDevices();
322+
323+ QDBusReply<QMap<QString,QVariant> > properties = m_bluezAdapter->call("GetProperties");
324+ if (properties.isValid())
325+ setProperties(properties.value());
326+
327+ // Delay enabling discoverability by 1 second.
328+ m_discoverableTimer.setSingleShot(true);
329+ connect(&m_discoverableTimer, SIGNAL(timeout()), this, SLOT(slotEnableDiscoverable()));
330+ m_discoverableTimer.start(1000);
331+
332 }
333 }
334
335@@ -199,6 +217,62 @@
336 }
337 }
338
339+void DeviceModel::setProperties(const QMap<QString,QVariant> &properties)
340+{
341+ QMapIterator<QString,QVariant> it(properties);
342+ while (it.hasNext()) {
343+ it.next();
344+ updateProperty(it.key(), it.value());
345+ }
346+}
347+
348+void DeviceModel::updateProperty(const QString &key, const QVariant &value)
349+{
350+ if (key == "Name") {
351+ m_adapterName = value.toString();
352+ } else if (key == "Address") {
353+ m_adapterAddress = value.toString();
354+ } else if (key == "Pairable") {
355+ m_isPairable = value.toBool();
356+ } else if (key == "Discoverable") {
357+ setDiscoverable(value.toBool());
358+ }
359+}
360+
361+void DeviceModel::setDiscoverable(bool discoverable)
362+{
363+ if (m_isDiscoverable != discoverable) {
364+ m_isDiscoverable = discoverable;
365+ Q_EMIT(discoverableChanged(m_isDiscoverable));
366+ }
367+}
368+
369+void DeviceModel::slotEnableDiscoverable()
370+{
371+ trySetDiscoverable(true);
372+}
373+
374+void DeviceModel::trySetDiscoverable(bool discoverable)
375+{
376+ QVariant value;
377+ QDBusVariant disc(discoverable);
378+ QDBusReply<void > reply;
379+
380+ value.setValue(disc);
381+
382+ if (m_bluezAdapter && m_bluezAdapter->isValid()) {
383+ reply = m_bluezAdapter->call("SetProperty", "Discoverable", value);
384+ if (!reply.isValid())
385+ qWarning() << "Error setting device discoverable:" << reply.error();
386+ }
387+}
388+
389+void DeviceModel::slotPropertyChanged(const QString &key,
390+ const QDBusVariant &value)
391+{
392+ updateProperty (key, value.variant());
393+}
394+
395 /***
396 ****
397 ***/
398
399=== modified file 'plugins/bluetooth/devicemodel.h'
400--- plugins/bluetooth/devicemodel.h 2014-05-30 06:53:11 +0000
401+++ plugins/bluetooth/devicemodel.h 2014-06-20 22:19:44 +0000
402@@ -61,24 +61,37 @@
403
404 QSharedPointer<Device> getDeviceFromAddress(const QString &address);
405 QSharedPointer<Device> getDeviceFromPath(const QString &path);
406+ QString adapterName() const { return m_adapterName; }
407
408 public:
409 bool isDiscovering() const { return m_isDiscovering; }
410+ bool isDiscoverable() const { return m_isDiscoverable; }
411 void pairDevice(const QString &address);
412+ void stopDiscovery();
413+ void startDiscovery();
414+ void toggleDiscovery();
415
416 Q_SIGNALS:
417 void discoveringChanged(bool isDiscovering);
418+ void discoverableChanged(bool isDiscoverable);
419
420 private:
421 QDBusConnection m_dbus;
422 QDBusInterface m_bluezManager;
423
424+ void setProperties(const QMap<QString,QVariant> &properties);
425+ void updateProperty(const QString &key, const QVariant &value);
426+
427+ QString m_adapterName;
428+ QString m_adapterAddress;
429+ bool m_isPairable = false;
430 bool m_isDiscovering = false;
431+ bool m_isDiscoverable = false;
432 QTimer m_timer;
433- void stopDiscovery();
434- void startDiscovery();
435- void toggleDiscovery();
436+ QTimer m_discoverableTimer;
437 void restartTimer();
438+ void trySetDiscoverable(bool discoverable);
439+ void setDiscoverable(bool discoverable);
440
441 QScopedPointer<QDBusInterface> m_bluezAdapter;
442 void clearAdapter();
443@@ -93,7 +106,9 @@
444 void emitRowChanged(int row);
445
446 private Q_SLOTS:
447+ void slotPropertyChanged(const QString &key, const QDBusVariant &value);
448 void slotTimeout();
449+ void slotEnableDiscoverable();
450 void slotDeviceChanged();
451 void slotDeviceCreated(const QDBusObjectPath &);
452 void slotDeviceRemoved(const QDBusObjectPath &);

Subscribers

People subscribed via source and target branches