Merge lp:~morphis/ubuntu-system-settings/bluez5-support into lp:ubuntu-system-settings

Proposed by Simon Fels on 2015-09-17
Status: Merged
Approved by: Sebastien Bacher on 2015-11-12
Approved revision: 1567
Merged at revision: 1562
Proposed branch: lp:~morphis/ubuntu-system-settings/bluez5-support
Merge into: lp:ubuntu-system-settings
Diff against target: 3883 lines (+1901/-877)
44 files modified
debian/control (+1/-1)
plugins/bluetooth/AuthorizationRequestDialog.qml (+53/-0)
plugins/bluetooth/CMakeLists.txt (+16/-3)
plugins/bluetooth/DevicePage.qml (+3/-2)
plugins/bluetooth/DisplayPinCodeDialog.qml (+54/-0)
plugins/bluetooth/PageComponent.qml (+81/-17)
plugins/bluetooth/agent.cpp (+77/-54)
plugins/bluetooth/agent.h (+9/-2)
plugins/bluetooth/agent.xml (+0/-38)
plugins/bluetooth/agentadaptor.cpp (+0/-75)
plugins/bluetooth/agentadaptor.h (+0/-79)
plugins/bluetooth/bluetooth.cpp (+19/-51)
plugins/bluetooth/bluetooth.h (+3/-1)
plugins/bluetooth/bluez_adapter1.cpp (+26/-0)
plugins/bluetooth/bluez_adapter1.h (+66/-0)
plugins/bluetooth/bluez_agent1adaptor.cpp (+93/-0)
plugins/bluetooth/bluez_agent1adaptor.h (+96/-0)
plugins/bluetooth/bluez_agentmanager1.cpp (+26/-0)
plugins/bluetooth/bluez_agentmanager1.h (+68/-0)
plugins/bluetooth/bluez_device1.cpp (+26/-0)
plugins/bluetooth/bluez_device1.h (+85/-0)
plugins/bluetooth/bluez_helper.h (+29/-0)
plugins/bluetooth/dbus-shared.h (+9/-0)
plugins/bluetooth/device.cpp (+181/-175)
plugins/bluetooth/device.h (+21/-24)
plugins/bluetooth/devicemodel.cpp (+254/-233)
plugins/bluetooth/devicemodel.h (+21/-13)
plugins/bluetooth/freedesktop_objectmanager.cpp (+26/-0)
plugins/bluetooth/freedesktop_objectmanager.h (+58/-0)
plugins/bluetooth/freedesktop_properties.cpp (+26/-0)
plugins/bluetooth/freedesktop_properties.h (+71/-0)
plugins/bluetooth/org.bluez.Adapter1.xml (+11/-0)
plugins/bluetooth/org.bluez.Agent1.xml (+55/-0)
plugins/bluetooth/org.bluez.AgentManager1.xml (+16/-0)
plugins/bluetooth/org.bluez.Device1.xml (+16/-0)
plugins/bluetooth/org.freedesktop.DBus.ObjectManager.xml (+19/-0)
plugins/bluetooth/org.freedesktop.DBus.Properties.xml (+27/-0)
plugins/bluetooth/plugin.cpp (+6/-0)
tests/plugins/bluetooth/CMakeLists.txt (+17/-16)
tests/plugins/bluetooth/fakebluez.cpp (+41/-4)
tests/plugins/bluetooth/fakebluez.h (+9/-6)
tests/plugins/bluetooth/tst_bluetooth.cpp (+100/-29)
tests/plugins/bluetooth/tst_device.cpp (+67/-54)
tests/plugins/bluetooth/tst_devicemodel.cpp (+19/-0)
To merge this branch: bzr merge lp:~morphis/ubuntu-system-settings/bluez5-support
Reviewer Review Type Date Requested Status
Sebastien Bacher (community) 2015-09-17 Approve on 2015-11-12
Jonas G. Drange (community) Approve on 2015-11-12
PS Jenkins bot continuous-integration Needs Fixing on 2015-11-12
Review via email: mp+271456@code.launchpad.net

Commit message

Ported the Bluetooth plugin to the changed BlueZ API which comes with version 5.x. The overall device management gets a lot more reliable with this. Superfluous code was dropped when possible. Also the unit tests got a rework and all pass now.

To post a comment you must log in.
1532. By Simon Fels on 2015-09-17

Don't allow connect/disconnect of a device when bluetooth is turned off

1533. By Simon Fels on 2015-09-17

Correctly unregister our agent with BlueZ

1534. By Simon Fels on 2015-09-17

Fix list management according to current bluetooth power state

1535. By Simon Fels on 2015-09-17

Update Bluetooth implementation to use BlueZ 5 API

1536. By Simon Fels on 2015-09-18

Disable bluetooth tests until they are migrated

1537. By Simon Fels on 2015-09-18

Make tests working and cleanup code

1538. By Simon Fels on 2015-09-18

Restructure qdbus wrappers a bit

Sebastien Bacher (seb128) wrote :

Thanks Simon, that seems to work mostly fine, some issues from testing that version on wily (some might not be new/were already there previous bluez)

- the "discoverable" label is not followed by the machine name

- clicking on a device in the autoconnect list and doing "forget that device" seems to not work (it was not reliable before or had delay but now seems to not work at all), in fact it works but the UI doesn't refresh until you exit the panel and enter it back

- sometimes the discoverable status hits "WARNING - Failed to start device discovery: "Operation already in progress"", it seems to keep trying and the item spins but never settle

- when pairing a keyboard, the device is correctly paired and connected (e.g I can type on it), but the list still show it as "to connect", the details view also has state "disconnected" (works after exiting the panel and coming back)

- the devices list once open doesn't seem to pick up new devices dynamically

In fact from those notes it seems that the devices list is not refreshed in some cases where it should (basically after actions like pairing, forgetting devices, etc)

1539. By Simon Fels on 2015-09-25

Merge with trunk

* Update Bluetooth implementation to use the BlueZ 5 DBus API
[ jonas-drange ]
* [hotspot] hide/show based on modem availability from Connectivity
  (which also requires a bumped dep). (LP: #1487157)
* [time-date] Migrate threaded code to worker-object pattern, move
  sorting to a worker thread from the GUI thread, and only instantiate
  UbuntuTimeDatePanel plugin once. (LP: #1492260)
* [wifi/wpa2ep] allow passwords of length 1 for wpa enterprise
  authentication schemes. (LP: #1490417)
[ Ken VanDine ]
* ported to libqofono 0.82 (modemTechnologies now
  availableTechnologies)

1540. By Simon Fels on 2015-10-05

Merge with trunk

* Used the correct property to determine if whoopsie will
  automatically report crashes (LP: #1494442)
[ CI Train Bot ]
* New rebuild forced.
[ jonas-drange ]
* [autopilot] use wait_select_single instead of select_single for all
  click_item
* [security-privacy] fix test broken by recent ui changes

1541. By Simon Fels on 2015-10-05

bluetooth: give test a bit more time to let dbus events come in

1542. By Simon Fels on 2015-10-05

Update changelog

1543. By Simon Fels on 2015-10-05

tests: bluetooth: give discovery tests a bit more time to process incoming
dbus events.

1544. By Simon Fels on 2015-10-07

Improve agent implementation to handle authorization requests too and register
our agent as default one to get all requests (also those for incoming pairing
requests).

1545. By Simon Fels on 2015-10-07

If device is not paired yet but should be connected pair it first and
continue with connecting it.

1546. By Simon Fels on 2015-10-07

Correct connection state handling after State property for profiles/devices
doesn't exists anymore with BlueZ 5.x

1547. By Simon Fels on 2015-10-08

Update connection state according to the device state

1548. By Simon Fels on 2015-10-09

Install missing bluetooth qml files

1549. By Simon Fels on 2015-10-09

Take 100ms for all event processing when running the bluetooth tests by
default to cause no failures on any hardware platform due to timing reasons.

1550. By Simon Fels on 2015-10-09

Merge with trunk

[ Sebastien Bacher ]
* [hospot] include cmakefile hack to get files listed in qtcreator
* [security-privacy] use the system location as well to look for trust
  store items, that's needed at least for unity8-dash which is not
  distributed as a click and doesn't a .local entry (LP: #1501428)
* [sound] don't display silent mode warnings, sounds should just be
  played when user selected (LP: #1391502)
[ jonas-drange ]
* [phone] encode numbers before passing them to url-dispatcher (LP:
  #1496845)

1551. By Simon Fels on 2015-10-09

Fix incorrect component name

1552. By Simon Fels on 2015-10-12

Allow the user to disconnect devices which are not supported but are
connected. This can happen when a remote device initiates the pairing
process and we just respond to it and allow the pairing to succeed.
Rather than to prevent this we allow this in order to supporte those
types in the future as ones we can deal with.

1553. By Simon Fels on 2015-10-16

bluetooth: Ignore devices with type "other"

1554. By Simon Fels on 2015-10-23

Fix bluetooth tests and enable device class tests again

1555. By Simon Fels on 2015-10-26

Close pairing popup according to the result of the actual operation. The
semantics of the unerlaying API has changed a bit so a rework was needed.

1556. By Simon Fels on 2015-10-27

Merge with trunk

[ CI Train Bot ]
* New rebuild forced.
[ Ken VanDine ]
* Bump Ubuntu.Components imports to 1.3 and fixed UbuntuShape
  deprecations (LP: #1508363)
[ jonas-drange ]
* re-add silentMode property to repair the silent mode switch

1557. By Simon Fels on 2015-10-28

Give us a bit more time to receive dbus events and process them

Sebastien Bacher (seb128) wrote :

there are quite some changes there but things look mostly fine and the change got several round of testing and is working in most cases, giving a preliminary +1 but we should do a full round of testing before landing and have more detailed look at the change, especially from people knowing qt a bit better would be welcome

review: Approve
Sebastien Bacher (seb128) wrote :

Looking a bit more there are some changes needed, we need at least to bump the bluez requirement in debian/control, the uitk import should also be bumped to 1.3 since that landed for ota8

review: Needs Fixing
Sebastien Bacher (seb128) wrote :

The Yes/No labels in new the dialog should probably be rather Allow/Refuse (just commenting about that, more reviewing for later)

review: Needs Fixing
Jonas G. Drange (jonas-drange) wrote :

Looking good, Simon. Some comments:

* I got this output from opening the BT panel and then turning BT off: http://pastebin.ubuntu.com/13123889/
* The “Forgetting a device” test in the test plan [1] fails for my Dell XPS13 Ubuntu Desktop. If I forget the device, the device can be forgotten after it's rediscovered.

review: Needs Fixing
1558. By Simon Fels on 2015-11-10

Only enable forget button when device is paired

1559. By Simon Fels on 2015-11-10

[ Bartosz Kosiorek ]
* Remove "Retry" button, when no internet connection is available. It
  will automatically retry after establishing connection (LP:
  #1479447) (LP: #1479447)
[ Ken VanDine ]
* Don't elide connect to internet label (LP: #1512768)
* Ensure we only check for updates when NetworkingStatus.online is
  true (LP: #1505663)
* [system-settings] Abort request when the onlineStatus changes to
  false (LP: #1505663)
[ CI Train Bot ]
* New rebuild forced.
[ jonas-drange ]
* Deprecated the use of Info endpoint in system_update.cpp and
  hotspot. Exposed detailed version details on UpdateManager. Used
  this to get to a 'tag' key which includes the ota string. Because of
  more advanced system-image testing, about tests now use the
  systemimage dbusmock template. debian/control, s-i-dbus changed to
  3.0.2 because that's where the ota string is. (LP: #1475568)

1560. By Simon Fels on 2015-11-10

Correct changelog

1561. By Simon Fels on 2015-11-10

Bump uitk version to 1.3 and change labels of authorization request dialog

1562. By Simon Fels on 2015-11-10

Bump required bluez version to 5.23 (it's the first version of bluez5 we
had in Ubuntu)

1563. By Simon Fels on 2015-11-11

[ jonas-drange ]
Cache call forwarding summary for each IMSI/ICCID. Block UI until
the CallForwarding binding is ready. Do not assume a failed
callforwarding change means it's disabled (could be forced by
carrier). (LP: #1478049)

1564. By Simon Fels on 2015-11-11

Use correct variable name to pass pincode to the created dialog

1565. By Simon Fels on 2015-11-11

Check for dbus menu model property before accessing it

1566. By Simon Fels on 2015-11-11

Don't try to make us discoverable again when the property changes. This can
happen when bluetooth gets disabled by something else.

Simon Fels (morphis) wrote :

Fixed all review comments. Also did one further fix to enable pairing with devices using LegacyPairing where the DisplayPin dialog didn't came up.

1567. By Simon Fels on 2015-11-12

Detect bluetooth watch devices

Jonas G. Drange (jonas-drange) wrote :

LGTM! Great stuff. Thanks

review: Approve
Sebastien Bacher (seb128) wrote :

the qt imports got bumped from 2.0 to 2.4 in the uitk 1.3 update, unsure if that makes a difference/should be done the same way here, otherwise looks good, thanks!

review: Approve
Simon Fels (morphis) wrote :

Manual test run:

Running tests...
Test project /home/simon/Work/ubuntu/bluetooth/touch-bluez5-upgrade/uss-bluez5-support/build
      Start 1: tst-plugins
 1/11 Test #1: tst-plugins ...................... Passed 0.13 sec
      Start 2: tst-arguments
 2/11 Test #2: tst-arguments .................... Passed 0.00 sec
      Start 3: python3
 3/11 Test #3: python3 .......................... Passed 1.21 sec
      Start 4: test_push_helper
 4/11 Test #4: test_push_helper ................. Passed 0.17 sec
      Start 5: tst-trust-store-model
 5/11 Test #5: tst-trust-store-model ............ Passed 0.25 sec
      Start 6: tst-update-manager
 6/11 Test #6: tst-update-manager ............... Passed 0.13 sec
      Start 7: tst-update
 7/11 Test #7: tst-update ....................... Passed 0.13 sec
      Start 8: tst-network
 8/11 Test #8: tst-network ...................... Passed 0.15 sec
      Start 9: tst-bluetooth
 9/11 Test #9: tst-bluetooth .................... Passed 9.78 sec
      Start 10: tst-bluetooth-devicemodel
10/11 Test #10: tst-bluetooth-devicemodel ........ Passed 3.01 sec
      Start 11: tst-bluetooth-device
11/11 Test #11: tst-bluetooth-device ............. Passed 11.33 sec

100% tests passed, 0 tests failed out of 11

Total Test time (real) = 26.30 sec

1568. By Simon Fels on 2015-11-19

bluetooth: set a timeout of 60 seconds for our dbus calls to the bluez Device
interface

1569. By Simon Fels on 2015-11-19

bluetooth: allow us to connect with bt watch device class devices

1570. By Simon Fels on 2015-11-20

[ Alejandro J. Cura ]
* If a system package gets updated by the user, only show the user's
  copy (LP: #1265250)
[ Bartosz Kosiorek ]
* Allow translating "Unavailable" string (LP: #1511384) (LP: #1511384)
[ Ken VanDine ]
* Don't check for updates if not online (LP: #1505663)
[ Michael Zanetti ]
* Only animate ActivityIndicators when they are visible (LP: #1513450)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2015-10-29 15:48:06 +0000
3+++ debian/control 2015-11-20 08:48:08 +0000
4@@ -60,7 +60,7 @@
5 ${shlibs:Depends},
6 accountsservice,
7 accountsservice-ubuntu-schemas (>= 0.0.3+14.10.20140829~),
8- bluez (>= 4.36),
9+ bluez (>= 5.23),
10 click | ubuntu-snappy-cli,
11 dbus-property-service [amd64 armhf i386],
12 gsettings-desktop-schemas,
13
14=== added file 'plugins/bluetooth/AuthorizationRequestDialog.qml'
15--- plugins/bluetooth/AuthorizationRequestDialog.qml 1970-01-01 00:00:00 +0000
16+++ plugins/bluetooth/AuthorizationRequestDialog.qml 2015-11-20 08:48:08 +0000
17@@ -0,0 +1,53 @@
18+/*
19+ * This file is part of ubuntu-system-settings
20+ *
21+ * Copyright (C) 2013-2015 Canonical Ltd.
22+ *
23+ * This program is free software: you can redistribute it and/or modify it
24+ * under the terms of the GNU General Public License version 3, as published
25+ * by the Free Software Foundation.
26+ *
27+ * This program is distributed in the hope that it will be useful, but
28+ * WITHOUT ANY WARRANTY; without even the implied warranties of
29+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
30+ * PURPOSE. See the GNU General Public License for more details.
31+ *
32+ * You should have received a copy of the GNU General Public License along
33+ * with this program. If not, see <http://www.gnu.org/licenses/>.
34+ */
35+
36+
37+import QtQuick 2.0
38+import Ubuntu.Components 1.3
39+import Ubuntu.Components.Popups 1.3
40+
41+Dialog {
42+ id: root
43+ title: i18n.tr("Bluetooth Pairing Authorization Request")
44+
45+ property string name: "Unknown"
46+
47+ signal accepted
48+ signal declined
49+
50+ // TRANSLATORS: %1 is the name of the bluetooth device which requires authorization
51+ text: i18n.tr("The device %1 wants to pair with this device. Do you want to allow this?").arg(root.name)
52+
53+ Row {
54+ spacing: units.gu(1)
55+ Button {
56+ text: i18n.tr("Allow")
57+ onClicked: {
58+ root.allowed()
59+ PopupUtils.close(root)
60+ }
61+ }
62+ Button {
63+ text: i18n.tr("Refuse")
64+ onClicked: {
65+ root.denied()
66+ PopupUtils.close(root)
67+ }
68+ }
69+ }
70+}
71
72=== modified file 'plugins/bluetooth/CMakeLists.txt'
73--- plugins/bluetooth/CMakeLists.txt 2015-08-26 08:47:44 +0000
74+++ plugins/bluetooth/CMakeLists.txt 2015-11-20 08:48:08 +0000
75@@ -3,21 +3,34 @@
76 set(QML_SOURCES
77 ProvidePinCodeDialog.qml
78 ConfirmPasskeyDialog.qml
79+DisplayPinCodeDialog.qml
80 DisplayPasskeyDialog.qml
81 ProvidePasskeyDialog.qml
82+AuthorizationRequestDialog.qml
83 DevicePage.qml
84 PageComponent.qml
85 )
86
87 add_library(UbuntuBluetoothPanel MODULE
88+ bluez_adapter1.cpp
89+ bluez_agentmanager1.cpp
90+ bluez_device1.cpp
91+ bluez_agent1adaptor.cpp
92+ freedesktop_properties.cpp
93+ freedesktop_objectmanager.cpp
94 agent.cpp
95- agentadaptor.cpp
96 bluetooth.cpp
97 device.cpp
98 devicemodel.cpp
99+ bluez_adapter1.h
100+ bluez_agentmanager1.h
101+ bluez_device1.h
102+ bluez_agent1adaptor.h
103+ freedesktop_properties.h
104+ freedesktop_objectmanager.h
105 plugin.cpp
106- agent.h
107- agentadaptor.h
108+ bluez_helper.h
109+ agent.h
110 bluetooth.h
111 device.h
112 devicemodel.h
113
114=== modified file 'plugins/bluetooth/DevicePage.qml'
115--- plugins/bluetooth/DevicePage.qml 2015-09-18 14:18:11 +0000
116+++ plugins/bluetooth/DevicePage.qml 2015-11-20 08:48:08 +0000
117@@ -58,6 +58,7 @@
118 case Device.Mouse: return i18n.tr("Mouse");
119 case Device.Printer: return i18n.tr("Printer");
120 case Device.Camera: return i18n.tr("Camera");
121+ case Device.Watch: return i18n.tr("Watch");
122 default: return i18n.tr("Other");
123 }
124 }
125@@ -180,7 +181,7 @@
126 pageStack.pop();
127 }
128 visible: backend.selectedDevice ? true : false
129- enabled: backend.selectedDevice ? backend.isSupportedType(backend.selectedDevice.type) : false
130+ enabled: backend.selectedDevice && backend.powered ? (backend.isSupportedType(backend.selectedDevice.type) || backend.selectedDevice.connection != Device.Disconnected) : false
131 }
132 }
133 ListItem.SingleControl {
134@@ -192,7 +193,7 @@
135 backend.resetSelectedDevice();
136 pageStack.pop();
137 }
138- enabled: backend.selectedDevice && backend.selectedDevice.path.length > 0 ? true : false
139+ enabled: backend.selectedDevice && backend.selectedDevice.path.length > 0 && backend.selectedDevice.paired ? true : false
140 }
141 }
142 }
143
144=== added file 'plugins/bluetooth/DisplayPinCodeDialog.qml'
145--- plugins/bluetooth/DisplayPinCodeDialog.qml 1970-01-01 00:00:00 +0000
146+++ plugins/bluetooth/DisplayPinCodeDialog.qml 2015-11-20 08:48:08 +0000
147@@ -0,0 +1,54 @@
148+/*
149+ * This file is part of ubuntu-system-settings
150+ *
151+ * Copyright (C) 2013-2015 Canonical Ltd.
152+ *
153+ * This program is free software: you can redistribute it and/or modify it
154+ * under the terms of the GNU General Public License version 3, as published
155+ * by the Free Software Foundation.
156+ *
157+ * This program is distributed in the hope that it will be useful, but
158+ * WITHOUT ANY WARRANTY; without even the implied warranties of
159+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
160+ * PURPOSE. See the GNU General Public License for more details.
161+ *
162+ * You should have received a copy of the GNU General Public License along
163+ * with this program. If not, see <http://www.gnu.org/licenses/>.
164+ */
165+
166+
167+import QtQuick 2.0
168+import Ubuntu.Components 1.3
169+import Ubuntu.Components.Popups 1.3
170+
171+Dialog {
172+ id: root
173+ title: i18n.tr("Bluetooth Pairing Request")
174+
175+ property string name: "Unknown"
176+ property string pincode: ""
177+
178+ signal canceled
179+
180+ // TRANSLATORS: %1 is the name of the bluetooth device being paired
181+ text: i18n.tr("Please enter the following PIN on %1 and press “Enter” on the keyboard:").arg(root.name)
182+
183+ Label {
184+ text: root.pincode+"⏎"
185+ fontSize: "x-large"
186+ verticalAlignment: Text.AlignVCenter
187+ horizontalAlignment: Text.AlignHCenter
188+ }
189+
190+ Row {
191+ spacing: units.gu(1)
192+ Button {
193+ text: i18n.tr("Cancel")
194+ onClicked: {
195+ root.canceled()
196+ PopupUtils.close(root)
197+ }
198+ width: (parent.width - parent.spacing)
199+ }
200+ }
201+}
202
203=== modified file 'plugins/bluetooth/PageComponent.qml'
204--- plugins/bluetooth/PageComponent.qml 2015-11-05 12:57:06 +0000
205+++ plugins/bluetooth/PageComponent.qml 2015-11-20 08:48:08 +0000
206@@ -34,8 +34,28 @@
207 objectName: "bluetoothPage"
208
209 property var dialogPopupId
210-
211- UbuntuBluetoothPanel { id: backend }
212+ property var currentDevice
213+
214+ function finishDevicePairing() {
215+ if (root.dialogPopupId)
216+ PopupUtils.close(root.dialogPopupId)
217+
218+ root.dialogPopupId = null
219+ root.currentDevice = null
220+ }
221+
222+ UbuntuBluetoothPanel {
223+ id: backend
224+
225+ onDevicePairingDone: {
226+ console.log("Got pairing status notification for device " + device.address)
227+
228+ if (device != root.currentDevice)
229+ return
230+
231+ finishDevicePairing()
232+ }
233+ }
234
235 Timer {
236 id: discoverableTimer
237@@ -71,12 +91,23 @@
238 }
239
240 Component {
241+ id: displayPinCodeDialog
242+ DisplayPinCodeDialog { }
243+ }
244+
245+ Component {
246 id: displayPasskeyDialog
247 DisplayPasskeyDialog { }
248 }
249
250+ Component {
251+ id: authorizationRequestDialog
252+ AuthorizationRequestDialog { }
253+ }
254+
255 Connections {
256 target: backend.agent
257+ onCancelNeeded: finishDevicePairing()
258 onPasskeyConfirmationNeeded: {
259 var request_tag = tag
260 var popup = PopupUtils.open(confirmPasskeyDialog, root, {passkey: passkey, name: device.name})
261@@ -95,23 +126,60 @@
262 popup.canceled.connect(function() {target.providePinCode(request_tag, false, "")})
263 popup.provided.connect(function(pinCode) {target.providePinCode(request_tag, true, pinCode)})
264 }
265+ onDisplayPinCodeNeeded: {
266+ if (!root.dialogPopupId)
267+ {
268+ root.currentDevice = device
269+ root.dialogPopupId = PopupUtils.open(displayPinCodeDialog, root, {pincode: pincode, name: device.name})
270+ root.dialogPopupId.canceled.connect(function() {
271+ root.dialogPopupId = null
272+ if (root.currentDevice) {
273+ root.currentDevice.cancelPairing()
274+ root.currentDevice = null
275+ }
276+ })
277+ }
278+ else
279+ {
280+ console.warn("Unhandled PIN code request for device " + device.name);
281+ }
282+ }
283 onDisplayPasskeyNeeded: {
284 if (!root.dialogPopupId)
285 {
286- var request_tag = tag
287+ root.currentDevice = device
288 root.dialogPopupId = PopupUtils.open(displayPasskeyDialog, root, {passkey: passkey, name: device.name,
289 entered: entered})
290- root.dialogPopupId.canceled.connect(function() {root.dialogPopupId = null;
291- target.displayPasskeyCallback(request_tag)})
292+ root.dialogPopupId.canceled.connect(function() {
293+ root.dialogPopupId = null
294+ if (root.currentDevice) {
295+ root.currentDevice.cancelPairing()
296+ root.currentDevice = null
297+ }
298+ })
299 }
300 else
301 {
302 root.dialogPopupId.entered = entered
303 }
304 }
305- onPairingDone: {
306- if (root.dialogPopupId)
307- PopupUtils.close(root.dialogPopupId)
308+ onReleaseNeeded: {
309+ finishDevicePairing()
310+ }
311+ onAuthorizationRequested: {
312+ if (!root.dialogPopupId)
313+ {
314+ var request_tag = tag
315+ root.dialogPopupId = PopupUtils.open(authorizationRequestDialog, root, {name: device.name})
316+ root.dialogPopupId.accepted.connect(function() {
317+ root.dialogPopupId = null
318+ target.authorizationRequestCallback(request_tag, true)
319+ })
320+ root.dialogPopupId.declined.connect(function() {
321+ root.dialogPopupId = null
322+ target.authorizationRequestCallback(request_tag, false)
323+ })
324+ }
325 }
326 }
327
328@@ -151,7 +219,7 @@
329 text: i18n.tr("Bluetooth")
330 control: Switch {
331 id: btSwitch
332- property bool serverChecked: bluetoothActionGroup.enabled.state
333+ property bool serverChecked: bluetoothActionGroup.enabled.state != undefined ? bluetoothActionGroup.enabled.state : false
334 USC.ServerPropertySynchroniser {
335 userTarget: btSwitch
336 userProperty: "checked"
337@@ -210,7 +278,6 @@
338 }
339 }
340
341- // Connnected Headset(s)
342 ListItem.Standard {
343 id: connectedHeader
344 text: i18n.tr("Connected devices:")
345@@ -225,7 +292,7 @@
346 left: parent.left
347 right: parent.right
348 }
349- visible: bluetoothActionGroup.enabled && (connectedRepeater.count > 0)
350+ visible: (bluetoothActionGroup.enabled.state != undefined && bluetoothActionGroup.enabled.state) && (connectedRepeater.count > 0)
351 objectName: "connectedList"
352
353 Repeater {
354@@ -248,12 +315,10 @@
355 }
356 }
357
358- // Disconnnected Headset(s)
359-
360 SettingsItemTitle {
361 id: disconnectedHeader
362 text: connectedList.visible ? i18n.tr("Connect another device:") : i18n.tr("Connect a device:")
363- enabled: bluetoothActionGroup.enabled
364+ enabled: bluetoothActionGroup.enabled.state != undefined ? bluetoothActionGroup.enabled.state : false
365 control: ActivityIndicator {
366 visible: backend.powered && backend.discovering
367 running: visible
368@@ -266,7 +331,7 @@
369 left: parent.left
370 right: parent.right
371 }
372- visible: bluetoothActionGroup.enabled && (disconnectedRepeater.count > 0)
373+ visible: (bluetoothActionGroup.enabled.state != undefined && bluetoothActionGroup.enabled.state) && (disconnectedRepeater.count > 0)
374 objectName: "disconnectedList"
375
376 Repeater {
377@@ -287,11 +352,10 @@
378 ListItem.Standard {
379 id: disconnectedNone
380 text: i18n.tr("None detected")
381- visible: !disconnectedList.visible
382+ visible: !disconnectedList.visible && disconnectedHeader.visible
383 enabled: false
384 }
385
386- // Devices that connect automatically
387 SettingsItemTitle {
388 id: autoconnectHeader
389 text: i18n.tr("Connect automatically when detected:")
390
391=== modified file 'plugins/bluetooth/agent.cpp'
392--- plugins/bluetooth/agent.cpp 2015-08-28 09:32:38 +0000
393+++ plugins/bluetooth/agent.cpp 2015-11-20 08:48:08 +0000
394@@ -53,7 +53,7 @@
395 */
396 void Agent::Release()
397 {
398- Q_EMIT(pairingDone());
399+ Q_EMIT(releaseNeeded());
400 }
401
402 /***
403@@ -112,9 +112,24 @@
404 }
405 }
406
407-/***
408-****
409-***/
410+QString Agent::RequestPinCode(const QDBusObjectPath &objectPath)
411+{
412+ auto device = m_devices.getDeviceFromPath(objectPath.path());
413+ if (device) {
414+ const uint tag = m_tag++;
415+
416+ setDelayedReply(true);
417+ assert(!m_delayedReplies.contains(tag));
418+ m_delayedReplies[tag] = message();
419+
420+ Q_EMIT(pinCodeNeeded(tag, device.data()));
421+
422+ } else { // passkey requested for an unknown device..?!
423+ reject(message(), __func__);
424+ }
425+
426+ return 0;
427+}
428
429 /**
430 * This method gets called when the service daemon
431@@ -168,35 +183,6 @@
432 ****
433 ***/
434
435-/*
436- * This method gets called when the service daemon
437- * needs to get the passkey for an authentication.
438- *
439- * The return value should be a string of 1-16 characters
440- * length. The string can be alphanumeric.
441- *
442- * Possible errors: org.bluez.Error.Rejected
443- * org.bluez.Error.Canceled
444- */
445-QString Agent::RequestPinCode(const QDBusObjectPath &objectPath)
446-{
447- auto device = m_devices.getDeviceFromPath(objectPath.path());
448- if (device) {
449- const uint tag = m_tag++;
450-
451- setDelayedReply(true);
452- assert(!m_delayedReplies.contains(tag));
453- m_delayedReplies[tag] = message();
454-
455- Q_EMIT(pinCodeNeeded(tag, device.data()));
456-
457- } else { // passkey requested for an unknown device..?!
458- reject(message(), __func__);
459- }
460-
461- return "";
462-}
463-
464 /**
465 * Invoked by the user-facing code after it prompts the user for a PIN code
466 * from an Agent::pinCodeNeeded() signal.
467@@ -218,33 +204,23 @@
468 }
469 }
470
471-/** This method gets called when the service daemon
472- * needs to display a passkey for an authentication.
473- * The entered parameter indicates the number of already
474- * typed keys on the remote side.
475- * An empty reply should be returned. When the passkey
476- * needs no longer to be displayed, the Cancel method
477- * of the agent will be called.
478- * During the pairing process this method might be
479- * called multiple times to update the entered value.
480- * Note that the passkey will always be a 6-digit number,
481- * so the display should be zero-padded at the start if
482- * the value contains less than 6 digits.
483- */
484+void Agent::DisplayPinCode(const QDBusObjectPath &objectPath, QString pincode)
485+{
486+ auto device = m_devices.getDeviceFromPath(objectPath.path());
487+ if (device) {
488+ Q_EMIT(displayPinCodeNeeded(device.data(), pincode));
489+ } else {
490+ reject(message(), __func__);
491+ }
492+}
493
494 void Agent::DisplayPasskey(const QDBusObjectPath &objectPath, uint passkey, ushort entered)
495 {
496 auto device = m_devices.getDeviceFromPath(objectPath.path());
497 if (device) {
498- const uint tag = m_tag++;
499-
500- setDelayedReply(true);
501- assert(!m_delayedReplies.contains(tag));
502- m_delayedReplies[tag] = message();
503-
504 QString passkeyStr = QString("%1").arg(passkey, 6, 10, QChar('0'));
505- Q_EMIT(displayPasskeyNeeded(tag, device.data(), passkeyStr, entered));
506- } else { // confirmation requested for an unknown device..?!
507+ Q_EMIT(displayPasskeyNeeded(device.data(), passkeyStr, entered));
508+ } else {
509 reject(message(), __func__);
510 }
511 }
512@@ -256,6 +232,53 @@
513 void Agent::Cancel()
514 {
515 qWarning() << "Cancel callback called";
516+
517+ Q_EMIT(cancelNeeded());
518+}
519+
520+void Agent::RequestAuthorization(const QDBusObjectPath &path)
521+{
522+ qWarning() << "Authorization requested for device"
523+ << path.path();
524+
525+ auto device = m_devices.getDeviceFromPath(path.path());
526+ if (device) {
527+ const uint tag = m_tag++;
528+
529+ setDelayedReply(true);
530+ assert(!m_delayedReplies.contains(tag));
531+ m_delayedReplies[tag] = message();
532+
533+ Q_EMIT(authorizationRequested(tag, device.data()));
534+ }
535+ else {
536+ reject(message(), __func__);
537+ }
538+}
539+
540+void Agent::authorizationRequestCallback(uint tag, bool allow)
541+{
542+ if (m_delayedReplies.contains(tag)) {
543+ QDBusMessage message = m_delayedReplies[tag];
544+
545+ if (allow)
546+ m_connection.send(message.createReply());
547+ else
548+ reject(message, __func__);
549+
550+ m_delayedReplies.remove(tag);
551+ }
552+}
553+
554+void Agent::displayPinCodeCallback(uint tag)
555+{
556+ if (m_delayedReplies.contains(tag)) {
557+ QDBusMessage message = m_delayedReplies[tag];
558+
559+ cancel(message, __func__);
560+
561+ m_delayedReplies.remove(tag);
562+ }
563 }
564
565 /**
566
567=== modified file 'plugins/bluetooth/agent.h'
568--- plugins/bluetooth/agent.h 2015-08-28 09:32:38 +0000
569+++ plugins/bluetooth/agent.h 2015-11-20 08:48:08 +0000
570@@ -41,22 +41,29 @@
571 Q_INVOKABLE void confirmPasskey(uint tag, bool confirmed);
572 Q_INVOKABLE void providePasskey(uint tag, bool provided, uint passkey);
573 Q_INVOKABLE void providePinCode(uint tag, bool provided, QString pinCode);
574+ Q_INVOKABLE void displayPinCodeCallback(uint tag);
575 Q_INVOKABLE void displayPasskeyCallback(uint tag);
576+ Q_INVOKABLE void authorizationRequestCallback(uint tag, bool allow);
577
578 public Q_SLOTS: // received from the system's bluez service
579 void Cancel();
580+ void DisplayPinCode(const QDBusObjectPath &path, QString pincode);
581 void DisplayPasskey(const QDBusObjectPath &path, uint passkey, ushort entered);
582 void Release();
583 void RequestConfirmation(const QDBusObjectPath &path, uint passkey);
584 uint RequestPasskey(const QDBusObjectPath &path);
585 QString RequestPinCode(const QDBusObjectPath &path);
586+ void RequestAuthorization(const QDBusObjectPath &path);
587
588 Q_SIGNALS:
589 void pinCodeNeeded(int tag, Device* device);
590 void passkeyNeeded(int tag, Device* device);
591 void passkeyConfirmationNeeded(int tag, Device* device, QString passkey);
592- void displayPasskeyNeeded(int tag, Device* device, QString passkey, ushort entered);
593- void pairingDone();
594+ void displayPinCodeNeeded(Device* device, QString pincode);
595+ void displayPasskeyNeeded(Device* device, QString passkey, ushort entered);
596+ void releaseNeeded();
597+ void cancelNeeded();
598+ void authorizationRequested(int tag, Device* device);
599
600 private:
601 Q_DISABLE_COPY(Agent)
602
603=== removed file 'plugins/bluetooth/agent.xml'
604--- plugins/bluetooth/agent.xml 2015-02-04 10:48:47 +0000
605+++ plugins/bluetooth/agent.xml 1970-01-01 00:00:00 +0000
606@@ -1,38 +0,0 @@
607-<?xml version="1.0" encoding="UTF-8" ?>
608-
609-<node name="/">
610- <interface name="org.bluez.Agent">
611- <method name="RequestPinCode">
612- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
613- <arg type="o" name="device"/>
614- <arg type="s" name="pincode" direction="out"/>
615- </method>
616-
617- <method name="RequestPasskey">
618- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
619- <arg type="o" name="device"/>
620- <arg type="u" name="passkey" direction="out"/>
621- </method>
622-
623- <method name="DisplayPasskey">
624- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
625- <arg type="o" name="device"/>
626- <arg type="u" name="passkey"/>
627- <arg type="q" name="entered"/>
628- </method>
629-
630- <method name="RequestConfirmation">
631- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
632- <arg type="o" name="device"/>
633- <arg type="u" name="passkey"/>
634- </method>
635-
636- <method name="Cancel">
637- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
638- </method>
639-
640- <method name="Release">
641- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
642- </method>
643- </interface>
644-</node>
645
646=== removed file 'plugins/bluetooth/agentadaptor.cpp'
647--- plugins/bluetooth/agentadaptor.cpp 2015-02-04 10:48:47 +0000
648+++ plugins/bluetooth/agentadaptor.cpp 1970-01-01 00:00:00 +0000
649@@ -1,75 +0,0 @@
650-/*
651- * This file was generated by qdbusxml2cpp version 0.8
652- * Command line was: qdbusxml2cpp agent.xml -a agentadaptor
653- *
654- * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
655- *
656- * This is an auto-generated file.
657- * Do not edit! All changes made to it will be lost.
658- */
659-
660-#include "agentadaptor.h"
661-#include <QtCore/QMetaObject>
662-#include <QtCore/QByteArray>
663-#include <QtCore/QList>
664-#include <QtCore/QMap>
665-#include <QtCore/QString>
666-#include <QtCore/QStringList>
667-#include <QtCore/QVariant>
668-
669-/*
670- * Implementation of adaptor class AgentAdaptor
671- */
672-
673-AgentAdaptor::AgentAdaptor(QObject *parent)
674- : QDBusAbstractAdaptor(parent)
675-{
676- // constructor
677- setAutoRelaySignals(true);
678-}
679-
680-AgentAdaptor::~AgentAdaptor()
681-{
682- // destructor
683-}
684-
685-void AgentAdaptor::Cancel()
686-{
687- // handle method call org.bluez.Agent.Cancel
688- QMetaObject::invokeMethod(parent(), "Cancel");
689-}
690-
691-void AgentAdaptor::DisplayPasskey(const QDBusObjectPath &device, uint passkey, ushort entered)
692-{
693- // handle method call org.bluez.Agent.DisplayPasskey
694- QMetaObject::invokeMethod(parent(), "DisplayPasskey", Q_ARG(QDBusObjectPath, device), Q_ARG(uint, passkey), Q_ARG(ushort, entered));
695-}
696-
697-void AgentAdaptor::Release()
698-{
699- // handle method call org.bluez.Agent.Release
700- QMetaObject::invokeMethod(parent(), "Release");
701-}
702-
703-void AgentAdaptor::RequestConfirmation(const QDBusObjectPath &device, uint passkey)
704-{
705- // handle method call org.bluez.Agent.RequestConfirmation
706- QMetaObject::invokeMethod(parent(), "RequestConfirmation", Q_ARG(QDBusObjectPath, device), Q_ARG(uint, passkey));
707-}
708-
709-uint AgentAdaptor::RequestPasskey(const QDBusObjectPath &device)
710-{
711- // handle method call org.bluez.Agent.RequestPasskey
712- uint passkey;
713- QMetaObject::invokeMethod(parent(), "RequestPasskey", Q_RETURN_ARG(uint, passkey), Q_ARG(QDBusObjectPath, device));
714- return passkey;
715-}
716-
717-QString AgentAdaptor::RequestPinCode(const QDBusObjectPath &device)
718-{
719- // handle method call org.bluez.Agent.RequestPinCode
720- QString pincode;
721- QMetaObject::invokeMethod(parent(), "RequestPinCode", Q_RETURN_ARG(QString, pincode), Q_ARG(QDBusObjectPath, device));
722- return pincode;
723-}
724-
725
726=== removed file 'plugins/bluetooth/agentadaptor.h'
727--- plugins/bluetooth/agentadaptor.h 2015-02-04 10:48:47 +0000
728+++ plugins/bluetooth/agentadaptor.h 1970-01-01 00:00:00 +0000
729@@ -1,79 +0,0 @@
730-/*
731- * This file was generated by qdbusxml2cpp version 0.8
732- * Command line was: qdbusxml2cpp agent.xml -a agentadaptor
733- *
734- * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
735- *
736- * This is an auto-generated file.
737- * This file may have been hand-edited. Look for HAND-EDIT comments
738- * before re-generating it.
739- */
740-
741-#ifndef AGENTADAPTOR_H_1423046874
742-#define AGENTADAPTOR_H_1423046874
743-
744-#include <QtCore/QObject>
745-#include <QtDBus/QtDBus>
746-QT_BEGIN_NAMESPACE
747-class QByteArray;
748-template<class T> class QList;
749-template<class Key, class Value> class QMap;
750-class QString;
751-class QStringList;
752-class QVariant;
753-QT_END_NAMESPACE
754-
755-/*
756- * Adaptor class for interface org.bluez.Agent
757- */
758-class AgentAdaptor: public QDBusAbstractAdaptor
759-{
760- Q_OBJECT
761- Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent")
762- Q_CLASSINFO("D-Bus Introspection", ""
763-" <interface name=\"org.bluez.Agent\">\n"
764-" <method name=\"RequestPinCode\">\n"
765-" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
766-" <arg type=\"o\" name=\"device\"/>\n"
767-" <arg direction=\"out\" type=\"s\" name=\"pincode\"/>\n"
768-" </method>\n"
769-" <method name=\"RequestPasskey\">\n"
770-" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
771-" <arg type=\"o\" name=\"device\"/>\n"
772-" <arg direction=\"out\" type=\"u\" name=\"passkey\"/>\n"
773-" </method>\n"
774-" <method name=\"DisplayPasskey\">\n"
775-" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
776-" <arg type=\"o\" name=\"device\"/>\n"
777-" <arg type=\"u\" name=\"passkey\"/>\n"
778-" <arg type=\"q\" name=\"entered\"/>\n"
779-" </method>\n"
780-" <method name=\"RequestConfirmation\">\n"
781-" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
782-" <arg type=\"o\" name=\"device\"/>\n"
783-" <arg type=\"u\" name=\"passkey\"/>\n"
784-" </method>\n"
785-" <method name=\"Cancel\">\n"
786-" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
787-" </method>\n"
788-" <method name=\"Release\">\n"
789-" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
790-" </method>\n"
791-" </interface>\n"
792- "")
793-public:
794- AgentAdaptor(QObject *parent);
795- virtual ~AgentAdaptor();
796-
797-public: // PROPERTIES
798-public Q_SLOTS: // METHODS
799- void Cancel();
800- void DisplayPasskey(const QDBusObjectPath &device, uint passkey, ushort entered);
801- void Release();
802- void RequestConfirmation(const QDBusObjectPath &device, uint passkey);
803- uint RequestPasskey(const QDBusObjectPath &device);
804- QString RequestPinCode(const QDBusObjectPath &device);
805-Q_SIGNALS: // SIGNALS
806-};
807-
808-#endif
809
810=== modified file 'plugins/bluetooth/bluetooth.cpp'
811--- plugins/bluetooth/bluetooth.cpp 2015-08-28 09:32:38 +0000
812+++ plugins/bluetooth/bluetooth.cpp 2015-11-20 08:48:08 +0000
813@@ -23,7 +23,6 @@
814 #include <QQmlEngine>
815
816 #include "agent.h"
817-#include "agentadaptor.h"
818 #include "dbus-shared.h"
819
820 Bluetooth::Bluetooth(QObject *parent):
821@@ -38,7 +37,7 @@
822 m_agent(m_dbus, m_devices)
823 {
824 // export our Agent to handle pairing requests
825- new AgentAdaptor(&m_agent);
826+ new BluezAgent1Adaptor(&m_agent);
827 if(!m_dbus.registerObject(DBUS_ADAPTER_AGENT_PATH, &m_agent))
828 qCritical() << "Couldn't register agent at" << DBUS_ADAPTER_AGENT_PATH;
829
830@@ -63,6 +62,9 @@
831
832 QObject::connect(&m_devices, SIGNAL(discoverableChanged(bool)),
833 this, SIGNAL(discoverableChanged(bool)));
834+
835+ QObject::connect(&m_devices, SIGNAL(devicePairingDone(Device*,bool)),
836+ this, SIGNAL(devicePairingDone(Device*,bool)));
837 }
838
839 void Bluetooth::setSelectedDevice(const QString &address)
840@@ -110,6 +112,7 @@
841 case Device::Type::OtherAudio:
842 case Device::Type::Keyboard:
843 case Device::Type::Mouse:
844+ case Device::Type::Watch:
845 return true;
846
847 default:
848@@ -167,73 +170,38 @@
849
850 void Bluetooth::disconnectDevice()
851 {
852- if (m_selectedDevice) {
853- auto type = m_selectedDevice->getType();
854- switch ((Device::Type)type) {
855- case Device::Type::Headset:
856- case Device::Type::Headphones:
857- case Device::Type::OtherAudio:
858- case Device::Type::Speakers:
859- case Device::Type::Carkit:
860- m_selectedDevice->disconnect(Device::ConnectionMode::Audio);
861- break;
862- case Device::Type::Keyboard:
863- case Device::Type::Mouse:
864- m_selectedDevice->disconnect(Device::ConnectionMode::Input);
865- break;
866- default:
867- qWarning() << "Nothing to disconnect: Unsupported device type.";
868- break;
869- }
870- } else {
871- qWarning() << "No selected device to disconnect";
872- }
873+ if (!m_selectedDevice)
874+ return;
875+
876+ m_selectedDevice->disconnect();
877 }
878
879 void Bluetooth::connectDevice(const QString &address)
880 {
881- Device::ConnectionMode connMode;
882 auto device = m_devices.getDeviceFromAddress(address);
883- Device::Type type;
884
885 if (!device) {
886 qWarning() << "No device to connect.";
887 return;
888 }
889
890- type = device->getType();
891- switch (type) {
892- case Device::Type::Headset:
893- case Device::Type::Headphones:
894- case Device::Type::OtherAudio:
895- case Device::Type::Speakers:
896- case Device::Type::Carkit:
897- connMode = Device::ConnectionMode::Audio;
898- break;
899- case Device::Type::Keyboard:
900- case Device::Type::Mouse:
901- connMode = Device::ConnectionMode::Input;
902- break;
903- default:
904- qWarning() << "Nothing to connect: Unsupported device type.";
905- return;
906+ if (!device->isPaired()) {
907+ device->setConnectAfterPairing(true);
908+ device->pair();
909 }
910-
911- if (device->isTrusted()) {
912- device->connect(connMode);
913- } else {
914- m_devices.addConnectAfterPairing(address, connMode);
915- m_devices.createDevice(address, &m_agent);
916+ else {
917+ device->connect();
918 }
919 }
920
921 void Bluetooth::removeDevice()
922 {
923- if (m_selectedDevice) {
924- QString path = m_selectedDevice->getPath();
925- m_devices.removeDevice(path);
926- } else {
927+ if (!m_selectedDevice) {
928 qWarning() << "No selected device to remove.";
929+ return;
930 }
931+
932+ QString path = m_selectedDevice->getPath();
933+ m_devices.removeDevice(path);
934 }
935
936
937=== modified file 'plugins/bluetooth/bluetooth.h'
938--- plugins/bluetooth/bluetooth.h 2015-08-28 09:32:38 +0000
939+++ plugins/bluetooth/bluetooth.h 2015-11-20 08:48:08 +0000
940@@ -24,9 +24,10 @@
941 #include <QObject>
942
943 #include "agent.h"
944-#include "agentadaptor.h"
945 #include "devicemodel.h"
946
947+#include "bluez_agent1adaptor.h"
948+
949 class Bluetooth : public QObject
950 {
951 Q_OBJECT
952@@ -68,6 +69,7 @@
953 void poweredChanged(bool powered);
954 void discoveringChanged(bool isActive);
955 void discoverableChanged(bool isActive);
956+ void devicePairingDone(Device *device, bool success);
957
958 public:
959 explicit Bluetooth(QObject *parent = nullptr);
960
961=== added file 'plugins/bluetooth/bluez_adapter1.cpp'
962--- plugins/bluetooth/bluez_adapter1.cpp 1970-01-01 00:00:00 +0000
963+++ plugins/bluetooth/bluez_adapter1.cpp 2015-11-20 08:48:08 +0000
964@@ -0,0 +1,26 @@
965+/*
966+ * This file was generated by qdbusxml2cpp version 0.8
967+ * Command line was: qdbusxml2cpp -c BluezAdapter1 -p bluez_adapter1 -v org.bluez.Adapter1.xml
968+ *
969+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
970+ *
971+ * This is an auto-generated file.
972+ * This file may have been hand-edited. Look for HAND-EDIT comments
973+ * before re-generating it.
974+ */
975+
976+#include "bluez_adapter1.h"
977+
978+/*
979+ * Implementation of interface class BluezAdapter1
980+ */
981+
982+BluezAdapter1::BluezAdapter1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
983+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
984+{
985+}
986+
987+BluezAdapter1::~BluezAdapter1()
988+{
989+}
990+
991
992=== added file 'plugins/bluetooth/bluez_adapter1.h'
993--- plugins/bluetooth/bluez_adapter1.h 1970-01-01 00:00:00 +0000
994+++ plugins/bluetooth/bluez_adapter1.h 2015-11-20 08:48:08 +0000
995@@ -0,0 +1,66 @@
996+/*
997+ * This file was generated by qdbusxml2cpp version 0.8
998+ * Command line was: qdbusxml2cpp -c BluezAdapter1 -p bluez_adapter1 -v org.bluez.Adapter1.xml
999+ *
1000+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
1001+ *
1002+ * This is an auto-generated file.
1003+ * Do not edit! All changes made to it will be lost.
1004+ */
1005+
1006+#ifndef BLUEZ_ADAPTER1_H_1442480417
1007+#define BLUEZ_ADAPTER1_H_1442480417
1008+
1009+#include <QtCore/QObject>
1010+#include <QtCore/QByteArray>
1011+#include <QtCore/QList>
1012+#include <QtCore/QMap>
1013+#include <QtCore/QString>
1014+#include <QtCore/QStringList>
1015+#include <QtCore/QVariant>
1016+#include <QtDBus/QtDBus>
1017+
1018+/*
1019+ * Proxy class for interface org.bluez.Adapter1
1020+ */
1021+class BluezAdapter1: public QDBusAbstractInterface
1022+{
1023+ Q_OBJECT
1024+public:
1025+ static inline const char *staticInterfaceName()
1026+ { return "org.bluez.Adapter1"; }
1027+
1028+public:
1029+ BluezAdapter1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
1030+
1031+ ~BluezAdapter1();
1032+
1033+public Q_SLOTS: // METHODS
1034+ inline QDBusPendingReply<> RemoveDevice(const QDBusObjectPath &device)
1035+ {
1036+ QList<QVariant> argumentList;
1037+ argumentList << QVariant::fromValue(device);
1038+ return asyncCallWithArgumentList(QStringLiteral("RemoveDevice"), argumentList);
1039+ }
1040+
1041+ inline QDBusPendingReply<> StartDiscovery()
1042+ {
1043+ QList<QVariant> argumentList;
1044+ return asyncCallWithArgumentList(QStringLiteral("StartDiscovery"), argumentList);
1045+ }
1046+
1047+ inline QDBusPendingReply<> StopDiscovery()
1048+ {
1049+ QList<QVariant> argumentList;
1050+ return asyncCallWithArgumentList(QStringLiteral("StopDiscovery"), argumentList);
1051+ }
1052+
1053+Q_SIGNALS: // SIGNALS
1054+};
1055+
1056+namespace org {
1057+ namespace bluez {
1058+ typedef ::BluezAdapter1 Adapter1;
1059+ }
1060+}
1061+#endif
1062
1063=== added file 'plugins/bluetooth/bluez_agent1adaptor.cpp'
1064--- plugins/bluetooth/bluez_agent1adaptor.cpp 1970-01-01 00:00:00 +0000
1065+++ plugins/bluetooth/bluez_agent1adaptor.cpp 2015-11-20 08:48:08 +0000
1066@@ -0,0 +1,93 @@
1067+/*
1068+ * This file was generated by qdbusxml2cpp version 0.8
1069+ * Command line was: qdbusxml2cpp -a bluez_agent1adaptor -c BluezAgent1Adaptor org.bluez.Agent1.xml
1070+ *
1071+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
1072+ *
1073+ * This is an auto-generated file.
1074+ * Do not edit! All changes made to it will be lost.
1075+ */
1076+
1077+#include "bluez_agent1adaptor.h"
1078+#include <QtCore/QMetaObject>
1079+#include <QtCore/QByteArray>
1080+#include <QtCore/QList>
1081+#include <QtCore/QMap>
1082+#include <QtCore/QString>
1083+#include <QtCore/QStringList>
1084+#include <QtCore/QVariant>
1085+
1086+/*
1087+ * Implementation of adaptor class BluezAgent1Adaptor
1088+ */
1089+
1090+BluezAgent1Adaptor::BluezAgent1Adaptor(QObject *parent)
1091+ : QDBusAbstractAdaptor(parent)
1092+{
1093+ // constructor
1094+ setAutoRelaySignals(true);
1095+}
1096+
1097+BluezAgent1Adaptor::~BluezAgent1Adaptor()
1098+{
1099+ // destructor
1100+}
1101+
1102+void BluezAgent1Adaptor::AuthorizeService(const QDBusObjectPath &device, const QString &uuid)
1103+{
1104+ // handle method call org.bluez.Agent1.AuthorizeService
1105+ QMetaObject::invokeMethod(parent(), "AuthorizeService", Q_ARG(QDBusObjectPath, device), Q_ARG(QString, uuid));
1106+}
1107+
1108+void BluezAgent1Adaptor::Cancel()
1109+{
1110+ // handle method call org.bluez.Agent1.Cancel
1111+ QMetaObject::invokeMethod(parent(), "Cancel");
1112+}
1113+
1114+void BluezAgent1Adaptor::DisplayPasskey(const QDBusObjectPath &device, uint passkey, ushort entered)
1115+{
1116+ // handle method call org.bluez.Agent1.DisplayPasskey
1117+ QMetaObject::invokeMethod(parent(), "DisplayPasskey", Q_ARG(QDBusObjectPath, device), Q_ARG(uint, passkey), Q_ARG(ushort, entered));
1118+}
1119+
1120+void BluezAgent1Adaptor::DisplayPinCode(const QDBusObjectPath &device, const QString &pincode)
1121+{
1122+ // handle method call org.bluez.Agent1.DisplayPinCode
1123+ QMetaObject::invokeMethod(parent(), "DisplayPinCode", Q_ARG(QDBusObjectPath, device), Q_ARG(QString, pincode));
1124+}
1125+
1126+void BluezAgent1Adaptor::Release()
1127+{
1128+ // handle method call org.bluez.Agent1.Release
1129+ QMetaObject::invokeMethod(parent(), "Release");
1130+}
1131+
1132+void BluezAgent1Adaptor::RequestAuthorization(const QDBusObjectPath &device)
1133+{
1134+ // handle method call org.bluez.Agent1.RequestAuthorization
1135+ QMetaObject::invokeMethod(parent(), "RequestAuthorization", Q_ARG(QDBusObjectPath, device));
1136+}
1137+
1138+void BluezAgent1Adaptor::RequestConfirmation(const QDBusObjectPath &device, uint passkey)
1139+{
1140+ // handle method call org.bluez.Agent1.RequestConfirmation
1141+ QMetaObject::invokeMethod(parent(), "RequestConfirmation", Q_ARG(QDBusObjectPath, device), Q_ARG(uint, passkey));
1142+}
1143+
1144+uint BluezAgent1Adaptor::RequestPasskey(const QDBusObjectPath &device)
1145+{
1146+ // handle method call org.bluez.Agent1.RequestPasskey
1147+ uint passkey;
1148+ QMetaObject::invokeMethod(parent(), "RequestPasskey", Q_RETURN_ARG(uint, passkey), Q_ARG(QDBusObjectPath, device));
1149+ return passkey;
1150+}
1151+
1152+QString BluezAgent1Adaptor::RequestPinCode(const QDBusObjectPath &device)
1153+{
1154+ // handle method call org.bluez.Agent1.RequestPinCode
1155+ QString pincode;
1156+ QMetaObject::invokeMethod(parent(), "RequestPinCode", Q_RETURN_ARG(QString, pincode), Q_ARG(QDBusObjectPath, device));
1157+ return pincode;
1158+}
1159+
1160
1161=== added file 'plugins/bluetooth/bluez_agent1adaptor.h'
1162--- plugins/bluetooth/bluez_agent1adaptor.h 1970-01-01 00:00:00 +0000
1163+++ plugins/bluetooth/bluez_agent1adaptor.h 2015-11-20 08:48:08 +0000
1164@@ -0,0 +1,96 @@
1165+/*
1166+ * This file was generated by qdbusxml2cpp version 0.8
1167+ * Command line was: qdbusxml2cpp -a bluez_agent1adaptor -c BluezAgent1Adaptor org.bluez.Agent1.xml
1168+ *
1169+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
1170+ *
1171+ * This is an auto-generated file.
1172+ * This file may have been hand-edited. Look for HAND-EDIT comments
1173+ * before re-generating it.
1174+ */
1175+
1176+#ifndef BLUEZ_AGENT1ADAPTOR_H_1442560744
1177+#define BLUEZ_AGENT1ADAPTOR_H_1442560744
1178+
1179+#include <QtCore/QObject>
1180+#include <QtDBus/QtDBus>
1181+QT_BEGIN_NAMESPACE
1182+class QByteArray;
1183+template<class T> class QList;
1184+template<class Key, class Value> class QMap;
1185+class QString;
1186+class QStringList;
1187+class QVariant;
1188+QT_END_NAMESPACE
1189+
1190+/*
1191+ * Adaptor class for interface org.bluez.Agent1
1192+ */
1193+class BluezAgent1Adaptor: public QDBusAbstractAdaptor
1194+{
1195+ Q_OBJECT
1196+ Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent1")
1197+ Q_CLASSINFO("D-Bus Introspection", ""
1198+" <interface name=\"org.bluez.Agent1\">\n"
1199+" <method name=\"RequestPinCode\">\n"
1200+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1201+" <arg type=\"o\" name=\"device\"/>\n"
1202+" <arg direction=\"out\" type=\"s\" name=\"pincode\"/>\n"
1203+" </method>\n"
1204+" <method name=\"DisplayPinCode\">\n"
1205+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1206+" <arg type=\"o\" name=\"device\"/>\n"
1207+" <arg type=\"s\" name=\"pincode\"/>\n"
1208+" </method>\n"
1209+" <method name=\"RequestPasskey\">\n"
1210+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1211+" <arg type=\"o\" name=\"device\"/>\n"
1212+" <arg direction=\"out\" type=\"u\" name=\"passkey\"/>\n"
1213+" </method>\n"
1214+" <method name=\"DisplayPasskey\">\n"
1215+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1216+" <arg type=\"o\" name=\"device\"/>\n"
1217+" <arg type=\"u\" name=\"passkey\"/>\n"
1218+" <arg type=\"q\" name=\"entered\"/>\n"
1219+" </method>\n"
1220+" <method name=\"RequestConfirmation\">\n"
1221+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1222+" <arg type=\"o\" name=\"device\"/>\n"
1223+" <arg type=\"u\" name=\"passkey\"/>\n"
1224+" </method>\n"
1225+" <method name=\"RequestAuthorization\">\n"
1226+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1227+" <arg type=\"o\" name=\"device\"/>\n"
1228+" </method>\n"
1229+" <method name=\"AuthorizeService\">\n"
1230+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1231+" <arg type=\"o\" name=\"device\"/>\n"
1232+" <arg type=\"s\" name=\"uuid\"/>\n"
1233+" </method>\n"
1234+" <method name=\"Cancel\">\n"
1235+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1236+" </method>\n"
1237+" <method name=\"Release\">\n"
1238+" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
1239+" </method>\n"
1240+" </interface>\n"
1241+ "")
1242+public:
1243+ BluezAgent1Adaptor(QObject *parent);
1244+ virtual ~BluezAgent1Adaptor();
1245+
1246+public: // PROPERTIES
1247+public Q_SLOTS: // METHODS
1248+ void AuthorizeService(const QDBusObjectPath &device, const QString &uuid);
1249+ void Cancel();
1250+ void DisplayPasskey(const QDBusObjectPath &device, uint passkey, ushort entered);
1251+ void DisplayPinCode(const QDBusObjectPath &device, const QString &pincode);
1252+ void Release();
1253+ void RequestAuthorization(const QDBusObjectPath &device);
1254+ void RequestConfirmation(const QDBusObjectPath &device, uint passkey);
1255+ uint RequestPasskey(const QDBusObjectPath &device);
1256+ QString RequestPinCode(const QDBusObjectPath &device);
1257+Q_SIGNALS: // SIGNALS
1258+};
1259+
1260+#endif
1261
1262=== added file 'plugins/bluetooth/bluez_agentmanager1.cpp'
1263--- plugins/bluetooth/bluez_agentmanager1.cpp 1970-01-01 00:00:00 +0000
1264+++ plugins/bluetooth/bluez_agentmanager1.cpp 2015-11-20 08:48:08 +0000
1265@@ -0,0 +1,26 @@
1266+/*
1267+ * This file was generated by qdbusxml2cpp version 0.8
1268+ * Command line was: qdbusxml2cpp -c BluezAgentManager1 -p bluez_agentmanager1 org.bluez.AgentManager1.xml
1269+ *
1270+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
1271+ *
1272+ * This is an auto-generated file.
1273+ * This file may have been hand-edited. Look for HAND-EDIT comments
1274+ * before re-generating it.
1275+ */
1276+
1277+#include "bluez_agentmanager1.h"
1278+
1279+/*
1280+ * Implementation of interface class BluezAgentManager1
1281+ */
1282+
1283+BluezAgentManager1::BluezAgentManager1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
1284+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
1285+{
1286+}
1287+
1288+BluezAgentManager1::~BluezAgentManager1()
1289+{
1290+}
1291+
1292
1293=== added file 'plugins/bluetooth/bluez_agentmanager1.h'
1294--- plugins/bluetooth/bluez_agentmanager1.h 1970-01-01 00:00:00 +0000
1295+++ plugins/bluetooth/bluez_agentmanager1.h 2015-11-20 08:48:08 +0000
1296@@ -0,0 +1,68 @@
1297+/*
1298+ * This file was generated by qdbusxml2cpp version 0.8
1299+ * Command line was: qdbusxml2cpp -c BluezAgentManager1 -p bluez_agentmanager1 org.bluez.AgentManager1.xml
1300+ *
1301+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
1302+ *
1303+ * This is an auto-generated file.
1304+ * Do not edit! All changes made to it will be lost.
1305+ */
1306+
1307+#ifndef BLUEZ_AGENTMANAGER1_H_1442489332
1308+#define BLUEZ_AGENTMANAGER1_H_1442489332
1309+
1310+#include <QtCore/QObject>
1311+#include <QtCore/QByteArray>
1312+#include <QtCore/QList>
1313+#include <QtCore/QMap>
1314+#include <QtCore/QString>
1315+#include <QtCore/QStringList>
1316+#include <QtCore/QVariant>
1317+#include <QtDBus/QtDBus>
1318+
1319+/*
1320+ * Proxy class for interface org.bluez.AgentManager1
1321+ */
1322+class BluezAgentManager1: public QDBusAbstractInterface
1323+{
1324+ Q_OBJECT
1325+public:
1326+ static inline const char *staticInterfaceName()
1327+ { return "org.bluez.AgentManager1"; }
1328+
1329+public:
1330+ BluezAgentManager1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
1331+
1332+ ~BluezAgentManager1();
1333+
1334+public Q_SLOTS: // METHODS
1335+ inline QDBusPendingReply<> RegisterAgent(const QDBusObjectPath &agent, const QString &capability)
1336+ {
1337+ QList<QVariant> argumentList;
1338+ argumentList << QVariant::fromValue(agent) << QVariant::fromValue(capability);
1339+ return asyncCallWithArgumentList(QStringLiteral("RegisterAgent"), argumentList);
1340+ }
1341+
1342+ inline QDBusPendingReply<> RequestDefaultAgent(const QDBusObjectPath &agent)
1343+ {
1344+ QList<QVariant> argumentList;
1345+ argumentList << QVariant::fromValue(agent);
1346+ return asyncCallWithArgumentList(QStringLiteral("RequestDefaultAgent"), argumentList);
1347+ }
1348+
1349+ inline QDBusPendingReply<> UnregisterAgent(const QDBusObjectPath &agent)
1350+ {
1351+ QList<QVariant> argumentList;
1352+ argumentList << QVariant::fromValue(agent);
1353+ return asyncCallWithArgumentList(QStringLiteral("UnregisterAgent"), argumentList);
1354+ }
1355+
1356+Q_SIGNALS: // SIGNALS
1357+};
1358+
1359+namespace org {
1360+ namespace bluez {
1361+ typedef ::BluezAgentManager1 AgentManager1;
1362+ }
1363+}
1364+#endif
1365
1366=== added file 'plugins/bluetooth/bluez_device1.cpp'
1367--- plugins/bluetooth/bluez_device1.cpp 1970-01-01 00:00:00 +0000
1368+++ plugins/bluetooth/bluez_device1.cpp 2015-11-20 08:48:08 +0000
1369@@ -0,0 +1,26 @@
1370+/*
1371+ * This file was generated by qdbusxml2cpp version 0.8
1372+ * Command line was: qdbusxml2cpp -c BluezDevice1 -p bluez_device1 org.bluez.Device1.xml
1373+ *
1374+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
1375+ *
1376+ * This is an auto-generated file.
1377+ * This file may have been hand-edited. Look for HAND-EDIT comments
1378+ * before re-generating it.
1379+ */
1380+
1381+#include "bluez_device1.h"
1382+
1383+/*
1384+ * Implementation of interface class BluezDevice1
1385+ */
1386+
1387+BluezDevice1::BluezDevice1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
1388+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
1389+{
1390+}
1391+
1392+BluezDevice1::~BluezDevice1()
1393+{
1394+}
1395+
1396
1397=== added file 'plugins/bluetooth/bluez_device1.h'
1398--- plugins/bluetooth/bluez_device1.h 1970-01-01 00:00:00 +0000
1399+++ plugins/bluetooth/bluez_device1.h 2015-11-20 08:48:08 +0000
1400@@ -0,0 +1,85 @@
1401+/*
1402+ * This file was generated by qdbusxml2cpp version 0.8
1403+ * Command line was: qdbusxml2cpp -c BluezDevice1 -p bluez_device1 org.bluez.Device1.xml
1404+ *
1405+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
1406+ *
1407+ * This is an auto-generated file.
1408+ * Do not edit! All changes made to it will be lost.
1409+ */
1410+
1411+#ifndef BLUEZ_DEVICE1_H_1442480478
1412+#define BLUEZ_DEVICE1_H_1442480478
1413+
1414+#include <QtCore/QObject>
1415+#include <QtCore/QByteArray>
1416+#include <QtCore/QList>
1417+#include <QtCore/QMap>
1418+#include <QtCore/QString>
1419+#include <QtCore/QStringList>
1420+#include <QtCore/QVariant>
1421+#include <QtDBus/QtDBus>
1422+
1423+/*
1424+ * Proxy class for interface org.bluez.Device1
1425+ */
1426+class BluezDevice1: public QDBusAbstractInterface
1427+{
1428+ Q_OBJECT
1429+public:
1430+ static inline const char *staticInterfaceName()
1431+ { return "org.bluez.Device1"; }
1432+
1433+public:
1434+ BluezDevice1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
1435+
1436+ ~BluezDevice1();
1437+
1438+public Q_SLOTS: // METHODS
1439+ inline QDBusPendingReply<> CancelPairing()
1440+ {
1441+ QList<QVariant> argumentList;
1442+ return asyncCallWithArgumentList(QStringLiteral("CancelPairing"), argumentList);
1443+ }
1444+
1445+ inline QDBusPendingReply<> Connect()
1446+ {
1447+ QList<QVariant> argumentList;
1448+ return asyncCallWithArgumentList(QStringLiteral("Connect"), argumentList);
1449+ }
1450+
1451+ inline QDBusPendingReply<> ConnectProfile(const QString &UUID)
1452+ {
1453+ QList<QVariant> argumentList;
1454+ argumentList << QVariant::fromValue(UUID);
1455+ return asyncCallWithArgumentList(QStringLiteral("ConnectProfile"), argumentList);
1456+ }
1457+
1458+ inline QDBusPendingReply<> Disconnect()
1459+ {
1460+ QList<QVariant> argumentList;
1461+ return asyncCallWithArgumentList(QStringLiteral("Disconnect"), argumentList);
1462+ }
1463+
1464+ inline QDBusPendingReply<> DisconnectProfile(const QString &UUID)
1465+ {
1466+ QList<QVariant> argumentList;
1467+ argumentList << QVariant::fromValue(UUID);
1468+ return asyncCallWithArgumentList(QStringLiteral("DisconnectProfile"), argumentList);
1469+ }
1470+
1471+ inline QDBusPendingReply<> Pair()
1472+ {
1473+ QList<QVariant> argumentList;
1474+ return asyncCallWithArgumentList(QStringLiteral("Pair"), argumentList);
1475+ }
1476+
1477+Q_SIGNALS: // SIGNALS
1478+};
1479+
1480+namespace org {
1481+ namespace bluez {
1482+ typedef ::BluezDevice1 Device1;
1483+ }
1484+}
1485+#endif
1486
1487=== added file 'plugins/bluetooth/bluez_helper.h'
1488--- plugins/bluetooth/bluez_helper.h 1970-01-01 00:00:00 +0000
1489+++ plugins/bluetooth/bluez_helper.h 2015-11-20 08:48:08 +0000
1490@@ -0,0 +1,29 @@
1491+/*
1492+ * Copyright (C) 2015 Canonical Ltd
1493+ *
1494+ * This program is free software: you can redistribute it and/or modify
1495+ * it under the terms of the GNU General Public License version 3 as
1496+ * published by the Free Software Foundation.
1497+ *
1498+ * This program is distributed in the hope that it will be useful,
1499+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1500+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1501+ * GNU General Public License for more details.
1502+ *
1503+ * You should have received a copy of the GNU General Public License
1504+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1505+ *
1506+*/
1507+
1508+#ifndef BLUEZ_HELPER_H_
1509+#define BLUEZ_HELPER_H_
1510+
1511+#include <QObject>
1512+
1513+typedef QMap<QString, QVariantMap> InterfaceList;
1514+typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList;
1515+
1516+Q_DECLARE_METATYPE(InterfaceList)
1517+Q_DECLARE_METATYPE(ManagedObjectList)
1518+
1519+#endif
1520
1521=== modified file 'plugins/bluetooth/dbus-shared.h'
1522--- plugins/bluetooth/dbus-shared.h 2015-08-28 09:32:38 +0000
1523+++ plugins/bluetooth/dbus-shared.h 2015-11-20 08:48:08 +0000
1524@@ -24,4 +24,13 @@
1525 #define DBUS_ADAPTER_AGENT_PATH "/com/canonical/SettingsBluetoothAgent/adapteragent"
1526 #define DBUS_AGENT_CAPABILITY "KeyboardDisplay"
1527
1528+#define BLUEZ_SERVICE "org.bluez"
1529+
1530+#define BLUEZ_ADAPTER_IFACE "org.bluez.Adapter1"
1531+#define BLUEZ_DEVICE_IFACE "org.bluez.Device1"
1532+
1533+#define watchCall(call, func) \
1534+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); \
1535+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, func)
1536+
1537 #endif // USS_DBUS_SHARED_H
1538
1539=== modified file 'plugins/bluetooth/device.cpp'
1540--- plugins/bluetooth/device.cpp 2015-08-28 09:32:38 +0000
1541+++ plugins/bluetooth/device.cpp 2015-11-20 08:48:08 +0000
1542@@ -26,16 +26,8 @@
1543
1544 #include "dbus-shared.h"
1545
1546-/***
1547-****
1548-***/
1549-
1550-Device::Device(const QMap<QString,QVariant> &properties)
1551-{
1552- setProperties(properties);
1553-}
1554-
1555-Device::Device(const QString &path, QDBusConnection &bus)
1556+Device::Device(const QString &path, QDBusConnection &bus) :
1557+ m_strength(Device::None)
1558 {
1559 initDevice(path, bus);
1560 }
1561@@ -53,53 +45,44 @@
1562 QObject::connect(this, SIGNAL(connectionChanged()), this, SIGNAL(deviceChanged()));
1563 QObject::connect(this, SIGNAL(strengthChanged()), this, SIGNAL(deviceChanged()));
1564
1565- // init the interfaces that we're supporting.
1566- initInterface(m_deviceInterface, path, "org.bluez.Device", bus);
1567- initInterface(m_audioInterface, path, "org.bluez.Audio", bus);
1568- initInterface(m_audioSourceInterface, path, "org.bluez.AudioSource", bus);
1569- initInterface(m_audioSinkInterface, path, "org.bluez.AudioSink", bus);
1570- initInterface(m_headsetInterface, path, "org.bluez.Headset", bus);
1571- initInterface(m_inputInterface, path, "org.bluez.Input", bus);
1572+ m_bluezDevice.reset(new BluezDevice1(BLUEZ_SERVICE, path, bus));
1573+ /* Give our calls a bit more time than the default 25 seconds to
1574+ * complete whatever they are doing. In some situations (e.g. with
1575+ * specific devices) the default doesn't seem to be enough to. */
1576+ m_bluezDevice->setTimeout(60 * 1000 /* 60 seconds */);
1577+
1578+ m_bluezDeviceProperties.reset(new FreeDesktopProperties(BLUEZ_SERVICE, path, bus));
1579+
1580+ QObject::connect(m_bluezDeviceProperties.data(), SIGNAL(PropertiesChanged(const QString&, const QVariantMap&, const QStringList&)),
1581+ this, SLOT(slotPropertiesChanged(const QString&, const QVariantMap&, const QStringList&)));
1582
1583 Q_EMIT(pathChanged());
1584-}
1585-
1586-/***
1587-****
1588-***/
1589-
1590-void Device::slotPropertyChanged(const QString &key,
1591- const QDBusVariant &value)
1592-{
1593- updateProperty (key, value.variant());
1594-}
1595-
1596-void Device::initInterface(QSharedPointer<QDBusInterface> &setme,
1597- const QString &path,
1598- const QString &interfaceName,
1599- QDBusConnection &bus)
1600-{
1601- const QString service = "org.bluez";
1602-
1603- auto i = new QDBusInterface(service, path, interfaceName, bus);
1604-
1605- if (!i->isValid()) {
1606- delete i;
1607- i = 0;
1608- qWarning() << "Couldn't add proxy for" << interfaceName;
1609- } else {
1610- if (!bus.connect(service, path, interfaceName, "PropertyChanged",
1611- this, SLOT(slotPropertyChanged(const QString&, const QDBusVariant&))))
1612- qWarning() << "Unable to connect to " << interfaceName << "::PropertyChanged on" << path;
1613- }
1614-
1615- setme.reset(i);
1616-
1617- if (setme && setme->isValid()) {
1618- QDBusReply<QMap<QString,QVariant> > properties = setme->call("GetProperties");
1619- if (properties.isValid())
1620- setProperties(properties.value());
1621- }
1622+
1623+ watchCall(m_bluezDeviceProperties->GetAll(BLUEZ_DEVICE_IFACE), [=](QDBusPendingCallWatcher *watcher) {
1624+ QDBusPendingReply<QVariantMap> reply = *watcher;
1625+
1626+ if (reply.isError()) {
1627+ qWarning() << "Failed to retrieve properties for device" << m_bluezDevice->path();
1628+ watcher->deleteLater();
1629+ return;
1630+ }
1631+
1632+ auto properties = reply.argumentAt<0>();
1633+ setProperties(properties);
1634+
1635+ watcher->deleteLater();
1636+ });
1637+}
1638+
1639+void Device::slotPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
1640+ const QStringList &invalidatedProperties)
1641+{
1642+ Q_UNUSED(invalidatedProperties);
1643+
1644+ if (interface != BLUEZ_DEVICE_IFACE)
1645+ return;
1646+
1647+ setProperties(changedProperties);
1648 }
1649
1650 void Device::setProperties(const QMap<QString,QVariant> &properties)
1651@@ -111,79 +94,118 @@
1652 }
1653 }
1654
1655-void Device::connectPending()
1656-{
1657- if (m_paired && !m_trusted) {
1658- while (!m_connectAfterPairing.isEmpty()) {
1659- ConnectionMode mode = m_connectAfterPairing.takeFirst();
1660- connect(mode);
1661- }
1662- }
1663-}
1664-
1665-/***
1666-****
1667-***/
1668-
1669-void Device::addConnectAfterPairing(ConnectionMode mode)
1670-{
1671- m_connectAfterPairing.append(mode);
1672-}
1673-
1674-void Device::disconnect(ConnectionMode mode)
1675-{
1676- QSharedPointer<QDBusInterface> interface;
1677-
1678- switch (mode) {
1679- case HeadsetMode:
1680- interface = m_headsetInterface;
1681- break;
1682- case Audio:
1683- interface = m_audioInterface;
1684- break;
1685- case Input:
1686- interface = m_inputInterface;
1687- break;
1688- default:
1689- qWarning() << "Unhandled connection mode" << mode;
1690- return;
1691- }
1692-
1693- QDBusPendingCall call = interface->asyncCall("Disconnect");
1694-
1695- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
1696- QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
1697- QDBusPendingReply<void> reply = *watcher;
1698-
1699- if (reply.isError()) {
1700- qWarning() << "Could not connect device:"
1701- << reply.error().message();
1702- }
1703-
1704- watcher->deleteLater();
1705- });
1706-}
1707-
1708-void Device::connect(ConnectionMode mode)
1709-{
1710- QSharedPointer<QDBusInterface> interface;
1711-
1712- switch (mode) {
1713- case HeadsetMode:
1714- interface = m_headsetInterface;
1715- break;
1716- case Audio:
1717- interface = m_audioInterface;
1718- break;
1719- case Input:
1720- interface = m_inputInterface;
1721- break;
1722- default:
1723- qWarning() << "Unhandled connection mode" << mode;
1724- return;
1725- }
1726-
1727- QDBusPendingCall call = interface->asyncCall("Connect");
1728+void Device::setConnectAfterPairing(bool value)
1729+{
1730+ if (m_connectAfterPairing == value)
1731+ return;
1732+
1733+ m_connectAfterPairing = value;
1734+}
1735+
1736+void Device::disconnect()
1737+{
1738+ setConnection(Device::Disconnecting);
1739+
1740+ QDBusPendingCall call = m_bluezDevice->Disconnect();
1741+
1742+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
1743+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
1744+ QDBusPendingReply<void> reply = *watcher;
1745+
1746+ if (reply.isError()) {
1747+ qWarning() << "Could not disconnect device:"
1748+ << reply.error().message();
1749+
1750+ // Make sure we switch the connection indicator back to
1751+ // a sane state
1752+ updateConnection();
1753+ }
1754+
1755+ watcher->deleteLater();
1756+ });
1757+}
1758+
1759+void Device::connectAfterPairing()
1760+{
1761+ if (!m_connectAfterPairing)
1762+ return;
1763+
1764+ connect();
1765+}
1766+
1767+void Device::pair()
1768+{
1769+ if (m_paired) {
1770+ // If we are already paired we just have to make sure we
1771+ // trigger the connection process if we have to
1772+ connectAfterPairing();
1773+ return;
1774+ }
1775+
1776+ setConnection(Device::Connecting);
1777+
1778+ m_isPairing = true;
1779+
1780+ auto call = m_bluezDevice->asyncCall("Pair");
1781+
1782+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
1783+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
1784+ QDBusPendingReply<void> reply = *watcher;
1785+ bool success = true;
1786+
1787+ if (reply.isError()) {
1788+ qWarning() << "Failed to pair with device:"
1789+ << reply.error().message();
1790+ updateConnection();
1791+ success = false;
1792+ }
1793+
1794+ m_isPairing = false;
1795+
1796+ Q_EMIT(pairingDone(success));
1797+
1798+ watcher->deleteLater();
1799+ });
1800+}
1801+
1802+void Device::cancelPairing()
1803+{
1804+ if (!m_isPairing)
1805+ return;
1806+
1807+ auto call = m_bluezDevice->asyncCall("CancelPairing");
1808+
1809+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
1810+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
1811+ QDBusPendingReply<void> reply = *watcher;
1812+
1813+ if (reply.isError()) {
1814+ qWarning() << "Failed to cancel pairing attempt with device:"
1815+ << reply.error().message();
1816+ updateConnection();
1817+ } else {
1818+ // Only mark us a not pairing when call succeeded
1819+ m_isPairing = false;
1820+ }
1821+
1822+ watcher->deleteLater();
1823+ });
1824+}
1825+
1826+void Device::connect()
1827+{
1828+ // If we have just paired then the device switched to connected = true for
1829+ // a short moment as BlueZ opened up a RFCOMM channel to perform SDP. If
1830+ // we should connect with the device on specific profiles now we go ahead
1831+ // here even if we're marked as connected as this still doesn't mean we're
1832+ // connected on any profile. Calling org.bluez.Device1.Connect multiple
1833+ // times doesn't hurt an will not fail.
1834+ if (m_isConnected && !m_connectAfterPairing)
1835+ return;
1836+
1837+ setConnection(Device::Connecting);
1838+
1839+ QDBusPendingCall call = m_bluezDevice->asyncCall("Connect");
1840
1841 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
1842 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
1843@@ -196,6 +218,12 @@
1844 makeTrusted(true);
1845 }
1846
1847+ // Regardless if the Connected property has changed or not we update
1848+ // the connection state here as the connection process is over now
1849+ // and we should have received any state change already at this
1850+ // point.
1851+ updateConnection();
1852+
1853 watcher->deleteLater();
1854 });
1855 }
1856@@ -205,36 +233,22 @@
1857 QDBusPendingReply<void> reply = *call;
1858
1859 if (reply.isError()) {
1860- qWarning() << "Could not set device as trusted:"
1861+ qWarning() << "Could not mark device as trusted:"
1862 << reply.error().message();
1863 }
1864+
1865 call->deleteLater();
1866 }
1867
1868 void Device::makeTrusted(bool trusted)
1869 {
1870- QVariant value;
1871- QDBusVariant variant(trusted);
1872-
1873- value.setValue(variant);
1874-
1875- if (m_deviceInterface) {
1876- QDBusPendingCall pcall
1877- = m_deviceInterface->asyncCall("SetProperty", "Trusted", value);
1878-
1879- QDBusPendingCallWatcher *watcher
1880- = new QDBusPendingCallWatcher(pcall, this);
1881- QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
1882- this, SLOT(slotMakeTrustedDone(QDBusPendingCallWatcher*)));
1883- } else {
1884- qWarning() << "Can't set device trusted before it is added in BlueZ";
1885- }
1886+ auto call = m_bluezDeviceProperties->Set(BLUEZ_DEVICE_IFACE, "Trusted", QDBusVariant(trusted));
1887+
1888+ auto watcher = new QDBusPendingCallWatcher(call, this);
1889+ QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
1890+ this, SLOT(slotMakeTrustedDone(QDBusPendingCallWatcher*)));
1891 }
1892
1893-/***
1894-****
1895-***/
1896-
1897 void Device::setName(const QString &name)
1898 {
1899 if (m_name != name) {
1900@@ -342,42 +356,34 @@
1901 {
1902 Connection c;
1903
1904- /* The "State" property is a little more useful this "Connected" bool
1905- because the former tells us Bluez *knows* a device is connecting.
1906- So use "Connected" only as a fallback */
1907-
1908- if ((m_state == "connected") || (m_state == "playing"))
1909- c = Connection::Connected;
1910- else if (m_state == "connecting")
1911- c = Connection::Connecting;
1912- else if (m_state == "disconnected")
1913- c = Connection::Disconnected;
1914- else
1915- c = m_isConnected ? Connection::Connected : Connection::Disconnected;
1916+ c = m_isConnected ? Connection::Connected : Connection::Disconnected;
1917
1918 setConnection(c);
1919 }
1920
1921 void Device::updateProperty(const QString &key, const QVariant &value)
1922 {
1923- if (key == "Name") { // org.bluez.Device
1924+ if (key == "Name") {
1925 setName(value.toString());
1926- } else if (key == "Address") { // org.bluez.Device
1927+ } else if (key == "Address") {
1928 setAddress(value.toString());
1929- } else if (key == "State") { // org.bluez.Audio, org.bluez.Headset
1930- m_state = value.toString();
1931- updateConnection();
1932 } else if (key == "Connected") {
1933 m_isConnected = value.toBool();
1934 updateConnection();
1935- } else if (key == "Class") { // org.bluez.Device
1936+ } else if (key == "Class") {
1937 setType(getTypeFromClass(value.toUInt()));
1938- } else if (key == "Paired") { // org.bluez.Device
1939+ } else if (key == "Paired") {
1940 setPaired(value.toBool());
1941+
1942+ if (m_paired && m_connectAfterPairing) {
1943+ connectAfterPairing();
1944+ return;
1945+ }
1946+
1947 updateConnection();
1948- } else if (key == "Trusted") { // org.bluez.Device
1949+ } else if (key == "Trusted") {
1950 setTrusted(value.toBool());
1951- } else if (key == "Icon") { // org.bluez.Device
1952+ } else if (key == "Icon") {
1953 m_fallbackIconName = value.toString();
1954 updateIcon ();
1955 } else if (key == "RSSI") {
1956@@ -386,10 +392,6 @@
1957 }
1958 }
1959
1960-/***
1961-****
1962-***/
1963-
1964 /* Determine the Type from the bits in the Class of Device (CoD) field.
1965 https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband */
1966 Device::Type Device::getTypeFromClass (quint32 c)
1967@@ -468,6 +470,11 @@
1968 if ((c & 0x20) != 0)
1969 return Type::Camera;
1970 break;
1971+
1972+ case 0x07:
1973+ if ((c & 0x4) != 0)
1974+ return Type::Watch;
1975+ break;
1976 }
1977
1978 return Type::Other;
1979@@ -489,4 +496,3 @@
1980
1981 return None;
1982 }
1983-
1984
1985=== modified file 'plugins/bluetooth/device.h'
1986--- plugins/bluetooth/device.h 2015-08-28 09:32:38 +0000
1987+++ plugins/bluetooth/device.h 2015-11-20 08:48:08 +0000
1988@@ -26,6 +26,9 @@
1989 #include <QSharedPointer>
1990 #include <QString>
1991
1992+#include "freedesktop_properties.h"
1993+#include "bluez_device1.h"
1994+
1995 struct Device: QObject
1996 {
1997 Q_OBJECT
1998@@ -71,17 +74,14 @@
1999
2000 enum Type { Other, Computer, Cellular, Smartphone, Phone, Modem, Network,
2001 Headset, Speakers, Headphones, Video, OtherAudio, Joypad,
2002- Keypad, Keyboard, Tablet, Mouse, Printer, Camera, Carkit };
2003+ Keypad, Keyboard, Tablet, Mouse, Printer, Camera, Carkit, Watch };
2004
2005 enum Strength { None, Poor, Fair, Good, Excellent };
2006
2007 enum Connection { Disconnected=1, Connecting=2,
2008 Connected=4, Disconnecting=8 };
2009
2010- enum ConnectionMode { Audio, AudioSource, AudioSink, HandsfreeGateway,
2011- HeadsetMode, Input };
2012-
2013- Q_ENUMS(Type Strength Connection ConnectionMode)
2014+ Q_ENUMS(Type Strength Connection)
2015
2016 Q_DECLARE_FLAGS(Connections, Connection)
2017
2018@@ -96,6 +96,7 @@
2019 void connectionChanged();
2020 void strengthChanged();
2021 void deviceChanged(); // catchall for any change
2022+ void pairingDone(bool success);
2023
2024 public:
2025 const QString& getName() const { return m_name; }
2026@@ -106,7 +107,7 @@
2027 bool isTrusted() const { return m_trusted; }
2028 Connection getConnection() const { return m_connection; }
2029 Strength getStrength() const { return m_strength; }
2030- QString getPath() const { return m_deviceInterface ? m_deviceInterface->path() : QString(); }
2031+ QString getPath() const { return m_bluezDevice ? m_bluezDevice->path() : QString(); }
2032
2033 private:
2034 QString m_name;
2035@@ -120,13 +121,10 @@
2036 Connection m_connection = Connection::Disconnected;
2037 Strength m_strength = Strength::None;
2038 bool m_isConnected = false;
2039- QSharedPointer<QDBusInterface> m_deviceInterface;
2040- QSharedPointer<QDBusInterface> m_audioInterface;
2041- QSharedPointer<QDBusInterface> m_audioSourceInterface;
2042- QSharedPointer<QDBusInterface> m_audioSinkInterface;
2043- QSharedPointer<QDBusInterface> m_headsetInterface;
2044- QSharedPointer<QDBusInterface> m_inputInterface;
2045- QList<ConnectionMode> m_connectAfterPairing;
2046+ bool m_connectAfterPairing = false;
2047+ QScopedPointer<BluezDevice1> m_bluezDevice;
2048+ QScopedPointer<FreeDesktopProperties> m_bluezDeviceProperties;
2049+ bool m_isPairing = false;
2050
2051 protected:
2052 void setName(const QString &name);
2053@@ -142,30 +140,29 @@
2054
2055 public:
2056 Device() {}
2057+ Device(const QString &path, QDBusConnection &bus);
2058 ~Device() {}
2059- Device(const QString &path, QDBusConnection &bus);
2060- Device(const QMap<QString,QVariant> &properties);
2061- void initDevice(const QString &path, QDBusConnection &bus);
2062 bool isValid() const { return getType() != Type::Other; }
2063- void connect(ConnectionMode);
2064+ void pair();
2065+ Q_INVOKABLE void cancelPairing();
2066+ void connect();
2067 void makeTrusted(bool trusted);
2068- void disconnect(ConnectionMode);
2069+ void disconnect();
2070 void setProperties(const QMap<QString,QVariant> &properties);
2071- void addConnectAfterPairing(const ConnectionMode mode);
2072-
2073- public Q_SLOTS:
2074- void connectPending();
2075+ void setConnectAfterPairing(bool value);
2076
2077 private Q_SLOTS:
2078- void slotPropertyChanged(const QString &key, const QDBusVariant &value);
2079+ void slotPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
2080+ const QStringList &invalidatedProperties);
2081 void slotMakeTrustedDone(QDBusPendingCallWatcher *call);
2082
2083 private:
2084+ void initDevice(const QString &path, QDBusConnection &bus);
2085 void updateProperties(QSharedPointer<QDBusInterface>);
2086- void initInterface(QSharedPointer<QDBusInterface>&, const QString &path, const QString &name, QDBusConnection&);
2087 void updateProperty(const QString &key, const QVariant &value);
2088 static Type getTypeFromClass(quint32 bluetoothClass);
2089 Device::Strength getStrengthFromRssi(int rssi);
2090+ void connectAfterPairing();
2091 };
2092
2093 Q_DECLARE_METATYPE(Device*)
2094
2095=== modified file 'plugins/bluetooth/devicemodel.cpp'
2096--- plugins/bluetooth/devicemodel.cpp 2015-08-28 09:32:38 +0000
2097+++ plugins/bluetooth/devicemodel.cpp 2015-11-20 08:48:08 +0000
2098@@ -27,33 +27,81 @@
2099
2100 namespace
2101 {
2102- const int SCANNING_ACTIVE_DURATION_MSEC = (10 * 1000);
2103-
2104+ const int SCANNING_ACTIVE_DURATION_MSEC = (30 * 1000);
2105 const int SCANNING_IDLE_DURATION_MSEC = (10 * 1000);
2106 }
2107
2108 DeviceModel::DeviceModel(QDBusConnection &dbus, QObject *parent):
2109 QAbstractListModel(parent),
2110 m_dbus(dbus),
2111- m_bluezManager("org.bluez", "/", "org.bluez.Manager", m_dbus)
2112+ m_bluezManager("org.bluez", "/", m_dbus),
2113+ m_bluezAgentManager("org.bluez", "/org/bluez", m_dbus),
2114+ m_isPowered(false),
2115+ m_isPairable(false),
2116+ m_isDiscovering(false),
2117+ m_isDiscoverable(false)
2118 {
2119 if (m_bluezManager.isValid()) {
2120
2121- QDBusReply<QDBusObjectPath> qObjectPath = m_bluezManager.call("DefaultAdapter");
2122- if (qObjectPath.isValid())
2123- setAdapterFromPath(qObjectPath.value().path());
2124-
2125- m_dbus.connect (m_bluezManager.service(),
2126- m_bluezManager.path(),
2127- m_bluezManager.interface(),
2128- "DefaultAdapterChanged",
2129- this, SLOT(slotDefaultAdapterChanged(const QDBusObjectPath&)));
2130-
2131- m_dbus.connect (m_bluezManager.service(),
2132- m_bluezManager.path(),
2133- m_bluezManager.interface(),
2134- "AdapterRemoved",
2135- this, SLOT(slotAdapterRemoved(const QDBusObjectPath&)));
2136+ connect(&m_bluezManager, SIGNAL(InterfacesAdded(const QDBusObjectPath&, InterfaceList)),
2137+ this, SLOT(slotInterfacesAdded(const QDBusObjectPath&, InterfaceList)));
2138+
2139+ connect(&m_bluezManager, SIGNAL(InterfacesRemoved(const QDBusObjectPath&, const QStringList&)),
2140+ this, SLOT(slotInterfacesRemoved(const QDBusObjectPath&, const QStringList&)));
2141+
2142+ watchCall(m_bluezManager.GetManagedObjects(), [=](QDBusPendingCallWatcher *watcher) {
2143+ QDBusPendingReply<ManagedObjectList> reply = *watcher;
2144+
2145+ if (reply.isError()) {
2146+ qWarning() << "Failed to retrieve list of managed objects from BlueZ service: "
2147+ << reply.error().message();
2148+ watcher->deleteLater();
2149+ return;
2150+ }
2151+
2152+ auto objectList = reply.argumentAt<0>();
2153+
2154+ for (QDBusObjectPath path : objectList.keys()) {
2155+ InterfaceList ifaces = objectList.value(path);
2156+
2157+ if (!ifaces.contains(BLUEZ_ADAPTER_IFACE))
2158+ continue;
2159+
2160+ // Ok, here we've found an adapter. As we don't expect multiple at the
2161+ // moment we just take the first one we find.
2162+ setAdapterFromPath(path.path(), ifaces.value(BLUEZ_ADAPTER_IFACE));
2163+ break;
2164+ }
2165+
2166+ watcher->deleteLater();
2167+ });
2168+ }
2169+
2170+ if (m_bluezAgentManager.isValid()) {
2171+ // NOTE: We can safely register our agent here even if we don't
2172+ // manage any adapter yet. BlueZ makes sure our agent will only
2173+ // process requests related to actions we do unless we our agent
2174+ // the system default one.
2175+ auto call = m_bluezAgentManager.RegisterAgent(QDBusObjectPath(DBUS_ADAPTER_AGENT_PATH),
2176+ DBUS_AGENT_CAPABILITY);
2177+
2178+ watchCall(call, [=](QDBusPendingCallWatcher *watcher) {
2179+ QDBusPendingReply<void> reply = *watcher;
2180+
2181+ if (reply.isError()) {
2182+ qWarning() << "Failed to register our agent with BlueZ:"
2183+ << reply.error().message();
2184+ }
2185+ else {
2186+ setupAsDefaultAgent();
2187+ }
2188+
2189+ watcher->deleteLater();
2190+ });
2191+ }
2192+ else {
2193+ qWarning() << "Could not register agent with BlueZ service as "
2194+ << "the agent manager is not available!";
2195 }
2196
2197 connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
2198@@ -62,6 +110,89 @@
2199 DeviceModel::~DeviceModel()
2200 {
2201 clearAdapter();
2202+
2203+ qWarning() << "Releasing device model ..";
2204+
2205+ if (m_bluezAgentManager.isValid()) {
2206+ auto call = m_bluezAgentManager.UnregisterAgent(QDBusObjectPath(DBUS_ADAPTER_AGENT_PATH));
2207+ watchCall(call, [=](QDBusPendingCallWatcher *watcher) {
2208+ QDBusPendingReply<void> reply = *watcher;
2209+
2210+ if (reply.isError()) {
2211+ qWarning() << "Failed to unregister our agent with BlueZ:"
2212+ << reply.error().message();
2213+ }
2214+
2215+ watcher->deleteLater();
2216+ });
2217+ }
2218+}
2219+
2220+void DeviceModel::setupAsDefaultAgent()
2221+{
2222+ auto call = m_bluezAgentManager.RequestDefaultAgent(QDBusObjectPath(DBUS_ADAPTER_AGENT_PATH));
2223+ watchCall(call, [=](QDBusPendingCallWatcher *watcher) {
2224+ QDBusPendingReply<void> reply = *watcher;
2225+
2226+ if (reply.isError()) {
2227+ qWarning() << "Failed to setup ourself as default agent: "
2228+ << reply.error().message();
2229+ }
2230+
2231+ watcher->deleteLater();
2232+ });
2233+}
2234+
2235+void DeviceModel::slotInterfacesAdded(const QDBusObjectPath &objectPath, InterfaceList ifacesAndProps)
2236+{
2237+ Q_UNUSED(ifacesAndProps);
2238+
2239+ auto candidatedPath = objectPath.path();
2240+
2241+ if (!m_bluezAdapter) {
2242+ // Maybe we have a new adapter we can start to use?
2243+ if (ifacesAndProps.contains(BLUEZ_ADAPTER_IFACE))
2244+ setAdapterFromPath(candidatedPath, ifacesAndProps.value(BLUEZ_ADAPTER_IFACE));
2245+
2246+ return;
2247+ }
2248+
2249+ // At this point we can only get new devices
2250+ if (!candidatedPath.startsWith(m_bluezAdapter->path()))
2251+ return;
2252+
2253+ if (!ifacesAndProps.contains(BLUEZ_DEVICE_IFACE))
2254+ return;
2255+
2256+ addDevice(candidatedPath, ifacesAndProps.value(BLUEZ_DEVICE_IFACE));
2257+}
2258+
2259+void DeviceModel::slotInterfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces)
2260+{
2261+ auto candidatedPath = objectPath.path();
2262+
2263+ if (!m_bluezAdapter)
2264+ return;
2265+
2266+ if (candidatedPath == m_bluezAdapter->path() &&
2267+ interfaces.contains(BLUEZ_ADAPTER_IFACE)) {
2268+ clearAdapter();
2269+ return;
2270+ }
2271+
2272+ if (!candidatedPath.startsWith(m_bluezAdapter->path()))
2273+ return;
2274+
2275+ if (!interfaces.contains(BLUEZ_DEVICE_IFACE))
2276+ return;
2277+
2278+ auto device = getDeviceFromPath(candidatedPath);
2279+ if (!device)
2280+ return;
2281+
2282+ const int row = findRowFromAddress(device->getAddress());
2283+ if ((row >= 0))
2284+ removeRow(row);
2285 }
2286
2287 int DeviceModel::findRowFromAddress(const QString &address) const
2288@@ -79,27 +210,45 @@
2289 : SCANNING_IDLE_DURATION_MSEC);
2290 }
2291
2292+void DeviceModel::setDiscovering(bool value)
2293+{
2294+ if (value == m_isDiscovering)
2295+ return;
2296+
2297+ m_isDiscovering = value;
2298+ Q_EMIT(discoveringChanged(m_isDiscovering));
2299+}
2300+
2301 void DeviceModel::stopDiscovery()
2302 {
2303- if (m_isDiscovering) {
2304- if (m_bluezAdapter)
2305- m_bluezAdapter->asyncCall("StopDiscovery");
2306- m_isDiscovering = false;
2307- Q_EMIT(discoveringChanged(m_isDiscovering));
2308+ if (m_bluezAdapter && m_isPowered && m_isDiscovering) {
2309+
2310+ watchCall(m_bluezAdapter->StopDiscovery(), [=](QDBusPendingCallWatcher *watcher) {
2311+ QDBusPendingReply<void> reply = *watcher;
2312+ if (reply.isError()) {
2313+ qWarning() << "Failed to stop device discovery:"
2314+ << reply.error().message();
2315+ }
2316+
2317+ watcher->deleteLater();
2318+ });
2319 }
2320-
2321- restartTimer();
2322 }
2323
2324 void DeviceModel::startDiscovery()
2325 {
2326 if (m_bluezAdapter && m_isPowered && !m_isDiscovering) {
2327- m_bluezAdapter->asyncCall("StartDiscovery");
2328- m_isDiscovering = true;
2329- Q_EMIT(discoveringChanged(m_isDiscovering));
2330+
2331+ watchCall(m_bluezAdapter->StartDiscovery(), [=](QDBusPendingCallWatcher *watcher) {
2332+ QDBusPendingReply<void> reply = *watcher;
2333+ if (reply.isError()) {
2334+ qWarning() << "Failed to start device discovery:"
2335+ << reply.error().message();
2336+ }
2337+
2338+ watcher->deleteLater();
2339+ });
2340 }
2341-
2342- restartTimer();
2343 }
2344
2345 void DeviceModel::toggleDiscovery()
2346@@ -119,27 +268,12 @@
2347 {
2348 if (m_bluezAdapter) {
2349
2350- QDBusConnection bus = m_bluezAdapter->connection();
2351- const QString service = m_bluezAdapter->service();
2352- const QString path = m_bluezAdapter->path();
2353- const QString interface = m_bluezAdapter->interface();
2354-
2355 stopDiscovery();
2356 m_discoverableTimer.stop();
2357 trySetDiscoverable(false);
2358
2359- bus.disconnect(service, path, interface, "DeviceCreated",
2360- this, SLOT(slotDeviceCreated(const QDBusObjectPath&)));
2361- bus.disconnect(service, path, interface, "DeviceRemoved",
2362- this, SLOT(slotDeviceRemoved(const QDBusObjectPath&)));
2363- bus.disconnect(service, path, interface, "DeviceFound",
2364- this, SLOT(slotDeviceFound(const QString&, const QMap<QString,QVariant>&)));
2365- bus.disconnect(service, path, interface, "DeviceDisappeared",
2366- this, SLOT(slotDeviceDisappeared(const QString&)));
2367- bus.disconnect(service, path, interface, "PropertyChanged",
2368- this, SLOT(slotPropertyChanged(const QString&, const QDBusVariant&)));
2369-
2370 m_bluezAdapter.reset(0);
2371+ m_bluezAdapterProperties.reset(0);
2372 m_adapterName.clear();
2373
2374 beginResetModel();
2375@@ -148,68 +282,75 @@
2376 }
2377 }
2378
2379-void DeviceModel::setAdapterFromPath(const QString &path)
2380+void DeviceModel::setAdapterFromPath(const QString &path, const QVariantMap &properties)
2381 {
2382 clearAdapter();
2383
2384 if (!path.isEmpty()) {
2385
2386- const QString service = "org.bluez";
2387- const QString interface = "org.bluez.Adapter";
2388- auto i = new QDBusInterface(service, path, interface, m_dbus);
2389-
2390- m_dbus.connect(service, path, interface, "DeviceCreated",
2391- this, SLOT(slotDeviceCreated(const QDBusObjectPath&)));
2392- m_dbus.connect(service, path, interface, "DeviceRemoved",
2393- this, SLOT(slotDeviceRemoved(const QDBusObjectPath&)));
2394- m_dbus.connect(service, path, interface, "DeviceFound",
2395- this, SLOT(slotDeviceFound(const QString&, const QMap<QString,QVariant>&)));
2396- m_dbus.connect(service, path, interface, "DeviceDisappeared",
2397- this, SLOT(slotDeviceDisappeared(const QString&)));
2398- m_dbus.connect(service, path, interface, "PropertyChanged",
2399- this, SLOT(slotPropertyChanged(const QString&, const QDBusVariant&)));
2400-
2401- m_bluezAdapter.reset(i);
2402+ auto adapter = new BluezAdapter1(BLUEZ_SERVICE, path, m_dbus);
2403+ auto adapterProperties = new FreeDesktopProperties(BLUEZ_SERVICE, path, m_dbus);
2404+
2405+ m_bluezAdapter.reset(adapter);
2406+ m_bluezAdapterProperties.reset(adapterProperties);
2407+
2408 startDiscovery();
2409 updateDevices();
2410
2411- QDBusReply<QMap<QString,QVariant> > properties = m_bluezAdapter->call("GetProperties");
2412- if (properties.isValid())
2413- setProperties(properties.value());
2414+ setProperties(properties);
2415+
2416+ connect(adapterProperties, SIGNAL(PropertiesChanged(const QString&, const QVariantMap&, const QStringList&)),
2417+ this, SLOT(slotAdapterPropertiesChanged(const QString&, const QVariantMap&, const QStringList&)));
2418
2419 // Delay enabling discoverability by 1 second.
2420 m_discoverableTimer.setSingleShot(true);
2421 connect(&m_discoverableTimer, SIGNAL(timeout()), this, SLOT(slotEnableDiscoverable()));
2422 m_discoverableTimer.start(1000);
2423-
2424- // With the agent registered on the bus, make it known by the adapter
2425- QDBusReply<void > reply = m_bluezAdapter->call("RegisterAgent",
2426- qVariantFromValue(QDBusObjectPath(DBUS_ADAPTER_AGENT_PATH)),
2427- QString(DBUS_AGENT_CAPABILITY));
2428- if (!reply.isValid())
2429- qWarning() << "Error registering agent for the default adapter:" << reply.error();
2430 }
2431 }
2432
2433-void DeviceModel::slotAdapterRemoved(const QDBusObjectPath &path)
2434-{
2435- if (m_bluezAdapter && (m_bluezAdapter->path()==path.path()))
2436- clearAdapter();
2437-}
2438-
2439-void DeviceModel::slotDefaultAdapterChanged(const QDBusObjectPath &objectPath)
2440-{
2441- setAdapterFromPath (objectPath.path());
2442+void DeviceModel::slotAdapterPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
2443+ const QStringList &invalidatedProperties)
2444+{
2445+ Q_UNUSED(invalidatedProperties);
2446+
2447+ if (interface != BLUEZ_ADAPTER_IFACE)
2448+ return;
2449+
2450+ setProperties(changedProperties);
2451 }
2452
2453 void DeviceModel::updateDevices()
2454 {
2455- if (m_bluezAdapter && m_bluezAdapter->isValid()) {
2456- QDBusReply<QList<QDBusObjectPath> > reply = m_bluezAdapter->call("ListDevices");
2457- if (reply.isValid())
2458- for (auto path : reply.value())
2459- addDevice(path.path());
2460- }
2461+ watchCall(m_bluezManager.GetManagedObjects(), [=](QDBusPendingCallWatcher *watcher) {
2462+ QDBusPendingReply<ManagedObjectList> reply = *watcher;
2463+
2464+ if (reply.isError()) {
2465+ qWarning() << "Failed to retrieve list of managed objects from BlueZ service: "
2466+ << reply.error().message();
2467+ watcher->deleteLater();
2468+ return;
2469+ }
2470+
2471+ auto objectList = reply.argumentAt<0>();
2472+
2473+ for (auto objectPath : objectList.keys()) {
2474+ auto candidatePath = objectPath.path();
2475+
2476+ if (!candidatePath.startsWith(m_bluezAdapter->path()))
2477+ continue;
2478+
2479+ InterfaceList ifaces = objectList.value(objectPath);
2480+
2481+ if (!ifaces.contains(BLUEZ_DEVICE_IFACE))
2482+ continue;
2483+
2484+ auto properties = ifaces.value(BLUEZ_DEVICE_IFACE);
2485+
2486+ addDevice(candidatePath, properties);
2487+ }
2488+
2489+ });
2490 }
2491
2492 void DeviceModel::setProperties(const QMap<QString,QVariant> &properties)
2493@@ -231,6 +372,9 @@
2494 m_isPairable = value.toBool();
2495 } else if (key == "Discoverable") {
2496 setDiscoverable(value.toBool());
2497+ } else if (key == "Discovering") {
2498+ setDiscovering(value.toBool());
2499+ restartTimer();
2500 } else if (key == "Powered") {
2501 setPowered(value.toBool());
2502 if (m_isPowered)
2503@@ -268,7 +412,7 @@
2504 value.setValue(disc);
2505
2506 if (m_bluezAdapter && m_bluezAdapter->isValid() && m_isPowered) {
2507- reply = m_bluezAdapter->call("SetProperty", "Discoverable", value);
2508+ reply = m_bluezAdapterProperties->call("Set", BLUEZ_ADAPTER_IFACE, "Discoverable", value);
2509 if (!reply.isValid())
2510 qWarning() << "Error setting device discoverable:" << reply.error();
2511 }
2512@@ -280,12 +424,23 @@
2513 updateProperty (key, value.variant());
2514 }
2515
2516-void DeviceModel::addDevice(const QString &path)
2517+void DeviceModel::slotDevicePairingDone(bool success)
2518+{
2519+ Device *device = static_cast<Device*>(sender());
2520+
2521+ Q_EMIT(devicePairingDone(device, success));
2522+}
2523+
2524+void DeviceModel::addDevice(const QString &path, const QVariantMap &properties)
2525 {
2526 QSharedPointer<Device> device(new Device(path, m_dbus));
2527+ device->setProperties(properties);
2528+
2529 if (device->isValid()) {
2530 QObject::connect(device.data(), SIGNAL(deviceChanged()),
2531 this, SLOT(slotDeviceChanged()));
2532+ QObject::connect(device.data(), SIGNAL(pairingDone(bool)),
2533+ this, SLOT(slotDevicePairingDone(bool)));
2534 addDevice(device);
2535 }
2536 }
2537@@ -322,78 +477,6 @@
2538 }
2539 }
2540
2541-void DeviceModel::slotDeviceCreated(const QDBusObjectPath &path)
2542-{
2543- const QString service = "org.bluez";
2544- const QString interface = "org.bluez.Device";
2545- QScopedPointer<QDBusInterface> bluezDevice(
2546- new QDBusInterface(service, path.path(), interface, m_dbus));
2547-
2548- // A device was created. Now, we likely already have it, so let's find it
2549- // again and finish the initialization.
2550- QDBusReply<QMap<QString,QVariant> > properties
2551- = bluezDevice->call("GetProperties");
2552- if (properties.isValid()) {
2553- QMapIterator<QString,QVariant> it(properties);
2554- while (it.hasNext()) {
2555- it.next();
2556- if (it.key() == "Address") {
2557- QSharedPointer<Device> device = getDeviceFromAddress(it.value().toString());
2558-
2559- if (device) {
2560- device->initDevice(path.path(), m_dbus);
2561- QObject::connect(device.data(), SIGNAL(deviceChanged()),
2562- this, SLOT(slotDeviceChanged()));
2563- addDevice(device);
2564- } else {
2565- addDevice(path.path());
2566- }
2567- break;
2568- }
2569- }
2570- } else {
2571- qWarning() << "Invalid device properties for" << path.path();
2572- }
2573-}
2574-
2575-void DeviceModel::slotDeviceFound(const QString &address,
2576- const QMap<QString,QVariant> &properties)
2577-{
2578- Q_UNUSED(properties);
2579-
2580- QSharedPointer<Device> device = getDeviceFromAddress(address);
2581-
2582- if (!device) {
2583- QSharedPointer<Device> device(new Device(properties));
2584- if (device->isValid()) {
2585- addDevice(device);
2586- }
2587- } else {
2588- device->setProperties(properties);
2589- }
2590-}
2591-
2592-void DeviceModel::slotDeviceRemoved(const QDBusObjectPath &path)
2593-{
2594- /* Remove the device immediately, it will be listed again
2595- once discovery results are returned. */
2596-
2597- auto device = getDeviceFromPath(path.path());
2598-
2599- if (device != nullptr) {
2600- const int row = findRowFromAddress(device->getAddress());
2601- if ((row >= 0))
2602- removeRow(row);
2603- }
2604-}
2605-
2606-void DeviceModel::slotDeviceDisappeared(const QString &address)
2607-{
2608- const int row = findRowFromAddress(address);
2609- if ((row >= 0) && !m_devices[row]->isPaired())
2610- removeRow(row);
2611-}
2612-
2613 void DeviceModel::slotDeviceChanged()
2614 {
2615 const Device * device = qobject_cast<Device*>(sender());
2616@@ -429,61 +512,6 @@
2617 return QSharedPointer<Device>();
2618 }
2619
2620-void DeviceModel::addConnectAfterPairing(const QString &address, Device::ConnectionMode mode)
2621-{
2622- QSharedPointer<Device> device = getDeviceFromAddress(address);
2623- if (device) {
2624- device->addConnectAfterPairing(mode);
2625- } else {
2626- qWarning() << "Device could not be found, can't add an operation";
2627- }
2628-}
2629-
2630-void DeviceModel::slotCreateFinished(QDBusPendingCallWatcher *call)
2631-{
2632- QDBusPendingReply<QDBusObjectPath> reply = *call;
2633-
2634- if (reply.isError()) {
2635- qWarning() << "Could not create device:" << reply.error().message();
2636- }
2637-
2638- call->deleteLater();
2639-}
2640-
2641-void DeviceModel::createDevice (const QString &address, QObject *agent)
2642-{
2643- if (m_bluezAdapter) {
2644- QString agent_path(DBUS_AGENT_PATH);
2645- agent_path.append("/");
2646- agent_path.append(address);
2647- agent_path.replace(":", "_");
2648-
2649- if(!m_dbus.registerObject(agent_path, agent))
2650- qCritical() << "Couldn't register agent at" << agent_path;
2651-
2652- QDBusPendingCall pcall = m_bluezAdapter->asyncCall("CreatePairedDevice",
2653- address,
2654- qVariantFromValue(QDBusObjectPath(agent_path)),
2655- QString(DBUS_AGENT_CAPABILITY));
2656-
2657- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
2658- QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this, address](QDBusPendingCallWatcher *watcher) {
2659- QDBusPendingReply<QDBusObjectPath> reply = *watcher;
2660-
2661- if (reply.isError()) {
2662- qWarning() << "Could not create device:" << reply.error().message();
2663- } else {
2664- QSharedPointer<Device> device = getDeviceFromAddress(address);
2665- device->connectPending();
2666- }
2667-
2668- watcher->deleteLater();
2669- });
2670- } else {
2671- qWarning() << "Default adapter is not available for device creation";
2672- }
2673-}
2674-
2675 void DeviceModel::slotRemoveFinished(QDBusPendingCallWatcher *call)
2676 {
2677 QDBusPendingReply<void> reply = *call;
2678@@ -496,19 +524,19 @@
2679
2680 void DeviceModel::removeDevice (const QString &path)
2681 {
2682- if (m_bluezAdapter) {
2683- QDBusPendingCall pcall = m_bluezAdapter->asyncCall("RemoveDevice", qVariantFromValue(QDBusObjectPath(path)));
2684-
2685- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
2686- QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
2687- this, SLOT(slotRemoveFinished(QDBusPendingCallWatcher*)));
2688- } else {
2689+ if (!m_bluezAdapter) {
2690 qWarning() << "Default adapter is not available for device removal";
2691+ return;
2692 }
2693+
2694+ QDBusPendingCall call = m_bluezAdapter->RemoveDevice(QDBusObjectPath(path));
2695+
2696+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
2697+ QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
2698+ this, SLOT(slotRemoveFinished(QDBusPendingCallWatcher*)));
2699 }
2700
2701-int
2702-DeviceModel::rowCount(const QModelIndex &parent) const
2703+int DeviceModel::rowCount(const QModelIndex &parent) const
2704 {
2705 Q_UNUSED(parent);
2706
2707@@ -583,13 +611,6 @@
2708 return ret;
2709 }
2710
2711-
2712-/***
2713-****
2714-**** Filter
2715-****
2716-***/
2717-
2718 void DeviceFilter::filterOnType(QVector<Device::Type> types)
2719 {
2720 m_types = types;
2721
2722=== modified file 'plugins/bluetooth/devicemodel.h'
2723--- plugins/bluetooth/devicemodel.h 2015-08-28 09:32:38 +0000
2724+++ plugins/bluetooth/devicemodel.h 2015-11-20 08:48:08 +0000
2725@@ -35,6 +35,11 @@
2726
2727 #include "device.h"
2728
2729+#include "freedesktop_objectmanager.h"
2730+#include "freedesktop_properties.h"
2731+#include "bluez_adapter1.h"
2732+#include "bluez_agentmanager1.h"
2733+
2734 class DeviceModel: public QAbstractListModel
2735 {
2736 Q_OBJECT
2737@@ -68,8 +73,6 @@
2738 bool isPowered() const { return m_isPowered; }
2739 bool isDiscovering() const { return m_isDiscovering; }
2740 bool isDiscoverable() const { return m_isDiscoverable; }
2741- void addConnectAfterPairing(const QString &address, Device::ConnectionMode mode);
2742- void createDevice(const QString &address, QObject *agent);
2743 void removeDevice(const QString &path);
2744 void stopDiscovery();
2745 void startDiscovery();
2746@@ -80,10 +83,12 @@
2747 void poweredChanged(bool powered);
2748 void discoveringChanged(bool isDiscovering);
2749 void discoverableChanged(bool isDiscoverable);
2750+ void devicePairingDone(Device *device, bool success);
2751
2752 private:
2753 QDBusConnection m_dbus;
2754- QDBusInterface m_bluezManager;
2755+ DBusObjectManagerInterface m_bluezManager;
2756+ BluezAgentManager1 m_bluezAgentManager;
2757
2758 void setProperties(const QMap<QString,QVariant> &properties);
2759 void updateProperty(const QString &key, const QVariant &value);
2760@@ -100,31 +105,34 @@
2761 void setDiscoverable(bool discoverable);
2762 void setPowered(bool powered);
2763
2764- QScopedPointer<QDBusInterface> m_bluezAdapter;
2765+ QScopedPointer<BluezAdapter1> m_bluezAdapter;
2766+ QScopedPointer<FreeDesktopProperties> m_bluezAdapterProperties;
2767+
2768 void clearAdapter();
2769- void setAdapterFromPath(const QString &objectPath);
2770+ void setAdapterFromPath(const QString &objectPath, const QVariantMap &properties);
2771
2772 QList<QSharedPointer<Device> > m_devices;
2773 void updateDevices();
2774 void addDevice(QSharedPointer<Device> &device);
2775- void addDevice(const QString &objectPath);
2776+ void addDevice(const QString &objectPath, const QVariantMap &properties);
2777 void removeRow(int i);
2778 int findRowFromAddress(const QString &address) const;
2779 void emitRowChanged(int row);
2780
2781+ void setDiscovering(bool value);
2782+ void setupAsDefaultAgent();
2783+
2784 private Q_SLOTS:
2785- void slotCreateFinished(QDBusPendingCallWatcher *call);
2786+ void slotInterfacesAdded(const QDBusObjectPath &objectPath, InterfaceList ifacesAndProps);
2787+ void slotInterfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces);
2788+ void slotAdapterPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
2789+ const QStringList &invalidatedProperties);
2790 void slotRemoveFinished(QDBusPendingCallWatcher *call);
2791 void slotPropertyChanged(const QString &key, const QDBusVariant &value);
2792 void slotTimeout();
2793 void slotEnableDiscoverable();
2794 void slotDeviceChanged();
2795- void slotDeviceCreated(const QDBusObjectPath &);
2796- void slotDeviceRemoved(const QDBusObjectPath &);
2797- void slotDeviceFound(const QString &, const QMap<QString,QVariant>&);
2798- void slotDeviceDisappeared(const QString&);
2799- void slotDefaultAdapterChanged(const QDBusObjectPath&);
2800- void slotAdapterRemoved(const QDBusObjectPath& path);
2801+ void slotDevicePairingDone(bool success);
2802 };
2803
2804 class DeviceFilter: public QSortFilterProxyModel
2805
2806=== added file 'plugins/bluetooth/freedesktop_objectmanager.cpp'
2807--- plugins/bluetooth/freedesktop_objectmanager.cpp 1970-01-01 00:00:00 +0000
2808+++ plugins/bluetooth/freedesktop_objectmanager.cpp 2015-11-20 08:48:08 +0000
2809@@ -0,0 +1,26 @@
2810+/*
2811+ * This file was generated by qdbusxml2cpp version 0.8
2812+ * Command line was: qdbusxml2cpp -p freedesktop_objectmanager -i bluez_helper.h -v -c DBusObjectManagerInterface org.freedesktop.DBus.ObjectManager.xml
2813+ *
2814+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
2815+ *
2816+ * This is an auto-generated file.
2817+ * This file may have been hand-edited. Look for HAND-EDIT comments
2818+ * before re-generating it.
2819+ */
2820+
2821+#include "freedesktop_objectmanager.h"
2822+
2823+/*
2824+ * Implementation of interface class DBusObjectManagerInterface
2825+ */
2826+
2827+DBusObjectManagerInterface::DBusObjectManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
2828+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
2829+{
2830+}
2831+
2832+DBusObjectManagerInterface::~DBusObjectManagerInterface()
2833+{
2834+}
2835+
2836
2837=== added file 'plugins/bluetooth/freedesktop_objectmanager.h'
2838--- plugins/bluetooth/freedesktop_objectmanager.h 1970-01-01 00:00:00 +0000
2839+++ plugins/bluetooth/freedesktop_objectmanager.h 2015-11-20 08:48:08 +0000
2840@@ -0,0 +1,58 @@
2841+/*
2842+ * This file was generated by qdbusxml2cpp version 0.8
2843+ * Command line was: qdbusxml2cpp -p freedesktop_objectmanager -i bluez_helper.h -v -c DBusObjectManagerInterface org.freedesktop.DBus.ObjectManager.xml
2844+ *
2845+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
2846+ *
2847+ * This is an auto-generated file.
2848+ * Do not edit! All changes made to it will be lost.
2849+ */
2850+
2851+#ifndef FREEDESKTOP_OBJECTMANAGER_H_1442473386
2852+#define FREEDESKTOP_OBJECTMANAGER_H_1442473386
2853+
2854+#include <QtCore/QObject>
2855+#include <QtCore/QByteArray>
2856+#include <QtCore/QList>
2857+#include <QtCore/QMap>
2858+#include <QtCore/QString>
2859+#include <QtCore/QStringList>
2860+#include <QtCore/QVariant>
2861+#include <QtDBus/QtDBus>
2862+#include "bluez_helper.h"
2863+
2864+/*
2865+ * Proxy class for interface org.freedesktop.DBus.ObjectManager
2866+ */
2867+class DBusObjectManagerInterface: public QDBusAbstractInterface
2868+{
2869+ Q_OBJECT
2870+public:
2871+ static inline const char *staticInterfaceName()
2872+ { return "org.freedesktop.DBus.ObjectManager"; }
2873+
2874+public:
2875+ DBusObjectManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
2876+
2877+ ~DBusObjectManagerInterface();
2878+
2879+public Q_SLOTS: // METHODS
2880+ inline QDBusPendingReply<ManagedObjectList> GetManagedObjects()
2881+ {
2882+ QList<QVariant> argumentList;
2883+ return asyncCallWithArgumentList(QStringLiteral("GetManagedObjects"), argumentList);
2884+ }
2885+
2886+Q_SIGNALS: // SIGNALS
2887+ void InterfacesAdded(const QDBusObjectPath &object_path, InterfaceList interfaces_and_properties);
2888+ void InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces);
2889+};
2890+
2891+namespace org {
2892+ namespace freedesktop {
2893+ namespace DBus {
2894+ typedef ::DBusObjectManagerInterface ObjectManager;
2895+ }
2896+ }
2897+}
2898+#endif
2899
2900=== added file 'plugins/bluetooth/freedesktop_properties.cpp'
2901--- plugins/bluetooth/freedesktop_properties.cpp 1970-01-01 00:00:00 +0000
2902+++ plugins/bluetooth/freedesktop_properties.cpp 2015-11-20 08:48:08 +0000
2903@@ -0,0 +1,26 @@
2904+/*
2905+ * This file was generated by qdbusxml2cpp version 0.8
2906+ * Command line was: qdbusxml2cpp -c FreeDesktopProperties -p freedesktop_properties -v org.freedesktop.DBus.Properties.xml
2907+ *
2908+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
2909+ *
2910+ * This is an auto-generated file.
2911+ * This file may have been hand-edited. Look for HAND-EDIT comments
2912+ * before re-generating it.
2913+ */
2914+
2915+#include "freedesktop_properties.h"
2916+
2917+/*
2918+ * Implementation of interface class FreeDesktopProperties
2919+ */
2920+
2921+FreeDesktopProperties::FreeDesktopProperties(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
2922+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
2923+{
2924+}
2925+
2926+FreeDesktopProperties::~FreeDesktopProperties()
2927+{
2928+}
2929+
2930
2931=== added file 'plugins/bluetooth/freedesktop_properties.h'
2932--- plugins/bluetooth/freedesktop_properties.h 1970-01-01 00:00:00 +0000
2933+++ plugins/bluetooth/freedesktop_properties.h 2015-11-20 08:48:08 +0000
2934@@ -0,0 +1,71 @@
2935+/*
2936+ * This file was generated by qdbusxml2cpp version 0.8
2937+ * Command line was: qdbusxml2cpp -c FreeDesktopProperties -p freedesktop_properties -v org.freedesktop.DBus.Properties.xml
2938+ *
2939+ * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
2940+ *
2941+ * This is an auto-generated file.
2942+ * Do not edit! All changes made to it will be lost.
2943+ */
2944+
2945+#ifndef FREEDESKTOP_PROPERTIES_H_1442473392
2946+#define FREEDESKTOP_PROPERTIES_H_1442473392
2947+
2948+#include <QtCore/QObject>
2949+#include <QtCore/QByteArray>
2950+#include <QtCore/QList>
2951+#include <QtCore/QMap>
2952+#include <QtCore/QString>
2953+#include <QtCore/QStringList>
2954+#include <QtCore/QVariant>
2955+#include <QtDBus/QtDBus>
2956+
2957+/*
2958+ * Proxy class for interface org.freedesktop.DBus.Properties
2959+ */
2960+class FreeDesktopProperties: public QDBusAbstractInterface
2961+{
2962+ Q_OBJECT
2963+public:
2964+ static inline const char *staticInterfaceName()
2965+ { return "org.freedesktop.DBus.Properties"; }
2966+
2967+public:
2968+ FreeDesktopProperties(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
2969+
2970+ ~FreeDesktopProperties();
2971+
2972+public Q_SLOTS: // METHODS
2973+ inline QDBusPendingReply<QDBusVariant> Get(const QString &interface, const QString &name)
2974+ {
2975+ QList<QVariant> argumentList;
2976+ argumentList << QVariant::fromValue(interface) << QVariant::fromValue(name);
2977+ return asyncCallWithArgumentList(QStringLiteral("Get"), argumentList);
2978+ }
2979+
2980+ inline QDBusPendingReply<QVariantMap> GetAll(const QString &interface)
2981+ {
2982+ QList<QVariant> argumentList;
2983+ argumentList << QVariant::fromValue(interface);
2984+ return asyncCallWithArgumentList(QStringLiteral("GetAll"), argumentList);
2985+ }
2986+
2987+ inline QDBusPendingReply<> Set(const QString &interface, const QString &name, const QDBusVariant &value)
2988+ {
2989+ QList<QVariant> argumentList;
2990+ argumentList << QVariant::fromValue(interface) << QVariant::fromValue(name) << QVariant::fromValue(value);
2991+ return asyncCallWithArgumentList(QStringLiteral("Set"), argumentList);
2992+ }
2993+
2994+Q_SIGNALS: // SIGNALS
2995+ void PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, const QStringList &invalidated_properties);
2996+};
2997+
2998+namespace org {
2999+ namespace freedesktop {
3000+ namespace DBus {
3001+ typedef ::FreeDesktopProperties Properties;
3002+ }
3003+ }
3004+}
3005+#endif
3006
3007=== added file 'plugins/bluetooth/org.bluez.Adapter1.xml'
3008--- plugins/bluetooth/org.bluez.Adapter1.xml 1970-01-01 00:00:00 +0000
3009+++ plugins/bluetooth/org.bluez.Adapter1.xml 2015-11-20 08:48:08 +0000
3010@@ -0,0 +1,11 @@
3011+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
3012+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3013+<node>
3014+ <interface name="org.bluez.Adapter1">
3015+ <method name="StartDiscovery"></method>
3016+ <method name="StopDiscovery"></method>
3017+ <method name="RemoveDevice">
3018+ <arg name="device" type="o" direction="in"/>
3019+ </method>
3020+ </interface>
3021+</node>
3022
3023=== added file 'plugins/bluetooth/org.bluez.Agent1.xml'
3024--- plugins/bluetooth/org.bluez.Agent1.xml 1970-01-01 00:00:00 +0000
3025+++ plugins/bluetooth/org.bluez.Agent1.xml 2015-11-20 08:48:08 +0000
3026@@ -0,0 +1,55 @@
3027+<?xml version="1.0" encoding="UTF-8" ?>
3028+
3029+<node name="/">
3030+ <interface name="org.bluez.Agent1">
3031+ <method name="RequestPinCode">
3032+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3033+ <arg type="o" name="device"/>
3034+ <arg type="s" name="pincode" direction="out"/>
3035+ </method>
3036+
3037+ <method name="DisplayPinCode">
3038+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3039+ <arg type="o" name="device"/>
3040+ <arg type="s" name="pincode"/>
3041+ </method>
3042+
3043+ <method name="RequestPasskey">
3044+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3045+ <arg type="o" name="device"/>
3046+ <arg type="u" name="passkey" direction="out"/>
3047+ </method>
3048+
3049+ <method name="DisplayPasskey">
3050+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3051+ <arg type="o" name="device"/>
3052+ <arg type="u" name="passkey"/>
3053+ <arg type="q" name="entered"/>
3054+ </method>
3055+
3056+ <method name="RequestConfirmation">
3057+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3058+ <arg type="o" name="device"/>
3059+ <arg type="u" name="passkey"/>
3060+ </method>
3061+
3062+ <method name="RequestAuthorization">
3063+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3064+ <arg type="o" name="device"/>
3065+ </method>
3066+
3067+ <method name="AuthorizeService">
3068+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3069+ <arg type="o" name="device"/>
3070+ <arg type="s" name="uuid"/>
3071+ </method>
3072+
3073+ <method name="Cancel">
3074+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3075+ </method>
3076+
3077+ <method name="Release">
3078+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
3079+ </method>
3080+ </interface>
3081+</node>
3082
3083=== added file 'plugins/bluetooth/org.bluez.AgentManager1.xml'
3084--- plugins/bluetooth/org.bluez.AgentManager1.xml 1970-01-01 00:00:00 +0000
3085+++ plugins/bluetooth/org.bluez.AgentManager1.xml 2015-11-20 08:48:08 +0000
3086@@ -0,0 +1,16 @@
3087+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
3088+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3089+<node>
3090+ <interface name="org.bluez.AgentManager1">
3091+ <method name="RegisterAgent">
3092+ <arg type="o" name="agent"/>
3093+ <arg type="s" name="capability"/>
3094+ </method>
3095+ <method name="UnregisterAgent">
3096+ <arg type="o" name="agent"/>
3097+ </method>
3098+ <method name="RequestDefaultAgent">
3099+ <arg type="o" name="agent"/>
3100+ </method>
3101+ </interface>
3102+</node>
3103
3104=== added file 'plugins/bluetooth/org.bluez.Device1.xml'
3105--- plugins/bluetooth/org.bluez.Device1.xml 1970-01-01 00:00:00 +0000
3106+++ plugins/bluetooth/org.bluez.Device1.xml 2015-11-20 08:48:08 +0000
3107@@ -0,0 +1,16 @@
3108+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
3109+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3110+<node>
3111+ <interface name="org.bluez.Device1">
3112+ <method name="Disconnect"></method>
3113+ <method name="Connect"></method>
3114+ <method name="ConnectProfile">
3115+ <arg name="UUID" type="s" direction="in"/>
3116+ </method>
3117+ <method name="DisconnectProfile">
3118+ <arg name="UUID" type="s" direction="in"/>
3119+ </method>
3120+ <method name="Pair"></method>
3121+ <method name="CancelPairing"></method>
3122+ </interface>
3123+</node>
3124
3125=== added file 'plugins/bluetooth/org.freedesktop.DBus.ObjectManager.xml'
3126--- plugins/bluetooth/org.freedesktop.DBus.ObjectManager.xml 1970-01-01 00:00:00 +0000
3127+++ plugins/bluetooth/org.freedesktop.DBus.ObjectManager.xml 2015-11-20 08:48:08 +0000
3128@@ -0,0 +1,19 @@
3129+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
3130+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3131+<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
3132+ <interface name="org.freedesktop.DBus.ObjectManager">
3133+ <method name="GetManagedObjects">
3134+ <arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
3135+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ManagedObjectList"/>
3136+ </method>
3137+ <signal name="InterfacesAdded">
3138+ <arg type="o" name="object_path"/>
3139+ <arg type="a{sa{sv}}" name="interfaces_and_properties"/>
3140+ <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="InterfaceList"/>
3141+ </signal>
3142+ <signal name="InterfacesRemoved">
3143+ <arg type="o" name="object_path"/>
3144+ <arg type="as" name="interfaces"/>
3145+ </signal>
3146+ </interface>
3147+</node>
3148
3149=== added file 'plugins/bluetooth/org.freedesktop.DBus.Properties.xml'
3150--- plugins/bluetooth/org.freedesktop.DBus.Properties.xml 1970-01-01 00:00:00 +0000
3151+++ plugins/bluetooth/org.freedesktop.DBus.Properties.xml 2015-11-20 08:48:08 +0000
3152@@ -0,0 +1,27 @@
3153+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
3154+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3155+<node>
3156+ <interface name="org.freedesktop.DBus.Properties">
3157+ <method name="Get">
3158+ <arg name="interface" type="s" direction="in"/>
3159+ <arg name="name" type="s" direction="in"/>
3160+ <arg name="value" type="v" direction="out"/>
3161+ </method>
3162+ <method name="Set">
3163+ <arg name="interface" type="s" direction="in"/>
3164+ <arg name="name" type="s" direction="in"/>
3165+ <arg name="value" type="v" direction="in"/>
3166+ </method>
3167+ <method name="GetAll">
3168+ <arg name="interface" type="s" direction="in"/>
3169+ <arg name="properties" type="a{sv}" direction="out"/>
3170+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
3171+ </method>
3172+ <signal name="PropertiesChanged">
3173+ <arg name="interface" type="s"/>
3174+ <arg name="changed_properties" type="a{sv}"/>
3175+ <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
3176+ <arg name="invalidated_properties" type="as"/>
3177+ </signal>
3178+ </interface>
3179+</node>
3180
3181=== modified file 'plugins/bluetooth/plugin.cpp'
3182--- plugins/bluetooth/plugin.cpp 2015-08-28 09:32:38 +0000
3183+++ plugins/bluetooth/plugin.cpp 2015-11-20 08:48:08 +0000
3184@@ -24,11 +24,17 @@
3185 #include <QtQml/QQmlContext>
3186 #include "bluetooth.h"
3187 #include "device.h"
3188+#include "bluez_helper.h"
3189
3190 void BackendPlugin::registerTypes(const char *uri)
3191 {
3192 Q_ASSERT(uri == QLatin1String("Ubuntu.SystemSettings.Bluetooth"));
3193
3194+ // Register additional QtDBus types we need
3195+ qDBusRegisterMetaType<InterfaceList>();
3196+ qDBusRegisterMetaType<ManagedObjectList>();
3197+
3198+ // .. now register our real QML types
3199 qmlRegisterType<Bluetooth>(uri, 1, 0, "UbuntuBluetoothPanel");
3200 qmlRegisterType<Device>(uri, 1, 0, "Device");
3201 qmlRegisterType<Device>(uri, 1, 0, "Agent");
3202
3203=== modified file 'tests/plugins/bluetooth/CMakeLists.txt'
3204--- tests/plugins/bluetooth/CMakeLists.txt 2014-07-29 20:45:24 +0000
3205+++ tests/plugins/bluetooth/CMakeLists.txt 2015-11-20 08:48:08 +0000
3206@@ -4,14 +4,23 @@
3207 include_directories(${QTDBUSTEST_INCLUDE_DIRS})
3208 add_definitions(-DTESTS)
3209
3210+set(PLUGIN_SOURCES
3211+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluetooth.cpp
3212+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/devicemodel.cpp
3213+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/device.cpp
3214+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agent.cpp
3215+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluez_agent1adaptor.cpp
3216+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluez_agentmanager1.cpp
3217+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluez_device1.cpp
3218+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluez_adapter1.cpp
3219+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/freedesktop_objectmanager.cpp
3220+ ${CMAKE_SOURCE_DIR}/plugins/bluetooth/freedesktop_properties.cpp
3221+)
3222+
3223 add_executable(tst-bluetooth
3224 tst_bluetooth.cpp
3225 fakebluez.cpp
3226- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluetooth.cpp
3227- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/devicemodel.cpp
3228- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/device.cpp
3229- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agent.cpp
3230- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agentadaptor.cpp
3231+ ${PLUGIN_SOURCES}
3232 )
3233
3234 target_link_libraries(tst-bluetooth
3235@@ -22,11 +31,7 @@
3236 add_executable(tst-bluetooth-devicemodel
3237 tst_devicemodel.cpp
3238 fakebluez.cpp
3239- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluetooth.cpp
3240- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/devicemodel.cpp
3241- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/device.cpp
3242- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agent.cpp
3243- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agentadaptor.cpp
3244+ ${PLUGIN_SOURCES}
3245 )
3246
3247 target_link_libraries(tst-bluetooth-devicemodel
3248@@ -35,13 +40,9 @@
3249 )
3250
3251 add_executable(tst-bluetooth-device
3252- tst_devicemodel.cpp
3253+ tst_device.cpp
3254 fakebluez.cpp
3255- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluetooth.cpp
3256- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/devicemodel.cpp
3257- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/device.cpp
3258- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agent.cpp
3259- ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agentadaptor.cpp
3260+ ${PLUGIN_SOURCES}
3261 )
3262
3263 target_link_libraries(tst-bluetooth-device
3264
3265=== modified file 'tests/plugins/bluetooth/fakebluez.cpp'
3266--- tests/plugins/bluetooth/fakebluez.cpp 2014-07-29 20:53:16 +0000
3267+++ tests/plugins/bluetooth/fakebluez.cpp 2015-11-20 08:48:08 +0000
3268@@ -29,7 +29,7 @@
3269 {
3270 DBusMock::registerMetaTypes();
3271
3272- m_dbusMock.registerTemplate(BLUEZ_SERVICE, "bluez4",
3273+ m_dbusMock.registerTemplate(BLUEZ_SERVICE, "bluez5",
3274 QDBusConnection::SystemBus);
3275 m_dbusTestRunner.startServices();
3276
3277@@ -75,13 +75,49 @@
3278 return reply.isValid() ? reply.value() : QString();
3279 }
3280
3281+void
3282+FakeBluez::pairDevice(const QString &address)
3283+{
3284+ QDBusReply<void> reply = m_bluezMock->call("PairDevice",
3285+ m_currentAdapter,
3286+ address);
3287+
3288+ if (!reply.isValid()) {
3289+ qWarning() << "Failed to pair mock device:" << reply.error().message();
3290+ }
3291+}
3292+
3293+void
3294+FakeBluez::connectDevice(const QString &address)
3295+{
3296+ QDBusReply<void> reply = m_bluezMock->call("ConnectDevice",
3297+ m_currentAdapter,
3298+ address);
3299+
3300+ if (!reply.isValid()) {
3301+ qWarning() << "Failed to connect mock device:" << reply.error().message();
3302+ }
3303+}
3304+
3305+void
3306+FakeBluez::disconnectDevice(const QString &address)
3307+{
3308+ QDBusReply<void> reply = m_bluezMock->call("DisconnectDevice",
3309+ m_currentAdapter,
3310+ address);
3311+
3312+ if (!reply.isValid()) {
3313+ qWarning() << "Failed to disconnect mock device:" << reply.error().message();
3314+ }
3315+}
3316+
3317 QVariant
3318 FakeBluez::getProperty(const QString &path,
3319 const QString &interface,
3320 const QString &property)
3321 {
3322 QDBusInterface iface(BLUEZ_SERVICE, path,
3323- "org.freedesktop.DBus.Properties",
3324+ FREEDESKTOP_PROPERTIES_IFACE,
3325 m_dbusTestRunner.systemConnection());
3326
3327 QDBusReply<QVariant> reply = iface.call("Get", interface, property);
3328@@ -103,10 +139,11 @@
3329 const QVariant &value)
3330 {
3331 QDBusInterface iface(BLUEZ_SERVICE, path,
3332- interface,
3333+ FREEDESKTOP_PROPERTIES_IFACE,
3334 m_dbusTestRunner.systemConnection());
3335
3336- QDBusReply<void> reply = iface.call("SetProperty",
3337+ QDBusReply<void> reply = iface.call("Set",
3338+ interface,
3339 property, value);
3340
3341 if (!reply.isValid()) {
3342
3343=== modified file 'tests/plugins/bluetooth/fakebluez.h'
3344--- tests/plugins/bluetooth/fakebluez.h 2014-07-29 20:53:16 +0000
3345+++ tests/plugins/bluetooth/fakebluez.h 2015-11-20 08:48:08 +0000
3346@@ -32,10 +32,10 @@
3347 #define BLUEZ_MAIN_OBJECT "/"
3348 #define BLUEZ_MOCK_IFACE "org.bluez.Mock"
3349
3350-#define BLUEZ_MANAGER_IFACE "org.bluez.Manager"
3351-#define BLUEZ_ADAPTER_IFACE "org.bluez.Adapter"
3352-#define BLUEZ_DEVICE_IFACE "org.bluez.Device"
3353-#define BLUEZ_AUDIO_IFACE "org.bluez.Audio"
3354+#define BLUEZ_ADAPTER_IFACE "org.bluez.Adapter1"
3355+#define BLUEZ_DEVICE_IFACE "org.bluez.Device1"
3356+
3357+#define FREEDESKTOP_PROPERTIES_IFACE "org.freedesktop.DBus.Properties"
3358
3359 using namespace QtDBusTest;
3360 using namespace QtDBusMock;
3361@@ -61,17 +61,20 @@
3362
3363 ~FakeBluez();
3364
3365- const QString currentAdapter() { return m_currentAdapter; }
3366+ const QString currentAdapterPath() { return QString("/org/bluez/%1").arg(m_currentAdapter); }
3367 const QList<QString> devices() { return m_devices; }
3368 const QDBusConnection & dbus() { return m_dbusTestRunner.systemConnection(); }
3369
3370 QString addAdapter(const QString &name, const QString &system_name);
3371 QString addDevice(const QString &name, const QString &address);
3372+ void pairDevice(const QString &address);
3373+ void connectDevice(const QString &address);
3374+ void disconnectDevice(const QString &address);
3375
3376 QVariant getProperty(const QString &path,
3377 const QString &interface,
3378 const QString &property);
3379-
3380+
3381 void setProperty(const QString &path,
3382 const QString &interface,
3383 const QString &property,
3384
3385=== modified file 'tests/plugins/bluetooth/tst_bluetooth.cpp'
3386--- tests/plugins/bluetooth/tst_bluetooth.cpp 2015-02-10 11:19:53 +0000
3387+++ tests/plugins/bluetooth/tst_bluetooth.cpp 2015-11-20 08:48:08 +0000
3388@@ -23,6 +23,7 @@
3389 #include "bluetooth.h"
3390 #include "device.h"
3391 #include "agent.h"
3392+#include "bluez_helper.h"
3393 #include "fakebluez.h"
3394
3395 using namespace Bluez;
3396@@ -36,6 +37,9 @@
3397 Bluetooth *m_bluetooth;
3398 QDBusConnection *m_dbus;
3399
3400+ void processEvents(unsigned int msecs = 500);
3401+ void setDiscovering(bool value);
3402+
3403 private Q_SLOTS:
3404 void init();
3405 void testGotAdapter();
3406@@ -48,16 +52,38 @@
3407
3408 };
3409
3410+void BluetoothTest::processEvents(unsigned int msecs)
3411+{
3412+ QTimer::singleShot(msecs, [=]() { QCoreApplication::instance()->exit(); });
3413+ QCoreApplication::instance()->exec();
3414+}
3415+
3416+void BluetoothTest::setDiscovering(bool value)
3417+{
3418+ m_bluezMock->setProperty(m_bluezMock->currentAdapterPath(),
3419+ BLUEZ_ADAPTER_IFACE,
3420+ "Discovering",
3421+ QVariant(value));
3422+}
3423+
3424 void BluetoothTest::init()
3425 {
3426+ qWarning() << "init test";
3427+
3428+ qDBusRegisterMetaType<InterfaceList>();
3429+ qDBusRegisterMetaType<ManagedObjectList>();
3430+
3431 m_bluezMock = new FakeBluez();
3432 m_bluezMock->addAdapter("new0", "bluetoothTest");
3433 m_dbus = new QDBusConnection(m_bluezMock->dbus());
3434 m_bluetooth = new Bluetooth(*m_dbus);
3435+
3436+ processEvents();
3437 }
3438
3439 void BluetoothTest::cleanup()
3440 {
3441+ qWarning() << "cleanup";
3442 delete m_bluezMock;
3443 delete m_bluetooth;
3444 }
3445@@ -67,6 +93,8 @@
3446 QString expected = "bluetoothTest";
3447 QString result;
3448
3449+ processEvents();
3450+
3451 result = m_bluetooth->adapterName();
3452
3453 QCOMPARE(result, expected);
3454@@ -74,70 +102,100 @@
3455
3456 void BluetoothTest::testStartDiscovery()
3457 {
3458- bool expected = true;
3459 QVariant result;
3460
3461- QSKIP("Fails due to a bug in bluez4 dbusmock template", SkipAll);
3462+ // This is what our test expects the adapter to have set
3463+ setDiscovering(false);
3464+ processEvents();
3465
3466- result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),
3467- "org.bluez.Adapter",
3468+ result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
3469+ BLUEZ_ADAPTER_IFACE,
3470 "Discovering");
3471 qWarning() << result;
3472- QCOMPARE(result.toBool(), !expected);
3473+ QCOMPARE(result.toBool(), false);
3474
3475 m_bluetooth->startDiscovery();
3476-
3477- result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),
3478- "org.bluez.Adapter",
3479+ setDiscovering(true);
3480+
3481+ processEvents();
3482+
3483+ result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
3484+ BLUEZ_ADAPTER_IFACE,
3485 "Discovering");
3486 qWarning() << result;
3487- QCOMPARE(result.toBool(), expected);
3488+ QCOMPARE(result.toBool(), true);
3489 }
3490
3491 void BluetoothTest::testStopDiscovery()
3492 {
3493- bool expected = false;
3494 QVariant result;
3495
3496- QSKIP("Fails due to a bug in bluez4 dbusmock template", SkipAll);
3497+ // This is what our test expects the adapter to have set
3498+ setDiscovering(true);
3499+ processEvents();
3500
3501- result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),
3502- "org.bluez.Adapter",
3503+ result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
3504+ BLUEZ_ADAPTER_IFACE,
3505 "Discovering");
3506- QCOMPARE(result.toBool(), !expected);
3507+ QCOMPARE(result.toBool(), true);
3508
3509 m_bluetooth->stopDiscovery();
3510-
3511- result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),
3512- "org.bluez.Adapter",
3513+ setDiscovering(false);
3514+
3515+ processEvents();
3516+
3517+ result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
3518+ BLUEZ_ADAPTER_IFACE,
3519 "Discovering");
3520- QCOMPARE(result.toBool(), expected);
3521+ QCOMPARE(result.toBool(), false);
3522 }
3523
3524+/*
3525+ * NOTE: The bluez5 mock template currently doesn't send PropertiesChanged
3526+ * events when StartDiscovery/StopDiscovery is called on the adapter interface.
3527+ * To accomondate this we're calling the org.freedesktop.DBus.Properties.Set
3528+ * method here manually to simulate a property change. However this means
3529+ * that other than doing a dumb call to StartDiscovery/StopDiscovery nothing
3530+ * else will happen when those methods are called of the Bluetooth class we're
3531+ * testing here.
3532+ *
3533+ * This affects the following tested methods:
3534+ * - Bluetooth::startDiscovering
3535+ * - Bluetooth::stopDiscovery
3536+ * - Bluetooth::toggleDiscovery
3537+ */
3538+
3539 void BluetoothTest::testToggleDiscovery()
3540 {
3541 QVariant result;
3542
3543- QSKIP("Fails due to a bug in bluez4 dbusmock template", SkipAll);
3544-
3545 m_bluetooth->stopDiscovery();
3546-
3547- result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),
3548- "org.bluez.Adapter",
3549+ setDiscovering(false);
3550+
3551+ processEvents();
3552+
3553+ result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
3554+ BLUEZ_ADAPTER_IFACE,
3555 "Discovering");
3556 QCOMPARE(result.toBool(), false);
3557
3558 m_bluetooth->toggleDiscovery();
3559-
3560- result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),
3561- "org.bluez.Adapter",
3562+ setDiscovering(true);
3563+
3564+ processEvents();
3565+
3566+ result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
3567+ BLUEZ_ADAPTER_IFACE,
3568 "Discovering");
3569 QCOMPARE(result.toBool(), true);
3570
3571 m_bluetooth->toggleDiscovery();
3572-
3573- result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),
3574- "org.bluez.Adapter",
3575+ setDiscovering(false);
3576+
3577+ processEvents();
3578+
3579+ result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
3580+ BLUEZ_ADAPTER_IFACE,
3581 "Discovering");
3582 QCOMPARE(result.toBool(), false);
3583 }
3584@@ -149,21 +207,34 @@
3585 QCOMPARE(Bluetooth::isSupportedType(Device::Type::Tablet), false);
3586 }
3587
3588+
3589 void BluetoothTest::testIsDiscovering()
3590 {
3591 m_bluetooth->stopDiscovery();
3592+ setDiscovering(false);
3593+
3594+ processEvents();
3595
3596 QCOMPARE(m_bluetooth->isDiscovering(), false);
3597
3598 m_bluetooth->startDiscovery();
3599+ setDiscovering(true);
3600+
3601+ processEvents();
3602
3603 QCOMPARE(m_bluetooth->isDiscovering(), true);
3604
3605 m_bluetooth->toggleDiscovery();
3606+ setDiscovering(false);
3607+
3608+ processEvents();
3609
3610 QCOMPARE(m_bluetooth->isDiscovering(), false);
3611
3612 m_bluetooth->toggleDiscovery();
3613+ setDiscovering(true);
3614+
3615+ processEvents();
3616
3617 QCOMPARE(m_bluetooth->isDiscovering(), true);
3618 }
3619
3620=== modified file 'tests/plugins/bluetooth/tst_device.cpp'
3621--- tests/plugins/bluetooth/tst_device.cpp 2015-08-25 16:41:10 +0000
3622+++ tests/plugins/bluetooth/tst_device.cpp 2015-11-20 08:48:08 +0000
3623@@ -36,7 +36,7 @@
3624 QDBusConnection *m_dbus;
3625
3626 private:
3627- void checkAudioState(const QString &expected);
3628+ void processEvents(unsigned int msecs = 500);
3629
3630 private Q_SLOTS:
3631 void init();
3632@@ -50,16 +50,29 @@
3633 void testGetStrength();
3634 void testGetPath();
3635 void testMakeTrusted();
3636-
3637+ void testConnect();
3638+ void testDisconnect();
3639+
3640 void cleanup();
3641
3642 };
3643
3644+void DeviceTest::processEvents(unsigned int msecs)
3645+{
3646+ QTimer::singleShot(msecs, [=]() { QCoreApplication::instance()->exit(); });
3647+ QCoreApplication::instance()->exec();
3648+}
3649+
3650 void DeviceTest::init()
3651 {
3652+ qDBusRegisterMetaType<InterfaceList>();
3653+ qDBusRegisterMetaType<ManagedObjectList>();
3654+
3655 m_bluezMock = new FakeBluez();
3656 m_bluezMock->addAdapter("new0", "bluetoothTest");
3657 m_bluezMock->addDevice("My Phone", "00:00:de:ad:be:ef");
3658+ // Only this will set the 'Class' and 'Icon' properties for the device ...
3659+ m_bluezMock->pairDevice("00:00:de:ad:be:ef");
3660 m_dbus = new QDBusConnection(m_bluezMock->dbus());
3661
3662 QList<QString> devices = m_bluezMock->devices();
3663@@ -67,6 +80,8 @@
3664 QFAIL("No devices in mock to be tested.");
3665
3666 m_device = new Device(devices.first(), *m_dbus);
3667+
3668+ processEvents();
3669 }
3670
3671 void DeviceTest::cleanup()
3672@@ -77,29 +92,37 @@
3673
3674 void DeviceTest::testGetName()
3675 {
3676- QCOMPARE(m_device->getName(), "My Phone");
3677-}
3678-
3679-void DeviceTest::testAddress()
3680-{
3681- QCOMPARE(m_device->getAddress(), "00:00:de:ad:be:ef");
3682-}
3683-
3684-void DeviceTest::testIconName()
3685-{
3686- QCOMPARE(m_device->getIconName(), "image://theme/audio-headset");
3687+ QCOMPARE(m_device->getName(), QString("My Phone"));
3688+}
3689+
3690+void DeviceTest::testGetAddress()
3691+{
3692+ QCOMPARE(m_device->getAddress(), QString("00:00:de:ad:be:ef"));
3693+}
3694+
3695+void DeviceTest::testGetIconName()
3696+{
3697+ QCOMPARE(m_device->getIconName(), QString("image://theme/phone-smartphone-symbolic"));
3698 }
3699
3700 void DeviceTest::testGetType()
3701 {
3702- QCOMPARE(m_device->getType(), Device::Type::Headset);
3703+ QCOMPARE(m_device->getType(), Device::Type::Smartphone);
3704 }
3705
3706 void DeviceTest::testIsPaired()
3707 {
3708+ QCOMPARE(m_device->isPaired(), true);
3709+
3710+ m_bluezMock->setProperty("/org/bluez/new0/dev_00_00_DE_AD_BE_EF", "org.bluez.Device1", "Paired", QVariant(false));
3711+
3712+ processEvents();
3713+
3714 QCOMPARE(m_device->isPaired(), false);
3715
3716- m_bluezMock->setProperty("org.bluez.Device", "Paired", QVariant(true));
3717+ m_bluezMock->setProperty("/org/bluez/new0/dev_00_00_DE_AD_BE_EF", "org.bluez.Device1", "Paired", QVariant(true));
3718+
3719+ processEvents();
3720
3721 QCOMPARE(m_device->isPaired(), true);
3722 }
3723@@ -108,26 +131,28 @@
3724 {
3725 QCOMPARE(m_device->isTrusted(), false);
3726
3727- m_bluezMock->setProperty("org.bluez.Device", "Trusted", QVariant(true));
3728+ m_bluezMock->setProperty("/org/bluez/new0/dev_00_00_DE_AD_BE_EF", "org.bluez.Device1", "Trusted", QVariant(true));
3729+
3730+ processEvents();
3731
3732 QCOMPARE(m_device->isTrusted(), true);
3733 }
3734
3735 void DeviceTest::testGetConnection()
3736 {
3737- QCOMPARE(m_device.getConnection(), Device::Connection::Disconnected);
3738+ QCOMPARE(m_device->getConnection(), Device::Connection::Disconnected);
3739 }
3740
3741 void DeviceTest::testGetStrength()
3742 {
3743- QCOMPARE(m_device.getStrength(), Device::Strength::Good);
3744+ QCOMPARE(m_device->getStrength(), Device::Strength::Fair);
3745 }
3746
3747 void DeviceTest::testGetPath()
3748 {
3749- QCOMPARE(m_device.getPath(),
3750- "/org/bluez/" + m_bluezMock->currentAdapter() + "/"
3751- + "dev_00_00_de_ad_be_ef");
3752+ QCOMPARE(m_device->getPath(),
3753+ m_bluezMock->currentAdapterPath() + "/"
3754+ + "dev_00_00_DE_AD_BE_EF");
3755 }
3756
3757 void DeviceTest::testMakeTrusted()
3758@@ -136,52 +161,40 @@
3759
3760 m_device->makeTrusted(true);
3761
3762+ processEvents();
3763+
3764 QCOMPARE(m_device->isTrusted(), true);
3765
3766 m_device->makeTrusted(false);
3767
3768+ processEvents();
3769+
3770 QCOMPARE(m_device->isTrusted(), false);
3771 }
3772
3773-void DeviceTest::checkAudioState(const QString &expected)
3774-{
3775- QVariant state = m_bluezMock->getProperty("org.bluez.Audio", "State");
3776-
3777- QVERIFY(state.type() == QMetaType::QString);
3778- QCOMPARE(state.toString(), expected);
3779-}
3780-
3781 void DeviceTest::testConnect()
3782 {
3783- testDiscoverServices();
3784-
3785- m_device->connect(Device::ConnectionMode::Audio);
3786-
3787- checkAudioState("connected");
3788+ m_device->connect();
3789+
3790+ m_bluezMock->connectDevice("00:00:de:ad:be:ef");
3791+
3792+ processEvents();
3793+
3794+ QCOMPARE(m_device->getConnection(), Device::Connected);
3795 }
3796
3797 void DeviceTest::testDisconnect()
3798 {
3799 testConnect();
3800
3801- m_device->disconnect(Device::ConnectionMode::Audio);
3802-
3803- checkAudioState("disconnected");
3804-}
3805-
3806-void DeviceTest::testConnectPending()
3807-{
3808- testIsPaired();
3809- testIsTrusted();
3810-
3811- m_device->addConnectAfterPairing(Device::ConnectionMode::Audio);
3812-
3813- checkAudioState("disconnected");
3814-
3815- m_device->connectPending();
3816-
3817- checkAudioState("connected");
3818-}
3819-
3820-QTEST_MAIN(DeviceTest);
3821+ m_device->disconnect();
3822+
3823+ m_bluezMock->disconnectDevice("00:00:de:ad:be:ef");
3824+
3825+ processEvents();
3826+
3827+ QCOMPARE(m_device->getConnection(), Device::Disconnected);
3828+}
3829+
3830+QTEST_MAIN(DeviceTest)
3831 #include "tst_device.moc"
3832
3833=== modified file 'tests/plugins/bluetooth/tst_devicemodel.cpp'
3834--- tests/plugins/bluetooth/tst_devicemodel.cpp 2014-08-20 12:50:09 +0000
3835+++ tests/plugins/bluetooth/tst_devicemodel.cpp 2015-11-20 08:48:08 +0000
3836@@ -35,6 +35,9 @@
3837 DeviceModel *m_devicemodel;
3838 QDBusConnection *m_dbus;
3839
3840+private:
3841+ void processEvents(unsigned int msecs = 500);
3842+
3843 private Q_SLOTS:
3844 void init();
3845 void testDeviceFoundOnStart();
3846@@ -45,15 +48,28 @@
3847
3848 };
3849
3850+void DeviceModelTest::processEvents(unsigned int msecs)
3851+{
3852+ QTimer::singleShot(msecs, [=]() { QCoreApplication::instance()->exit(); });
3853+ QCoreApplication::instance()->exec();
3854+}
3855+
3856 void DeviceModelTest::init()
3857 {
3858+ qDBusRegisterMetaType<InterfaceList>();
3859+ qDBusRegisterMetaType<ManagedObjectList>();
3860+
3861 m_bluezMock = new FakeBluez();
3862
3863 m_bluezMock->addAdapter("new0", "bluetoothTest");
3864 m_bluezMock->addDevice("My Phone", "00:00:de:ad:be:ef");
3865+ // Only this will set the 'Class' and 'Icon' properties for the device ...
3866+ m_bluezMock->pairDevice("00:00:de:ad:be:ef");
3867
3868 m_dbus = new QDBusConnection(m_bluezMock->dbus());
3869 m_devicemodel = new DeviceModel(*m_dbus);
3870+
3871+ processEvents();
3872 }
3873
3874 void DeviceModelTest::cleanup()
3875@@ -64,6 +80,9 @@
3876
3877 void DeviceModelTest::testDeviceFoundOnStart()
3878 {
3879+ // FIXME needs to take a bit more time especially on i386
3880+ processEvents();
3881+
3882 QCOMPARE(m_devicemodel->rowCount(), 1);
3883 }
3884

Subscribers

People subscribed via source and target branches