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

Proposed by Simon Fels
Status: Merged
Approved by: Sebastien Bacher
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) Approve
Jonas G. Drange (community) Approve
PS Jenkins bot continuous-integration Needs Fixing
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

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

1533. By Simon Fels

Correctly unregister our agent with BlueZ

1534. By Simon Fels

Fix list management according to current bluetooth power state

1535. By Simon Fels

Update Bluetooth implementation to use BlueZ 5 API

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1536. By Simon Fels

Disable bluetooth tests until they are migrated

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1537. By Simon Fels

Make tests working and cleanup code

1538. By Simon Fels

Restructure qdbus wrappers a bit

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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

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)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1540. By Simon Fels

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

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

1542. By Simon Fels

Update changelog

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1543. By Simon Fels

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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1544. By Simon Fels

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

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

1546. By Simon Fels

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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1547. By Simon Fels

Update connection state according to the device state

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1548. By Simon Fels

Install missing bluetooth qml files

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1549. By Simon Fels

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

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

Fix incorrect component name

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1552. By Simon Fels

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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1553. By Simon Fels

bluetooth: Ignore devices with type "other"

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1554. By Simon Fels

Fix bluetooth tests and enable device class tests again

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1555. By Simon Fels

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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1556. By Simon Fels

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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1557. By Simon Fels

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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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
Revision history for this message
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
Revision history for this message
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
Revision history for this message
Jonas G. Drange (jonas-drange) wrote :
Revision history for this message
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

Only enable forget button when device is paired

1559. By Simon Fels

[ 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

Correct changelog

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1561. By Simon Fels

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

1562. By Simon Fels

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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1563. By Simon Fels

[ 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

Use correct variable name to pass pincode to the created dialog

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1565. By Simon Fels

Check for dbus menu model property before accessing it

1566. By Simon Fels

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

Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1567. By Simon Fels

Detect bluetooth watch devices

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

LGTM! Great stuff. Thanks

review: Approve
Revision history for this message
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
Revision history for this message
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

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

1569. By Simon Fels

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

1570. By Simon Fels

[ 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
=== modified file 'debian/control'
--- debian/control 2015-10-29 15:48:06 +0000
+++ debian/control 2015-11-20 08:48:08 +0000
@@ -60,7 +60,7 @@
60 ${shlibs:Depends},60 ${shlibs:Depends},
61 accountsservice,61 accountsservice,
62 accountsservice-ubuntu-schemas (>= 0.0.3+14.10.20140829~),62 accountsservice-ubuntu-schemas (>= 0.0.3+14.10.20140829~),
63 bluez (>= 4.36),63 bluez (>= 5.23),
64 click | ubuntu-snappy-cli,64 click | ubuntu-snappy-cli,
65 dbus-property-service [amd64 armhf i386],65 dbus-property-service [amd64 armhf i386],
66 gsettings-desktop-schemas,66 gsettings-desktop-schemas,
6767
=== added file 'plugins/bluetooth/AuthorizationRequestDialog.qml'
--- plugins/bluetooth/AuthorizationRequestDialog.qml 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/AuthorizationRequestDialog.qml 2015-11-20 08:48:08 +0000
@@ -0,0 +1,53 @@
1/*
2 * This file is part of ubuntu-system-settings
3 *
4 * Copyright (C) 2013-2015 Canonical Ltd.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20import QtQuick 2.0
21import Ubuntu.Components 1.3
22import Ubuntu.Components.Popups 1.3
23
24Dialog {
25 id: root
26 title: i18n.tr("Bluetooth Pairing Authorization Request")
27
28 property string name: "Unknown"
29
30 signal accepted
31 signal declined
32
33 // TRANSLATORS: %1 is the name of the bluetooth device which requires authorization
34 text: i18n.tr("The device %1 wants to pair with this device. Do you want to allow this?").arg(root.name)
35
36 Row {
37 spacing: units.gu(1)
38 Button {
39 text: i18n.tr("Allow")
40 onClicked: {
41 root.allowed()
42 PopupUtils.close(root)
43 }
44 }
45 Button {
46 text: i18n.tr("Refuse")
47 onClicked: {
48 root.denied()
49 PopupUtils.close(root)
50 }
51 }
52 }
53}
054
=== modified file 'plugins/bluetooth/CMakeLists.txt'
--- plugins/bluetooth/CMakeLists.txt 2015-08-26 08:47:44 +0000
+++ plugins/bluetooth/CMakeLists.txt 2015-11-20 08:48:08 +0000
@@ -3,21 +3,34 @@
3set(QML_SOURCES3set(QML_SOURCES
4ProvidePinCodeDialog.qml4ProvidePinCodeDialog.qml
5ConfirmPasskeyDialog.qml5ConfirmPasskeyDialog.qml
6DisplayPinCodeDialog.qml
6DisplayPasskeyDialog.qml7DisplayPasskeyDialog.qml
7ProvidePasskeyDialog.qml8ProvidePasskeyDialog.qml
9AuthorizationRequestDialog.qml
8DevicePage.qml10DevicePage.qml
9PageComponent.qml11PageComponent.qml
10)12)
1113
12add_library(UbuntuBluetoothPanel MODULE14add_library(UbuntuBluetoothPanel MODULE
15 bluez_adapter1.cpp
16 bluez_agentmanager1.cpp
17 bluez_device1.cpp
18 bluez_agent1adaptor.cpp
19 freedesktop_properties.cpp
20 freedesktop_objectmanager.cpp
13 agent.cpp21 agent.cpp
14 agentadaptor.cpp
15 bluetooth.cpp22 bluetooth.cpp
16 device.cpp23 device.cpp
17 devicemodel.cpp24 devicemodel.cpp
25 bluez_adapter1.h
26 bluez_agentmanager1.h
27 bluez_device1.h
28 bluez_agent1adaptor.h
29 freedesktop_properties.h
30 freedesktop_objectmanager.h
18 plugin.cpp31 plugin.cpp
19 agent.h 32 bluez_helper.h
20 agentadaptor.h33 agent.h
21 bluetooth.h34 bluetooth.h
22 device.h35 device.h
23 devicemodel.h36 devicemodel.h
2437
=== modified file 'plugins/bluetooth/DevicePage.qml'
--- plugins/bluetooth/DevicePage.qml 2015-09-18 14:18:11 +0000
+++ plugins/bluetooth/DevicePage.qml 2015-11-20 08:48:08 +0000
@@ -58,6 +58,7 @@
58 case Device.Mouse: return i18n.tr("Mouse");58 case Device.Mouse: return i18n.tr("Mouse");
59 case Device.Printer: return i18n.tr("Printer");59 case Device.Printer: return i18n.tr("Printer");
60 case Device.Camera: return i18n.tr("Camera");60 case Device.Camera: return i18n.tr("Camera");
61 case Device.Watch: return i18n.tr("Watch");
61 default: return i18n.tr("Other");62 default: return i18n.tr("Other");
62 }63 }
63 }64 }
@@ -180,7 +181,7 @@
180 pageStack.pop();181 pageStack.pop();
181 }182 }
182 visible: backend.selectedDevice ? true : false183 visible: backend.selectedDevice ? true : false
183 enabled: backend.selectedDevice ? backend.isSupportedType(backend.selectedDevice.type) : false184 enabled: backend.selectedDevice && backend.powered ? (backend.isSupportedType(backend.selectedDevice.type) || backend.selectedDevice.connection != Device.Disconnected) : false
184 }185 }
185 }186 }
186 ListItem.SingleControl {187 ListItem.SingleControl {
@@ -192,7 +193,7 @@
192 backend.resetSelectedDevice();193 backend.resetSelectedDevice();
193 pageStack.pop();194 pageStack.pop();
194 }195 }
195 enabled: backend.selectedDevice && backend.selectedDevice.path.length > 0 ? true : false196 enabled: backend.selectedDevice && backend.selectedDevice.path.length > 0 && backend.selectedDevice.paired ? true : false
196 }197 }
197 }198 }
198 }199 }
199200
=== added file 'plugins/bluetooth/DisplayPinCodeDialog.qml'
--- plugins/bluetooth/DisplayPinCodeDialog.qml 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/DisplayPinCodeDialog.qml 2015-11-20 08:48:08 +0000
@@ -0,0 +1,54 @@
1/*
2 * This file is part of ubuntu-system-settings
3 *
4 * Copyright (C) 2013-2015 Canonical Ltd.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20import QtQuick 2.0
21import Ubuntu.Components 1.3
22import Ubuntu.Components.Popups 1.3
23
24Dialog {
25 id: root
26 title: i18n.tr("Bluetooth Pairing Request")
27
28 property string name: "Unknown"
29 property string pincode: ""
30
31 signal canceled
32
33 // TRANSLATORS: %1 is the name of the bluetooth device being paired
34 text: i18n.tr("Please enter the following PIN on %1 and press “Enter” on the keyboard:").arg(root.name)
35
36 Label {
37 text: root.pincode+"⏎"
38 fontSize: "x-large"
39 verticalAlignment: Text.AlignVCenter
40 horizontalAlignment: Text.AlignHCenter
41 }
42
43 Row {
44 spacing: units.gu(1)
45 Button {
46 text: i18n.tr("Cancel")
47 onClicked: {
48 root.canceled()
49 PopupUtils.close(root)
50 }
51 width: (parent.width - parent.spacing)
52 }
53 }
54}
055
=== modified file 'plugins/bluetooth/PageComponent.qml'
--- plugins/bluetooth/PageComponent.qml 2015-11-05 12:57:06 +0000
+++ plugins/bluetooth/PageComponent.qml 2015-11-20 08:48:08 +0000
@@ -34,8 +34,28 @@
34 objectName: "bluetoothPage"34 objectName: "bluetoothPage"
3535
36 property var dialogPopupId36 property var dialogPopupId
3737 property var currentDevice
38 UbuntuBluetoothPanel { id: backend }38
39 function finishDevicePairing() {
40 if (root.dialogPopupId)
41 PopupUtils.close(root.dialogPopupId)
42
43 root.dialogPopupId = null
44 root.currentDevice = null
45 }
46
47 UbuntuBluetoothPanel {
48 id: backend
49
50 onDevicePairingDone: {
51 console.log("Got pairing status notification for device " + device.address)
52
53 if (device != root.currentDevice)
54 return
55
56 finishDevicePairing()
57 }
58 }
3959
40 Timer {60 Timer {
41 id: discoverableTimer61 id: discoverableTimer
@@ -71,12 +91,23 @@
71 }91 }
7292
73 Component {93 Component {
94 id: displayPinCodeDialog
95 DisplayPinCodeDialog { }
96 }
97
98 Component {
74 id: displayPasskeyDialog99 id: displayPasskeyDialog
75 DisplayPasskeyDialog { }100 DisplayPasskeyDialog { }
76 }101 }
77102
103 Component {
104 id: authorizationRequestDialog
105 AuthorizationRequestDialog { }
106 }
107
78 Connections {108 Connections {
79 target: backend.agent109 target: backend.agent
110 onCancelNeeded: finishDevicePairing()
80 onPasskeyConfirmationNeeded: {111 onPasskeyConfirmationNeeded: {
81 var request_tag = tag112 var request_tag = tag
82 var popup = PopupUtils.open(confirmPasskeyDialog, root, {passkey: passkey, name: device.name})113 var popup = PopupUtils.open(confirmPasskeyDialog, root, {passkey: passkey, name: device.name})
@@ -95,23 +126,60 @@
95 popup.canceled.connect(function() {target.providePinCode(request_tag, false, "")})126 popup.canceled.connect(function() {target.providePinCode(request_tag, false, "")})
96 popup.provided.connect(function(pinCode) {target.providePinCode(request_tag, true, pinCode)})127 popup.provided.connect(function(pinCode) {target.providePinCode(request_tag, true, pinCode)})
97 }128 }
129 onDisplayPinCodeNeeded: {
130 if (!root.dialogPopupId)
131 {
132 root.currentDevice = device
133 root.dialogPopupId = PopupUtils.open(displayPinCodeDialog, root, {pincode: pincode, name: device.name})
134 root.dialogPopupId.canceled.connect(function() {
135 root.dialogPopupId = null
136 if (root.currentDevice) {
137 root.currentDevice.cancelPairing()
138 root.currentDevice = null
139 }
140 })
141 }
142 else
143 {
144 console.warn("Unhandled PIN code request for device " + device.name);
145 }
146 }
98 onDisplayPasskeyNeeded: {147 onDisplayPasskeyNeeded: {
99 if (!root.dialogPopupId)148 if (!root.dialogPopupId)
100 {149 {
101 var request_tag = tag150 root.currentDevice = device
102 root.dialogPopupId = PopupUtils.open(displayPasskeyDialog, root, {passkey: passkey, name: device.name,151 root.dialogPopupId = PopupUtils.open(displayPasskeyDialog, root, {passkey: passkey, name: device.name,
103 entered: entered})152 entered: entered})
104 root.dialogPopupId.canceled.connect(function() {root.dialogPopupId = null;153 root.dialogPopupId.canceled.connect(function() {
105 target.displayPasskeyCallback(request_tag)})154 root.dialogPopupId = null
155 if (root.currentDevice) {
156 root.currentDevice.cancelPairing()
157 root.currentDevice = null
158 }
159 })
106 }160 }
107 else161 else
108 {162 {
109 root.dialogPopupId.entered = entered163 root.dialogPopupId.entered = entered
110 }164 }
111 }165 }
112 onPairingDone: {166 onReleaseNeeded: {
113 if (root.dialogPopupId)167 finishDevicePairing()
114 PopupUtils.close(root.dialogPopupId)168 }
169 onAuthorizationRequested: {
170 if (!root.dialogPopupId)
171 {
172 var request_tag = tag
173 root.dialogPopupId = PopupUtils.open(authorizationRequestDialog, root, {name: device.name})
174 root.dialogPopupId.accepted.connect(function() {
175 root.dialogPopupId = null
176 target.authorizationRequestCallback(request_tag, true)
177 })
178 root.dialogPopupId.declined.connect(function() {
179 root.dialogPopupId = null
180 target.authorizationRequestCallback(request_tag, false)
181 })
182 }
115 }183 }
116 }184 }
117185
@@ -151,7 +219,7 @@
151 text: i18n.tr("Bluetooth")219 text: i18n.tr("Bluetooth")
152 control: Switch {220 control: Switch {
153 id: btSwitch221 id: btSwitch
154 property bool serverChecked: bluetoothActionGroup.enabled.state222 property bool serverChecked: bluetoothActionGroup.enabled.state != undefined ? bluetoothActionGroup.enabled.state : false
155 USC.ServerPropertySynchroniser {223 USC.ServerPropertySynchroniser {
156 userTarget: btSwitch224 userTarget: btSwitch
157 userProperty: "checked"225 userProperty: "checked"
@@ -210,7 +278,6 @@
210 }278 }
211 }279 }
212280
213 // Connnected Headset(s)
214 ListItem.Standard {281 ListItem.Standard {
215 id: connectedHeader282 id: connectedHeader
216 text: i18n.tr("Connected devices:")283 text: i18n.tr("Connected devices:")
@@ -225,7 +292,7 @@
225 left: parent.left292 left: parent.left
226 right: parent.right293 right: parent.right
227 }294 }
228 visible: bluetoothActionGroup.enabled && (connectedRepeater.count > 0)295 visible: (bluetoothActionGroup.enabled.state != undefined && bluetoothActionGroup.enabled.state) && (connectedRepeater.count > 0)
229 objectName: "connectedList"296 objectName: "connectedList"
230297
231 Repeater {298 Repeater {
@@ -248,12 +315,10 @@
248 }315 }
249 }316 }
250317
251 // Disconnnected Headset(s)
252
253 SettingsItemTitle {318 SettingsItemTitle {
254 id: disconnectedHeader319 id: disconnectedHeader
255 text: connectedList.visible ? i18n.tr("Connect another device:") : i18n.tr("Connect a device:")320 text: connectedList.visible ? i18n.tr("Connect another device:") : i18n.tr("Connect a device:")
256 enabled: bluetoothActionGroup.enabled321 enabled: bluetoothActionGroup.enabled.state != undefined ? bluetoothActionGroup.enabled.state : false
257 control: ActivityIndicator {322 control: ActivityIndicator {
258 visible: backend.powered && backend.discovering323 visible: backend.powered && backend.discovering
259 running: visible324 running: visible
@@ -266,7 +331,7 @@
266 left: parent.left331 left: parent.left
267 right: parent.right332 right: parent.right
268 }333 }
269 visible: bluetoothActionGroup.enabled && (disconnectedRepeater.count > 0)334 visible: (bluetoothActionGroup.enabled.state != undefined && bluetoothActionGroup.enabled.state) && (disconnectedRepeater.count > 0)
270 objectName: "disconnectedList"335 objectName: "disconnectedList"
271336
272 Repeater {337 Repeater {
@@ -287,11 +352,10 @@
287 ListItem.Standard {352 ListItem.Standard {
288 id: disconnectedNone353 id: disconnectedNone
289 text: i18n.tr("None detected")354 text: i18n.tr("None detected")
290 visible: !disconnectedList.visible355 visible: !disconnectedList.visible && disconnectedHeader.visible
291 enabled: false356 enabled: false
292 }357 }
293358
294 // Devices that connect automatically
295 SettingsItemTitle {359 SettingsItemTitle {
296 id: autoconnectHeader360 id: autoconnectHeader
297 text: i18n.tr("Connect automatically when detected:")361 text: i18n.tr("Connect automatically when detected:")
298362
=== modified file 'plugins/bluetooth/agent.cpp'
--- plugins/bluetooth/agent.cpp 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/agent.cpp 2015-11-20 08:48:08 +0000
@@ -53,7 +53,7 @@
53 */53 */
54void Agent::Release()54void Agent::Release()
55{55{
56 Q_EMIT(pairingDone());56 Q_EMIT(releaseNeeded());
57}57}
5858
59/***59/***
@@ -112,9 +112,24 @@
112 }112 }
113}113}
114114
115/***115QString Agent::RequestPinCode(const QDBusObjectPath &objectPath)
116****116{
117***/117 auto device = m_devices.getDeviceFromPath(objectPath.path());
118 if (device) {
119 const uint tag = m_tag++;
120
121 setDelayedReply(true);
122 assert(!m_delayedReplies.contains(tag));
123 m_delayedReplies[tag] = message();
124
125 Q_EMIT(pinCodeNeeded(tag, device.data()));
126
127 } else { // passkey requested for an unknown device..?!
128 reject(message(), __func__);
129 }
130
131 return 0;
132}
118133
119/**134/**
120 * This method gets called when the service daemon135 * This method gets called when the service daemon
@@ -168,35 +183,6 @@
168****183****
169***/184***/
170185
171/*
172 * This method gets called when the service daemon
173 * needs to get the passkey for an authentication.
174 *
175 * The return value should be a string of 1-16 characters
176 * length. The string can be alphanumeric.
177 *
178 * Possible errors: org.bluez.Error.Rejected
179 * org.bluez.Error.Canceled
180 */
181QString Agent::RequestPinCode(const QDBusObjectPath &objectPath)
182{
183 auto device = m_devices.getDeviceFromPath(objectPath.path());
184 if (device) {
185 const uint tag = m_tag++;
186
187 setDelayedReply(true);
188 assert(!m_delayedReplies.contains(tag));
189 m_delayedReplies[tag] = message();
190
191 Q_EMIT(pinCodeNeeded(tag, device.data()));
192
193 } else { // passkey requested for an unknown device..?!
194 reject(message(), __func__);
195 }
196
197 return "";
198}
199
200/**186/**
201 * Invoked by the user-facing code after it prompts the user for a PIN code187 * Invoked by the user-facing code after it prompts the user for a PIN code
202 * from an Agent::pinCodeNeeded() signal.188 * from an Agent::pinCodeNeeded() signal.
@@ -218,33 +204,23 @@
218 }204 }
219}205}
220206
221/** This method gets called when the service daemon207void Agent::DisplayPinCode(const QDBusObjectPath &objectPath, QString pincode)
222 * needs to display a passkey for an authentication.208{
223 * The entered parameter indicates the number of already209 auto device = m_devices.getDeviceFromPath(objectPath.path());
224 * typed keys on the remote side.210 if (device) {
225 * An empty reply should be returned. When the passkey211 Q_EMIT(displayPinCodeNeeded(device.data(), pincode));
226 * needs no longer to be displayed, the Cancel method212 } else {
227 * of the agent will be called.213 reject(message(), __func__);
228 * During the pairing process this method might be214 }
229 * called multiple times to update the entered value.215}
230 * Note that the passkey will always be a 6-digit number,
231 * so the display should be zero-padded at the start if
232 * the value contains less than 6 digits.
233 */
234216
235void Agent::DisplayPasskey(const QDBusObjectPath &objectPath, uint passkey, ushort entered)217void Agent::DisplayPasskey(const QDBusObjectPath &objectPath, uint passkey, ushort entered)
236{218{
237 auto device = m_devices.getDeviceFromPath(objectPath.path());219 auto device = m_devices.getDeviceFromPath(objectPath.path());
238 if (device) {220 if (device) {
239 const uint tag = m_tag++;
240
241 setDelayedReply(true);
242 assert(!m_delayedReplies.contains(tag));
243 m_delayedReplies[tag] = message();
244
245 QString passkeyStr = QString("%1").arg(passkey, 6, 10, QChar('0'));221 QString passkeyStr = QString("%1").arg(passkey, 6, 10, QChar('0'));
246 Q_EMIT(displayPasskeyNeeded(tag, device.data(), passkeyStr, entered));222 Q_EMIT(displayPasskeyNeeded(device.data(), passkeyStr, entered));
247 } else { // confirmation requested for an unknown device..?!223 } else {
248 reject(message(), __func__);224 reject(message(), __func__);
249 }225 }
250}226}
@@ -256,6 +232,53 @@
256void Agent::Cancel()232void Agent::Cancel()
257{233{
258 qWarning() << "Cancel callback called";234 qWarning() << "Cancel callback called";
235
236 Q_EMIT(cancelNeeded());
237}
238
239void Agent::RequestAuthorization(const QDBusObjectPath &path)
240{
241 qWarning() << "Authorization requested for device"
242 << path.path();
243
244 auto device = m_devices.getDeviceFromPath(path.path());
245 if (device) {
246 const uint tag = m_tag++;
247
248 setDelayedReply(true);
249 assert(!m_delayedReplies.contains(tag));
250 m_delayedReplies[tag] = message();
251
252 Q_EMIT(authorizationRequested(tag, device.data()));
253 }
254 else {
255 reject(message(), __func__);
256 }
257}
258
259void Agent::authorizationRequestCallback(uint tag, bool allow)
260{
261 if (m_delayedReplies.contains(tag)) {
262 QDBusMessage message = m_delayedReplies[tag];
263
264 if (allow)
265 m_connection.send(message.createReply());
266 else
267 reject(message, __func__);
268
269 m_delayedReplies.remove(tag);
270 }
271}
272
273void Agent::displayPinCodeCallback(uint tag)
274{
275 if (m_delayedReplies.contains(tag)) {
276 QDBusMessage message = m_delayedReplies[tag];
277
278 cancel(message, __func__);
279
280 m_delayedReplies.remove(tag);
281 }
259}282}
260283
261/**284/**
262285
=== modified file 'plugins/bluetooth/agent.h'
--- plugins/bluetooth/agent.h 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/agent.h 2015-11-20 08:48:08 +0000
@@ -41,22 +41,29 @@
41 Q_INVOKABLE void confirmPasskey(uint tag, bool confirmed);41 Q_INVOKABLE void confirmPasskey(uint tag, bool confirmed);
42 Q_INVOKABLE void providePasskey(uint tag, bool provided, uint passkey);42 Q_INVOKABLE void providePasskey(uint tag, bool provided, uint passkey);
43 Q_INVOKABLE void providePinCode(uint tag, bool provided, QString pinCode);43 Q_INVOKABLE void providePinCode(uint tag, bool provided, QString pinCode);
44 Q_INVOKABLE void displayPinCodeCallback(uint tag);
44 Q_INVOKABLE void displayPasskeyCallback(uint tag);45 Q_INVOKABLE void displayPasskeyCallback(uint tag);
46 Q_INVOKABLE void authorizationRequestCallback(uint tag, bool allow);
4547
46public Q_SLOTS: // received from the system's bluez service48public Q_SLOTS: // received from the system's bluez service
47 void Cancel();49 void Cancel();
50 void DisplayPinCode(const QDBusObjectPath &path, QString pincode);
48 void DisplayPasskey(const QDBusObjectPath &path, uint passkey, ushort entered);51 void DisplayPasskey(const QDBusObjectPath &path, uint passkey, ushort entered);
49 void Release();52 void Release();
50 void RequestConfirmation(const QDBusObjectPath &path, uint passkey);53 void RequestConfirmation(const QDBusObjectPath &path, uint passkey);
51 uint RequestPasskey(const QDBusObjectPath &path);54 uint RequestPasskey(const QDBusObjectPath &path);
52 QString RequestPinCode(const QDBusObjectPath &path);55 QString RequestPinCode(const QDBusObjectPath &path);
56 void RequestAuthorization(const QDBusObjectPath &path);
5357
54Q_SIGNALS:58Q_SIGNALS:
55 void pinCodeNeeded(int tag, Device* device);59 void pinCodeNeeded(int tag, Device* device);
56 void passkeyNeeded(int tag, Device* device);60 void passkeyNeeded(int tag, Device* device);
57 void passkeyConfirmationNeeded(int tag, Device* device, QString passkey);61 void passkeyConfirmationNeeded(int tag, Device* device, QString passkey);
58 void displayPasskeyNeeded(int tag, Device* device, QString passkey, ushort entered);62 void displayPinCodeNeeded(Device* device, QString pincode);
59 void pairingDone();63 void displayPasskeyNeeded(Device* device, QString passkey, ushort entered);
64 void releaseNeeded();
65 void cancelNeeded();
66 void authorizationRequested(int tag, Device* device);
6067
61private:68private:
62 Q_DISABLE_COPY(Agent)69 Q_DISABLE_COPY(Agent)
6370
=== removed file 'plugins/bluetooth/agent.xml'
--- plugins/bluetooth/agent.xml 2015-02-04 10:48:47 +0000
+++ plugins/bluetooth/agent.xml 1970-01-01 00:00:00 +0000
@@ -1,38 +0,0 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<node name="/">
4 <interface name="org.bluez.Agent">
5 <method name="RequestPinCode">
6 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
7 <arg type="o" name="device"/>
8 <arg type="s" name="pincode" direction="out"/>
9 </method>
10
11 <method name="RequestPasskey">
12 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
13 <arg type="o" name="device"/>
14 <arg type="u" name="passkey" direction="out"/>
15 </method>
16
17 <method name="DisplayPasskey">
18 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
19 <arg type="o" name="device"/>
20 <arg type="u" name="passkey"/>
21 <arg type="q" name="entered"/>
22 </method>
23
24 <method name="RequestConfirmation">
25 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
26 <arg type="o" name="device"/>
27 <arg type="u" name="passkey"/>
28 </method>
29
30 <method name="Cancel">
31 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
32 </method>
33
34 <method name="Release">
35 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
36 </method>
37 </interface>
38</node>
390
=== removed file 'plugins/bluetooth/agentadaptor.cpp'
--- plugins/bluetooth/agentadaptor.cpp 2015-02-04 10:48:47 +0000
+++ plugins/bluetooth/agentadaptor.cpp 1970-01-01 00:00:00 +0000
@@ -1,75 +0,0 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp agent.xml -a agentadaptor
4 *
5 * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * Do not edit! All changes made to it will be lost.
9 */
10
11#include "agentadaptor.h"
12#include <QtCore/QMetaObject>
13#include <QtCore/QByteArray>
14#include <QtCore/QList>
15#include <QtCore/QMap>
16#include <QtCore/QString>
17#include <QtCore/QStringList>
18#include <QtCore/QVariant>
19
20/*
21 * Implementation of adaptor class AgentAdaptor
22 */
23
24AgentAdaptor::AgentAdaptor(QObject *parent)
25 : QDBusAbstractAdaptor(parent)
26{
27 // constructor
28 setAutoRelaySignals(true);
29}
30
31AgentAdaptor::~AgentAdaptor()
32{
33 // destructor
34}
35
36void AgentAdaptor::Cancel()
37{
38 // handle method call org.bluez.Agent.Cancel
39 QMetaObject::invokeMethod(parent(), "Cancel");
40}
41
42void AgentAdaptor::DisplayPasskey(const QDBusObjectPath &device, uint passkey, ushort entered)
43{
44 // handle method call org.bluez.Agent.DisplayPasskey
45 QMetaObject::invokeMethod(parent(), "DisplayPasskey", Q_ARG(QDBusObjectPath, device), Q_ARG(uint, passkey), Q_ARG(ushort, entered));
46}
47
48void AgentAdaptor::Release()
49{
50 // handle method call org.bluez.Agent.Release
51 QMetaObject::invokeMethod(parent(), "Release");
52}
53
54void AgentAdaptor::RequestConfirmation(const QDBusObjectPath &device, uint passkey)
55{
56 // handle method call org.bluez.Agent.RequestConfirmation
57 QMetaObject::invokeMethod(parent(), "RequestConfirmation", Q_ARG(QDBusObjectPath, device), Q_ARG(uint, passkey));
58}
59
60uint AgentAdaptor::RequestPasskey(const QDBusObjectPath &device)
61{
62 // handle method call org.bluez.Agent.RequestPasskey
63 uint passkey;
64 QMetaObject::invokeMethod(parent(), "RequestPasskey", Q_RETURN_ARG(uint, passkey), Q_ARG(QDBusObjectPath, device));
65 return passkey;
66}
67
68QString AgentAdaptor::RequestPinCode(const QDBusObjectPath &device)
69{
70 // handle method call org.bluez.Agent.RequestPinCode
71 QString pincode;
72 QMetaObject::invokeMethod(parent(), "RequestPinCode", Q_RETURN_ARG(QString, pincode), Q_ARG(QDBusObjectPath, device));
73 return pincode;
74}
75
760
=== removed file 'plugins/bluetooth/agentadaptor.h'
--- plugins/bluetooth/agentadaptor.h 2015-02-04 10:48:47 +0000
+++ plugins/bluetooth/agentadaptor.h 1970-01-01 00:00:00 +0000
@@ -1,79 +0,0 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp agent.xml -a agentadaptor
4 *
5 * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * This file may have been hand-edited. Look for HAND-EDIT comments
9 * before re-generating it.
10 */
11
12#ifndef AGENTADAPTOR_H_1423046874
13#define AGENTADAPTOR_H_1423046874
14
15#include <QtCore/QObject>
16#include <QtDBus/QtDBus>
17QT_BEGIN_NAMESPACE
18class QByteArray;
19template<class T> class QList;
20template<class Key, class Value> class QMap;
21class QString;
22class QStringList;
23class QVariant;
24QT_END_NAMESPACE
25
26/*
27 * Adaptor class for interface org.bluez.Agent
28 */
29class AgentAdaptor: public QDBusAbstractAdaptor
30{
31 Q_OBJECT
32 Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent")
33 Q_CLASSINFO("D-Bus Introspection", ""
34" <interface name=\"org.bluez.Agent\">\n"
35" <method name=\"RequestPinCode\">\n"
36" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
37" <arg type=\"o\" name=\"device\"/>\n"
38" <arg direction=\"out\" type=\"s\" name=\"pincode\"/>\n"
39" </method>\n"
40" <method name=\"RequestPasskey\">\n"
41" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
42" <arg type=\"o\" name=\"device\"/>\n"
43" <arg direction=\"out\" type=\"u\" name=\"passkey\"/>\n"
44" </method>\n"
45" <method name=\"DisplayPasskey\">\n"
46" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
47" <arg type=\"o\" name=\"device\"/>\n"
48" <arg type=\"u\" name=\"passkey\"/>\n"
49" <arg type=\"q\" name=\"entered\"/>\n"
50" </method>\n"
51" <method name=\"RequestConfirmation\">\n"
52" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
53" <arg type=\"o\" name=\"device\"/>\n"
54" <arg type=\"u\" name=\"passkey\"/>\n"
55" </method>\n"
56" <method name=\"Cancel\">\n"
57" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
58" </method>\n"
59" <method name=\"Release\">\n"
60" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
61" </method>\n"
62" </interface>\n"
63 "")
64public:
65 AgentAdaptor(QObject *parent);
66 virtual ~AgentAdaptor();
67
68public: // PROPERTIES
69public Q_SLOTS: // METHODS
70 void Cancel();
71 void DisplayPasskey(const QDBusObjectPath &device, uint passkey, ushort entered);
72 void Release();
73 void RequestConfirmation(const QDBusObjectPath &device, uint passkey);
74 uint RequestPasskey(const QDBusObjectPath &device);
75 QString RequestPinCode(const QDBusObjectPath &device);
76Q_SIGNALS: // SIGNALS
77};
78
79#endif
800
=== modified file 'plugins/bluetooth/bluetooth.cpp'
--- plugins/bluetooth/bluetooth.cpp 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/bluetooth.cpp 2015-11-20 08:48:08 +0000
@@ -23,7 +23,6 @@
23#include <QQmlEngine>23#include <QQmlEngine>
2424
25#include "agent.h"25#include "agent.h"
26#include "agentadaptor.h"
27#include "dbus-shared.h"26#include "dbus-shared.h"
2827
29Bluetooth::Bluetooth(QObject *parent):28Bluetooth::Bluetooth(QObject *parent):
@@ -38,7 +37,7 @@
38 m_agent(m_dbus, m_devices)37 m_agent(m_dbus, m_devices)
39{38{
40 // export our Agent to handle pairing requests39 // export our Agent to handle pairing requests
41 new AgentAdaptor(&m_agent);40 new BluezAgent1Adaptor(&m_agent);
42 if(!m_dbus.registerObject(DBUS_ADAPTER_AGENT_PATH, &m_agent))41 if(!m_dbus.registerObject(DBUS_ADAPTER_AGENT_PATH, &m_agent))
43 qCritical() << "Couldn't register agent at" << DBUS_ADAPTER_AGENT_PATH;42 qCritical() << "Couldn't register agent at" << DBUS_ADAPTER_AGENT_PATH;
4443
@@ -63,6 +62,9 @@
6362
64 QObject::connect(&m_devices, SIGNAL(discoverableChanged(bool)),63 QObject::connect(&m_devices, SIGNAL(discoverableChanged(bool)),
65 this, SIGNAL(discoverableChanged(bool)));64 this, SIGNAL(discoverableChanged(bool)));
65
66 QObject::connect(&m_devices, SIGNAL(devicePairingDone(Device*,bool)),
67 this, SIGNAL(devicePairingDone(Device*,bool)));
66}68}
6769
68void Bluetooth::setSelectedDevice(const QString &address)70void Bluetooth::setSelectedDevice(const QString &address)
@@ -110,6 +112,7 @@
110 case Device::Type::OtherAudio:112 case Device::Type::OtherAudio:
111 case Device::Type::Keyboard:113 case Device::Type::Keyboard:
112 case Device::Type::Mouse:114 case Device::Type::Mouse:
115 case Device::Type::Watch:
113 return true;116 return true;
114117
115 default:118 default:
@@ -167,73 +170,38 @@
167170
168void Bluetooth::disconnectDevice()171void Bluetooth::disconnectDevice()
169{172{
170 if (m_selectedDevice) {173 if (!m_selectedDevice)
171 auto type = m_selectedDevice->getType();174 return;
172 switch ((Device::Type)type) {175
173 case Device::Type::Headset:176 m_selectedDevice->disconnect();
174 case Device::Type::Headphones:
175 case Device::Type::OtherAudio:
176 case Device::Type::Speakers:
177 case Device::Type::Carkit:
178 m_selectedDevice->disconnect(Device::ConnectionMode::Audio);
179 break;
180 case Device::Type::Keyboard:
181 case Device::Type::Mouse:
182 m_selectedDevice->disconnect(Device::ConnectionMode::Input);
183 break;
184 default:
185 qWarning() << "Nothing to disconnect: Unsupported device type.";
186 break;
187 }
188 } else {
189 qWarning() << "No selected device to disconnect";
190 }
191}177}
192178
193void Bluetooth::connectDevice(const QString &address)179void Bluetooth::connectDevice(const QString &address)
194{180{
195 Device::ConnectionMode connMode;
196 auto device = m_devices.getDeviceFromAddress(address);181 auto device = m_devices.getDeviceFromAddress(address);
197 Device::Type type;
198182
199 if (!device) {183 if (!device) {
200 qWarning() << "No device to connect.";184 qWarning() << "No device to connect.";
201 return;185 return;
202 }186 }
203187
204 type = device->getType();188 if (!device->isPaired()) {
205 switch (type) {189 device->setConnectAfterPairing(true);
206 case Device::Type::Headset:190 device->pair();
207 case Device::Type::Headphones:
208 case Device::Type::OtherAudio:
209 case Device::Type::Speakers:
210 case Device::Type::Carkit:
211 connMode = Device::ConnectionMode::Audio;
212 break;
213 case Device::Type::Keyboard:
214 case Device::Type::Mouse:
215 connMode = Device::ConnectionMode::Input;
216 break;
217 default:
218 qWarning() << "Nothing to connect: Unsupported device type.";
219 return;
220 }191 }
221192 else {
222 if (device->isTrusted()) {193 device->connect();
223 device->connect(connMode);
224 } else {
225 m_devices.addConnectAfterPairing(address, connMode);
226 m_devices.createDevice(address, &m_agent);
227 }194 }
228}195}
229196
230void Bluetooth::removeDevice()197void Bluetooth::removeDevice()
231{198{
232 if (m_selectedDevice) {199 if (!m_selectedDevice) {
233 QString path = m_selectedDevice->getPath();
234 m_devices.removeDevice(path);
235 } else {
236 qWarning() << "No selected device to remove.";200 qWarning() << "No selected device to remove.";
201 return;
237 }202 }
203
204 QString path = m_selectedDevice->getPath();
205 m_devices.removeDevice(path);
238}206}
239207
240208
=== modified file 'plugins/bluetooth/bluetooth.h'
--- plugins/bluetooth/bluetooth.h 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/bluetooth.h 2015-11-20 08:48:08 +0000
@@ -24,9 +24,10 @@
24#include <QObject>24#include <QObject>
2525
26#include "agent.h"26#include "agent.h"
27#include "agentadaptor.h"
28#include "devicemodel.h"27#include "devicemodel.h"
2928
29#include "bluez_agent1adaptor.h"
30
30class Bluetooth : public QObject31class Bluetooth : public QObject
31{32{
32 Q_OBJECT33 Q_OBJECT
@@ -68,6 +69,7 @@
68 void poweredChanged(bool powered);69 void poweredChanged(bool powered);
69 void discoveringChanged(bool isActive);70 void discoveringChanged(bool isActive);
70 void discoverableChanged(bool isActive);71 void discoverableChanged(bool isActive);
72 void devicePairingDone(Device *device, bool success);
7173
72public:74public:
73 explicit Bluetooth(QObject *parent = nullptr);75 explicit Bluetooth(QObject *parent = nullptr);
7476
=== added file 'plugins/bluetooth/bluez_adapter1.cpp'
--- plugins/bluetooth/bluez_adapter1.cpp 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_adapter1.cpp 2015-11-20 08:48:08 +0000
@@ -0,0 +1,26 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -c BluezAdapter1 -p bluez_adapter1 -v org.bluez.Adapter1.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * This file may have been hand-edited. Look for HAND-EDIT comments
9 * before re-generating it.
10 */
11
12#include "bluez_adapter1.h"
13
14/*
15 * Implementation of interface class BluezAdapter1
16 */
17
18BluezAdapter1::BluezAdapter1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
19 : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
20{
21}
22
23BluezAdapter1::~BluezAdapter1()
24{
25}
26
027
=== added file 'plugins/bluetooth/bluez_adapter1.h'
--- plugins/bluetooth/bluez_adapter1.h 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_adapter1.h 2015-11-20 08:48:08 +0000
@@ -0,0 +1,66 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -c BluezAdapter1 -p bluez_adapter1 -v org.bluez.Adapter1.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * Do not edit! All changes made to it will be lost.
9 */
10
11#ifndef BLUEZ_ADAPTER1_H_1442480417
12#define BLUEZ_ADAPTER1_H_1442480417
13
14#include <QtCore/QObject>
15#include <QtCore/QByteArray>
16#include <QtCore/QList>
17#include <QtCore/QMap>
18#include <QtCore/QString>
19#include <QtCore/QStringList>
20#include <QtCore/QVariant>
21#include <QtDBus/QtDBus>
22
23/*
24 * Proxy class for interface org.bluez.Adapter1
25 */
26class BluezAdapter1: public QDBusAbstractInterface
27{
28 Q_OBJECT
29public:
30 static inline const char *staticInterfaceName()
31 { return "org.bluez.Adapter1"; }
32
33public:
34 BluezAdapter1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
35
36 ~BluezAdapter1();
37
38public Q_SLOTS: // METHODS
39 inline QDBusPendingReply<> RemoveDevice(const QDBusObjectPath &device)
40 {
41 QList<QVariant> argumentList;
42 argumentList << QVariant::fromValue(device);
43 return asyncCallWithArgumentList(QStringLiteral("RemoveDevice"), argumentList);
44 }
45
46 inline QDBusPendingReply<> StartDiscovery()
47 {
48 QList<QVariant> argumentList;
49 return asyncCallWithArgumentList(QStringLiteral("StartDiscovery"), argumentList);
50 }
51
52 inline QDBusPendingReply<> StopDiscovery()
53 {
54 QList<QVariant> argumentList;
55 return asyncCallWithArgumentList(QStringLiteral("StopDiscovery"), argumentList);
56 }
57
58Q_SIGNALS: // SIGNALS
59};
60
61namespace org {
62 namespace bluez {
63 typedef ::BluezAdapter1 Adapter1;
64 }
65}
66#endif
067
=== added file 'plugins/bluetooth/bluez_agent1adaptor.cpp'
--- plugins/bluetooth/bluez_agent1adaptor.cpp 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_agent1adaptor.cpp 2015-11-20 08:48:08 +0000
@@ -0,0 +1,93 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -a bluez_agent1adaptor -c BluezAgent1Adaptor org.bluez.Agent1.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * Do not edit! All changes made to it will be lost.
9 */
10
11#include "bluez_agent1adaptor.h"
12#include <QtCore/QMetaObject>
13#include <QtCore/QByteArray>
14#include <QtCore/QList>
15#include <QtCore/QMap>
16#include <QtCore/QString>
17#include <QtCore/QStringList>
18#include <QtCore/QVariant>
19
20/*
21 * Implementation of adaptor class BluezAgent1Adaptor
22 */
23
24BluezAgent1Adaptor::BluezAgent1Adaptor(QObject *parent)
25 : QDBusAbstractAdaptor(parent)
26{
27 // constructor
28 setAutoRelaySignals(true);
29}
30
31BluezAgent1Adaptor::~BluezAgent1Adaptor()
32{
33 // destructor
34}
35
36void BluezAgent1Adaptor::AuthorizeService(const QDBusObjectPath &device, const QString &uuid)
37{
38 // handle method call org.bluez.Agent1.AuthorizeService
39 QMetaObject::invokeMethod(parent(), "AuthorizeService", Q_ARG(QDBusObjectPath, device), Q_ARG(QString, uuid));
40}
41
42void BluezAgent1Adaptor::Cancel()
43{
44 // handle method call org.bluez.Agent1.Cancel
45 QMetaObject::invokeMethod(parent(), "Cancel");
46}
47
48void BluezAgent1Adaptor::DisplayPasskey(const QDBusObjectPath &device, uint passkey, ushort entered)
49{
50 // handle method call org.bluez.Agent1.DisplayPasskey
51 QMetaObject::invokeMethod(parent(), "DisplayPasskey", Q_ARG(QDBusObjectPath, device), Q_ARG(uint, passkey), Q_ARG(ushort, entered));
52}
53
54void BluezAgent1Adaptor::DisplayPinCode(const QDBusObjectPath &device, const QString &pincode)
55{
56 // handle method call org.bluez.Agent1.DisplayPinCode
57 QMetaObject::invokeMethod(parent(), "DisplayPinCode", Q_ARG(QDBusObjectPath, device), Q_ARG(QString, pincode));
58}
59
60void BluezAgent1Adaptor::Release()
61{
62 // handle method call org.bluez.Agent1.Release
63 QMetaObject::invokeMethod(parent(), "Release");
64}
65
66void BluezAgent1Adaptor::RequestAuthorization(const QDBusObjectPath &device)
67{
68 // handle method call org.bluez.Agent1.RequestAuthorization
69 QMetaObject::invokeMethod(parent(), "RequestAuthorization", Q_ARG(QDBusObjectPath, device));
70}
71
72void BluezAgent1Adaptor::RequestConfirmation(const QDBusObjectPath &device, uint passkey)
73{
74 // handle method call org.bluez.Agent1.RequestConfirmation
75 QMetaObject::invokeMethod(parent(), "RequestConfirmation", Q_ARG(QDBusObjectPath, device), Q_ARG(uint, passkey));
76}
77
78uint BluezAgent1Adaptor::RequestPasskey(const QDBusObjectPath &device)
79{
80 // handle method call org.bluez.Agent1.RequestPasskey
81 uint passkey;
82 QMetaObject::invokeMethod(parent(), "RequestPasskey", Q_RETURN_ARG(uint, passkey), Q_ARG(QDBusObjectPath, device));
83 return passkey;
84}
85
86QString BluezAgent1Adaptor::RequestPinCode(const QDBusObjectPath &device)
87{
88 // handle method call org.bluez.Agent1.RequestPinCode
89 QString pincode;
90 QMetaObject::invokeMethod(parent(), "RequestPinCode", Q_RETURN_ARG(QString, pincode), Q_ARG(QDBusObjectPath, device));
91 return pincode;
92}
93
094
=== added file 'plugins/bluetooth/bluez_agent1adaptor.h'
--- plugins/bluetooth/bluez_agent1adaptor.h 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_agent1adaptor.h 2015-11-20 08:48:08 +0000
@@ -0,0 +1,96 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -a bluez_agent1adaptor -c BluezAgent1Adaptor org.bluez.Agent1.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * This file may have been hand-edited. Look for HAND-EDIT comments
9 * before re-generating it.
10 */
11
12#ifndef BLUEZ_AGENT1ADAPTOR_H_1442560744
13#define BLUEZ_AGENT1ADAPTOR_H_1442560744
14
15#include <QtCore/QObject>
16#include <QtDBus/QtDBus>
17QT_BEGIN_NAMESPACE
18class QByteArray;
19template<class T> class QList;
20template<class Key, class Value> class QMap;
21class QString;
22class QStringList;
23class QVariant;
24QT_END_NAMESPACE
25
26/*
27 * Adaptor class for interface org.bluez.Agent1
28 */
29class BluezAgent1Adaptor: public QDBusAbstractAdaptor
30{
31 Q_OBJECT
32 Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent1")
33 Q_CLASSINFO("D-Bus Introspection", ""
34" <interface name=\"org.bluez.Agent1\">\n"
35" <method name=\"RequestPinCode\">\n"
36" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
37" <arg type=\"o\" name=\"device\"/>\n"
38" <arg direction=\"out\" type=\"s\" name=\"pincode\"/>\n"
39" </method>\n"
40" <method name=\"DisplayPinCode\">\n"
41" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
42" <arg type=\"o\" name=\"device\"/>\n"
43" <arg type=\"s\" name=\"pincode\"/>\n"
44" </method>\n"
45" <method name=\"RequestPasskey\">\n"
46" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
47" <arg type=\"o\" name=\"device\"/>\n"
48" <arg direction=\"out\" type=\"u\" name=\"passkey\"/>\n"
49" </method>\n"
50" <method name=\"DisplayPasskey\">\n"
51" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
52" <arg type=\"o\" name=\"device\"/>\n"
53" <arg type=\"u\" name=\"passkey\"/>\n"
54" <arg type=\"q\" name=\"entered\"/>\n"
55" </method>\n"
56" <method name=\"RequestConfirmation\">\n"
57" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
58" <arg type=\"o\" name=\"device\"/>\n"
59" <arg type=\"u\" name=\"passkey\"/>\n"
60" </method>\n"
61" <method name=\"RequestAuthorization\">\n"
62" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
63" <arg type=\"o\" name=\"device\"/>\n"
64" </method>\n"
65" <method name=\"AuthorizeService\">\n"
66" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
67" <arg type=\"o\" name=\"device\"/>\n"
68" <arg type=\"s\" name=\"uuid\"/>\n"
69" </method>\n"
70" <method name=\"Cancel\">\n"
71" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
72" </method>\n"
73" <method name=\"Release\">\n"
74" <annotation value=\"\" name=\"org.freedesktop.DBus.GLib.Async\"/>\n"
75" </method>\n"
76" </interface>\n"
77 "")
78public:
79 BluezAgent1Adaptor(QObject *parent);
80 virtual ~BluezAgent1Adaptor();
81
82public: // PROPERTIES
83public Q_SLOTS: // METHODS
84 void AuthorizeService(const QDBusObjectPath &device, const QString &uuid);
85 void Cancel();
86 void DisplayPasskey(const QDBusObjectPath &device, uint passkey, ushort entered);
87 void DisplayPinCode(const QDBusObjectPath &device, const QString &pincode);
88 void Release();
89 void RequestAuthorization(const QDBusObjectPath &device);
90 void RequestConfirmation(const QDBusObjectPath &device, uint passkey);
91 uint RequestPasskey(const QDBusObjectPath &device);
92 QString RequestPinCode(const QDBusObjectPath &device);
93Q_SIGNALS: // SIGNALS
94};
95
96#endif
097
=== added file 'plugins/bluetooth/bluez_agentmanager1.cpp'
--- plugins/bluetooth/bluez_agentmanager1.cpp 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_agentmanager1.cpp 2015-11-20 08:48:08 +0000
@@ -0,0 +1,26 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -c BluezAgentManager1 -p bluez_agentmanager1 org.bluez.AgentManager1.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * This file may have been hand-edited. Look for HAND-EDIT comments
9 * before re-generating it.
10 */
11
12#include "bluez_agentmanager1.h"
13
14/*
15 * Implementation of interface class BluezAgentManager1
16 */
17
18BluezAgentManager1::BluezAgentManager1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
19 : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
20{
21}
22
23BluezAgentManager1::~BluezAgentManager1()
24{
25}
26
027
=== added file 'plugins/bluetooth/bluez_agentmanager1.h'
--- plugins/bluetooth/bluez_agentmanager1.h 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_agentmanager1.h 2015-11-20 08:48:08 +0000
@@ -0,0 +1,68 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -c BluezAgentManager1 -p bluez_agentmanager1 org.bluez.AgentManager1.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * Do not edit! All changes made to it will be lost.
9 */
10
11#ifndef BLUEZ_AGENTMANAGER1_H_1442489332
12#define BLUEZ_AGENTMANAGER1_H_1442489332
13
14#include <QtCore/QObject>
15#include <QtCore/QByteArray>
16#include <QtCore/QList>
17#include <QtCore/QMap>
18#include <QtCore/QString>
19#include <QtCore/QStringList>
20#include <QtCore/QVariant>
21#include <QtDBus/QtDBus>
22
23/*
24 * Proxy class for interface org.bluez.AgentManager1
25 */
26class BluezAgentManager1: public QDBusAbstractInterface
27{
28 Q_OBJECT
29public:
30 static inline const char *staticInterfaceName()
31 { return "org.bluez.AgentManager1"; }
32
33public:
34 BluezAgentManager1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
35
36 ~BluezAgentManager1();
37
38public Q_SLOTS: // METHODS
39 inline QDBusPendingReply<> RegisterAgent(const QDBusObjectPath &agent, const QString &capability)
40 {
41 QList<QVariant> argumentList;
42 argumentList << QVariant::fromValue(agent) << QVariant::fromValue(capability);
43 return asyncCallWithArgumentList(QStringLiteral("RegisterAgent"), argumentList);
44 }
45
46 inline QDBusPendingReply<> RequestDefaultAgent(const QDBusObjectPath &agent)
47 {
48 QList<QVariant> argumentList;
49 argumentList << QVariant::fromValue(agent);
50 return asyncCallWithArgumentList(QStringLiteral("RequestDefaultAgent"), argumentList);
51 }
52
53 inline QDBusPendingReply<> UnregisterAgent(const QDBusObjectPath &agent)
54 {
55 QList<QVariant> argumentList;
56 argumentList << QVariant::fromValue(agent);
57 return asyncCallWithArgumentList(QStringLiteral("UnregisterAgent"), argumentList);
58 }
59
60Q_SIGNALS: // SIGNALS
61};
62
63namespace org {
64 namespace bluez {
65 typedef ::BluezAgentManager1 AgentManager1;
66 }
67}
68#endif
069
=== added file 'plugins/bluetooth/bluez_device1.cpp'
--- plugins/bluetooth/bluez_device1.cpp 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_device1.cpp 2015-11-20 08:48:08 +0000
@@ -0,0 +1,26 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -c BluezDevice1 -p bluez_device1 org.bluez.Device1.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * This file may have been hand-edited. Look for HAND-EDIT comments
9 * before re-generating it.
10 */
11
12#include "bluez_device1.h"
13
14/*
15 * Implementation of interface class BluezDevice1
16 */
17
18BluezDevice1::BluezDevice1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
19 : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
20{
21}
22
23BluezDevice1::~BluezDevice1()
24{
25}
26
027
=== added file 'plugins/bluetooth/bluez_device1.h'
--- plugins/bluetooth/bluez_device1.h 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_device1.h 2015-11-20 08:48:08 +0000
@@ -0,0 +1,85 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -c BluezDevice1 -p bluez_device1 org.bluez.Device1.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * Do not edit! All changes made to it will be lost.
9 */
10
11#ifndef BLUEZ_DEVICE1_H_1442480478
12#define BLUEZ_DEVICE1_H_1442480478
13
14#include <QtCore/QObject>
15#include <QtCore/QByteArray>
16#include <QtCore/QList>
17#include <QtCore/QMap>
18#include <QtCore/QString>
19#include <QtCore/QStringList>
20#include <QtCore/QVariant>
21#include <QtDBus/QtDBus>
22
23/*
24 * Proxy class for interface org.bluez.Device1
25 */
26class BluezDevice1: public QDBusAbstractInterface
27{
28 Q_OBJECT
29public:
30 static inline const char *staticInterfaceName()
31 { return "org.bluez.Device1"; }
32
33public:
34 BluezDevice1(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
35
36 ~BluezDevice1();
37
38public Q_SLOTS: // METHODS
39 inline QDBusPendingReply<> CancelPairing()
40 {
41 QList<QVariant> argumentList;
42 return asyncCallWithArgumentList(QStringLiteral("CancelPairing"), argumentList);
43 }
44
45 inline QDBusPendingReply<> Connect()
46 {
47 QList<QVariant> argumentList;
48 return asyncCallWithArgumentList(QStringLiteral("Connect"), argumentList);
49 }
50
51 inline QDBusPendingReply<> ConnectProfile(const QString &UUID)
52 {
53 QList<QVariant> argumentList;
54 argumentList << QVariant::fromValue(UUID);
55 return asyncCallWithArgumentList(QStringLiteral("ConnectProfile"), argumentList);
56 }
57
58 inline QDBusPendingReply<> Disconnect()
59 {
60 QList<QVariant> argumentList;
61 return asyncCallWithArgumentList(QStringLiteral("Disconnect"), argumentList);
62 }
63
64 inline QDBusPendingReply<> DisconnectProfile(const QString &UUID)
65 {
66 QList<QVariant> argumentList;
67 argumentList << QVariant::fromValue(UUID);
68 return asyncCallWithArgumentList(QStringLiteral("DisconnectProfile"), argumentList);
69 }
70
71 inline QDBusPendingReply<> Pair()
72 {
73 QList<QVariant> argumentList;
74 return asyncCallWithArgumentList(QStringLiteral("Pair"), argumentList);
75 }
76
77Q_SIGNALS: // SIGNALS
78};
79
80namespace org {
81 namespace bluez {
82 typedef ::BluezDevice1 Device1;
83 }
84}
85#endif
086
=== added file 'plugins/bluetooth/bluez_helper.h'
--- plugins/bluetooth/bluez_helper.h 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/bluez_helper.h 2015-11-20 08:48:08 +0000
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2015 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16*/
17
18#ifndef BLUEZ_HELPER_H_
19#define BLUEZ_HELPER_H_
20
21#include <QObject>
22
23typedef QMap<QString, QVariantMap> InterfaceList;
24typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList;
25
26Q_DECLARE_METATYPE(InterfaceList)
27Q_DECLARE_METATYPE(ManagedObjectList)
28
29#endif
030
=== modified file 'plugins/bluetooth/dbus-shared.h'
--- plugins/bluetooth/dbus-shared.h 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/dbus-shared.h 2015-11-20 08:48:08 +0000
@@ -24,4 +24,13 @@
24#define DBUS_ADAPTER_AGENT_PATH "/com/canonical/SettingsBluetoothAgent/adapteragent"24#define DBUS_ADAPTER_AGENT_PATH "/com/canonical/SettingsBluetoothAgent/adapteragent"
25#define DBUS_AGENT_CAPABILITY "KeyboardDisplay"25#define DBUS_AGENT_CAPABILITY "KeyboardDisplay"
2626
27#define BLUEZ_SERVICE "org.bluez"
28
29#define BLUEZ_ADAPTER_IFACE "org.bluez.Adapter1"
30#define BLUEZ_DEVICE_IFACE "org.bluez.Device1"
31
32#define watchCall(call, func) \
33 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); \
34 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, func)
35
27#endif // USS_DBUS_SHARED_H36#endif // USS_DBUS_SHARED_H
2837
=== modified file 'plugins/bluetooth/device.cpp'
--- plugins/bluetooth/device.cpp 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/device.cpp 2015-11-20 08:48:08 +0000
@@ -26,16 +26,8 @@
2626
27#include "dbus-shared.h"27#include "dbus-shared.h"
2828
29/***29Device::Device(const QString &path, QDBusConnection &bus) :
30****30 m_strength(Device::None)
31***/
32
33Device::Device(const QMap<QString,QVariant> &properties)
34{
35 setProperties(properties);
36}
37
38Device::Device(const QString &path, QDBusConnection &bus)
39{31{
40 initDevice(path, bus);32 initDevice(path, bus);
41}33}
@@ -53,53 +45,44 @@
53 QObject::connect(this, SIGNAL(connectionChanged()), this, SIGNAL(deviceChanged()));45 QObject::connect(this, SIGNAL(connectionChanged()), this, SIGNAL(deviceChanged()));
54 QObject::connect(this, SIGNAL(strengthChanged()), this, SIGNAL(deviceChanged()));46 QObject::connect(this, SIGNAL(strengthChanged()), this, SIGNAL(deviceChanged()));
5547
56 // init the interfaces that we're supporting.48 m_bluezDevice.reset(new BluezDevice1(BLUEZ_SERVICE, path, bus));
57 initInterface(m_deviceInterface, path, "org.bluez.Device", bus);49 /* Give our calls a bit more time than the default 25 seconds to
58 initInterface(m_audioInterface, path, "org.bluez.Audio", bus);50 * complete whatever they are doing. In some situations (e.g. with
59 initInterface(m_audioSourceInterface, path, "org.bluez.AudioSource", bus);51 * specific devices) the default doesn't seem to be enough to. */
60 initInterface(m_audioSinkInterface, path, "org.bluez.AudioSink", bus);52 m_bluezDevice->setTimeout(60 * 1000 /* 60 seconds */);
61 initInterface(m_headsetInterface, path, "org.bluez.Headset", bus);53
62 initInterface(m_inputInterface, path, "org.bluez.Input", bus);54 m_bluezDeviceProperties.reset(new FreeDesktopProperties(BLUEZ_SERVICE, path, bus));
55
56 QObject::connect(m_bluezDeviceProperties.data(), SIGNAL(PropertiesChanged(const QString&, const QVariantMap&, const QStringList&)),
57 this, SLOT(slotPropertiesChanged(const QString&, const QVariantMap&, const QStringList&)));
6358
64 Q_EMIT(pathChanged());59 Q_EMIT(pathChanged());
65}60
6661 watchCall(m_bluezDeviceProperties->GetAll(BLUEZ_DEVICE_IFACE), [=](QDBusPendingCallWatcher *watcher) {
67/***62 QDBusPendingReply<QVariantMap> reply = *watcher;
68****63
69***/64 if (reply.isError()) {
7065 qWarning() << "Failed to retrieve properties for device" << m_bluezDevice->path();
71void Device::slotPropertyChanged(const QString &key,66 watcher->deleteLater();
72 const QDBusVariant &value)67 return;
73{68 }
74 updateProperty (key, value.variant());69
75}70 auto properties = reply.argumentAt<0>();
7671 setProperties(properties);
77void Device::initInterface(QSharedPointer<QDBusInterface> &setme,72
78 const QString &path,73 watcher->deleteLater();
79 const QString &interfaceName,74 });
80 QDBusConnection &bus)75}
81{76
82 const QString service = "org.bluez";77void Device::slotPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
8378 const QStringList &invalidatedProperties)
84 auto i = new QDBusInterface(service, path, interfaceName, bus);79{
8580 Q_UNUSED(invalidatedProperties);
86 if (!i->isValid()) {81
87 delete i;82 if (interface != BLUEZ_DEVICE_IFACE)
88 i = 0;83 return;
89 qWarning() << "Couldn't add proxy for" << interfaceName;84
90 } else {85 setProperties(changedProperties);
91 if (!bus.connect(service, path, interfaceName, "PropertyChanged",
92 this, SLOT(slotPropertyChanged(const QString&, const QDBusVariant&))))
93 qWarning() << "Unable to connect to " << interfaceName << "::PropertyChanged on" << path;
94 }
95
96 setme.reset(i);
97
98 if (setme && setme->isValid()) {
99 QDBusReply<QMap<QString,QVariant> > properties = setme->call("GetProperties");
100 if (properties.isValid())
101 setProperties(properties.value());
102 }
103}86}
10487
105void Device::setProperties(const QMap<QString,QVariant> &properties)88void Device::setProperties(const QMap<QString,QVariant> &properties)
@@ -111,79 +94,118 @@
111 }94 }
112}95}
11396
114void Device::connectPending()97void Device::setConnectAfterPairing(bool value)
115{98{
116 if (m_paired && !m_trusted) {99 if (m_connectAfterPairing == value)
117 while (!m_connectAfterPairing.isEmpty()) {100 return;
118 ConnectionMode mode = m_connectAfterPairing.takeFirst();101
119 connect(mode);102 m_connectAfterPairing = value;
120 }103}
121 }104
122}105void Device::disconnect()
123106{
124/***107 setConnection(Device::Disconnecting);
125****108
126***/109 QDBusPendingCall call = m_bluezDevice->Disconnect();
127110
128void Device::addConnectAfterPairing(ConnectionMode mode)111 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
129{112 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
130 m_connectAfterPairing.append(mode);113 QDBusPendingReply<void> reply = *watcher;
131}114
132115 if (reply.isError()) {
133void Device::disconnect(ConnectionMode mode)116 qWarning() << "Could not disconnect device:"
134{117 << reply.error().message();
135 QSharedPointer<QDBusInterface> interface;118
136119 // Make sure we switch the connection indicator back to
137 switch (mode) {120 // a sane state
138 case HeadsetMode:121 updateConnection();
139 interface = m_headsetInterface;122 }
140 break;123
141 case Audio:124 watcher->deleteLater();
142 interface = m_audioInterface;125 });
143 break;126}
144 case Input:127
145 interface = m_inputInterface;128void Device::connectAfterPairing()
146 break;129{
147 default:130 if (!m_connectAfterPairing)
148 qWarning() << "Unhandled connection mode" << mode;131 return;
149 return;132
150 }133 connect();
151134}
152 QDBusPendingCall call = interface->asyncCall("Disconnect");135
153136void Device::pair()
154 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);137{
155 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {138 if (m_paired) {
156 QDBusPendingReply<void> reply = *watcher;139 // If we are already paired we just have to make sure we
157140 // trigger the connection process if we have to
158 if (reply.isError()) {141 connectAfterPairing();
159 qWarning() << "Could not connect device:"142 return;
160 << reply.error().message();143 }
161 }144
162145 setConnection(Device::Connecting);
163 watcher->deleteLater();146
164 });147 m_isPairing = true;
165}148
166149 auto call = m_bluezDevice->asyncCall("Pair");
167void Device::connect(ConnectionMode mode)150
168{151 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
169 QSharedPointer<QDBusInterface> interface;152 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
170153 QDBusPendingReply<void> reply = *watcher;
171 switch (mode) {154 bool success = true;
172 case HeadsetMode:155
173 interface = m_headsetInterface;156 if (reply.isError()) {
174 break;157 qWarning() << "Failed to pair with device:"
175 case Audio:158 << reply.error().message();
176 interface = m_audioInterface;159 updateConnection();
177 break;160 success = false;
178 case Input:161 }
179 interface = m_inputInterface;162
180 break;163 m_isPairing = false;
181 default:164
182 qWarning() << "Unhandled connection mode" << mode;165 Q_EMIT(pairingDone(success));
183 return;166
184 }167 watcher->deleteLater();
185168 });
186 QDBusPendingCall call = interface->asyncCall("Connect");169}
170
171void Device::cancelPairing()
172{
173 if (!m_isPairing)
174 return;
175
176 auto call = m_bluezDevice->asyncCall("CancelPairing");
177
178 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
179 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
180 QDBusPendingReply<void> reply = *watcher;
181
182 if (reply.isError()) {
183 qWarning() << "Failed to cancel pairing attempt with device:"
184 << reply.error().message();
185 updateConnection();
186 } else {
187 // Only mark us a not pairing when call succeeded
188 m_isPairing = false;
189 }
190
191 watcher->deleteLater();
192 });
193}
194
195void Device::connect()
196{
197 // If we have just paired then the device switched to connected = true for
198 // a short moment as BlueZ opened up a RFCOMM channel to perform SDP. If
199 // we should connect with the device on specific profiles now we go ahead
200 // here even if we're marked as connected as this still doesn't mean we're
201 // connected on any profile. Calling org.bluez.Device1.Connect multiple
202 // times doesn't hurt an will not fail.
203 if (m_isConnected && !m_connectAfterPairing)
204 return;
205
206 setConnection(Device::Connecting);
207
208 QDBusPendingCall call = m_bluezDevice->asyncCall("Connect");
187209
188 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);210 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
189 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {211 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *watcher) {
@@ -196,6 +218,12 @@
196 makeTrusted(true);218 makeTrusted(true);
197 }219 }
198220
221 // Regardless if the Connected property has changed or not we update
222 // the connection state here as the connection process is over now
223 // and we should have received any state change already at this
224 // point.
225 updateConnection();
226
199 watcher->deleteLater();227 watcher->deleteLater();
200 });228 });
201}229}
@@ -205,36 +233,22 @@
205 QDBusPendingReply<void> reply = *call;233 QDBusPendingReply<void> reply = *call;
206234
207 if (reply.isError()) {235 if (reply.isError()) {
208 qWarning() << "Could not set device as trusted:"236 qWarning() << "Could not mark device as trusted:"
209 << reply.error().message();237 << reply.error().message();
210 }238 }
239
211 call->deleteLater();240 call->deleteLater();
212}241}
213242
214void Device::makeTrusted(bool trusted)243void Device::makeTrusted(bool trusted)
215{244{
216 QVariant value;245 auto call = m_bluezDeviceProperties->Set(BLUEZ_DEVICE_IFACE, "Trusted", QDBusVariant(trusted));
217 QDBusVariant variant(trusted);246
218247 auto watcher = new QDBusPendingCallWatcher(call, this);
219 value.setValue(variant);248 QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
220249 this, SLOT(slotMakeTrustedDone(QDBusPendingCallWatcher*)));
221 if (m_deviceInterface) {
222 QDBusPendingCall pcall
223 = m_deviceInterface->asyncCall("SetProperty", "Trusted", value);
224
225 QDBusPendingCallWatcher *watcher
226 = new QDBusPendingCallWatcher(pcall, this);
227 QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
228 this, SLOT(slotMakeTrustedDone(QDBusPendingCallWatcher*)));
229 } else {
230 qWarning() << "Can't set device trusted before it is added in BlueZ";
231 }
232}250}
233251
234/***
235****
236***/
237
238void Device::setName(const QString &name)252void Device::setName(const QString &name)
239{253{
240 if (m_name != name) {254 if (m_name != name) {
@@ -342,42 +356,34 @@
342{356{
343 Connection c;357 Connection c;
344358
345 /* The "State" property is a little more useful this "Connected" bool359 c = m_isConnected ? Connection::Connected : Connection::Disconnected;
346 because the former tells us Bluez *knows* a device is connecting.
347 So use "Connected" only as a fallback */
348
349 if ((m_state == "connected") || (m_state == "playing"))
350 c = Connection::Connected;
351 else if (m_state == "connecting")
352 c = Connection::Connecting;
353 else if (m_state == "disconnected")
354 c = Connection::Disconnected;
355 else
356 c = m_isConnected ? Connection::Connected : Connection::Disconnected;
357360
358 setConnection(c);361 setConnection(c);
359}362}
360363
361void Device::updateProperty(const QString &key, const QVariant &value)364void Device::updateProperty(const QString &key, const QVariant &value)
362{365{
363 if (key == "Name") { // org.bluez.Device366 if (key == "Name") {
364 setName(value.toString());367 setName(value.toString());
365 } else if (key == "Address") { // org.bluez.Device368 } else if (key == "Address") {
366 setAddress(value.toString());369 setAddress(value.toString());
367 } else if (key == "State") { // org.bluez.Audio, org.bluez.Headset
368 m_state = value.toString();
369 updateConnection();
370 } else if (key == "Connected") {370 } else if (key == "Connected") {
371 m_isConnected = value.toBool();371 m_isConnected = value.toBool();
372 updateConnection();372 updateConnection();
373 } else if (key == "Class") { // org.bluez.Device373 } else if (key == "Class") {
374 setType(getTypeFromClass(value.toUInt()));374 setType(getTypeFromClass(value.toUInt()));
375 } else if (key == "Paired") { // org.bluez.Device375 } else if (key == "Paired") {
376 setPaired(value.toBool());376 setPaired(value.toBool());
377
378 if (m_paired && m_connectAfterPairing) {
379 connectAfterPairing();
380 return;
381 }
382
377 updateConnection();383 updateConnection();
378 } else if (key == "Trusted") { // org.bluez.Device384 } else if (key == "Trusted") {
379 setTrusted(value.toBool());385 setTrusted(value.toBool());
380 } else if (key == "Icon") { // org.bluez.Device386 } else if (key == "Icon") {
381 m_fallbackIconName = value.toString();387 m_fallbackIconName = value.toString();
382 updateIcon ();388 updateIcon ();
383 } else if (key == "RSSI") {389 } else if (key == "RSSI") {
@@ -386,10 +392,6 @@
386 }392 }
387}393}
388394
389/***
390****
391***/
392
393/* Determine the Type from the bits in the Class of Device (CoD) field.395/* Determine the Type from the bits in the Class of Device (CoD) field.
394 https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband */396 https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband */
395Device::Type Device::getTypeFromClass (quint32 c)397Device::Type Device::getTypeFromClass (quint32 c)
@@ -468,6 +470,11 @@
468 if ((c & 0x20) != 0)470 if ((c & 0x20) != 0)
469 return Type::Camera;471 return Type::Camera;
470 break;472 break;
473
474 case 0x07:
475 if ((c & 0x4) != 0)
476 return Type::Watch;
477 break;
471 }478 }
472479
473 return Type::Other;480 return Type::Other;
@@ -489,4 +496,3 @@
489496
490 return None;497 return None;
491}498}
492
493499
=== modified file 'plugins/bluetooth/device.h'
--- plugins/bluetooth/device.h 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/device.h 2015-11-20 08:48:08 +0000
@@ -26,6 +26,9 @@
26#include <QSharedPointer>26#include <QSharedPointer>
27#include <QString>27#include <QString>
2828
29#include "freedesktop_properties.h"
30#include "bluez_device1.h"
31
29struct Device: QObject32struct Device: QObject
30{33{
31 Q_OBJECT34 Q_OBJECT
@@ -71,17 +74,14 @@
7174
72 enum Type { Other, Computer, Cellular, Smartphone, Phone, Modem, Network,75 enum Type { Other, Computer, Cellular, Smartphone, Phone, Modem, Network,
73 Headset, Speakers, Headphones, Video, OtherAudio, Joypad,76 Headset, Speakers, Headphones, Video, OtherAudio, Joypad,
74 Keypad, Keyboard, Tablet, Mouse, Printer, Camera, Carkit };77 Keypad, Keyboard, Tablet, Mouse, Printer, Camera, Carkit, Watch };
7578
76 enum Strength { None, Poor, Fair, Good, Excellent };79 enum Strength { None, Poor, Fair, Good, Excellent };
7780
78 enum Connection { Disconnected=1, Connecting=2,81 enum Connection { Disconnected=1, Connecting=2,
79 Connected=4, Disconnecting=8 };82 Connected=4, Disconnecting=8 };
8083
81 enum ConnectionMode { Audio, AudioSource, AudioSink, HandsfreeGateway,84 Q_ENUMS(Type Strength Connection)
82 HeadsetMode, Input };
83
84 Q_ENUMS(Type Strength Connection ConnectionMode)
8585
86 Q_DECLARE_FLAGS(Connections, Connection)86 Q_DECLARE_FLAGS(Connections, Connection)
8787
@@ -96,6 +96,7 @@
96 void connectionChanged();96 void connectionChanged();
97 void strengthChanged();97 void strengthChanged();
98 void deviceChanged(); // catchall for any change98 void deviceChanged(); // catchall for any change
99 void pairingDone(bool success);
99100
100public:101public:
101 const QString& getName() const { return m_name; }102 const QString& getName() const { return m_name; }
@@ -106,7 +107,7 @@
106 bool isTrusted() const { return m_trusted; }107 bool isTrusted() const { return m_trusted; }
107 Connection getConnection() const { return m_connection; }108 Connection getConnection() const { return m_connection; }
108 Strength getStrength() const { return m_strength; }109 Strength getStrength() const { return m_strength; }
109 QString getPath() const { return m_deviceInterface ? m_deviceInterface->path() : QString(); }110 QString getPath() const { return m_bluezDevice ? m_bluezDevice->path() : QString(); }
110111
111 private:112 private:
112 QString m_name;113 QString m_name;
@@ -120,13 +121,10 @@
120 Connection m_connection = Connection::Disconnected;121 Connection m_connection = Connection::Disconnected;
121 Strength m_strength = Strength::None;122 Strength m_strength = Strength::None;
122 bool m_isConnected = false;123 bool m_isConnected = false;
123 QSharedPointer<QDBusInterface> m_deviceInterface;124 bool m_connectAfterPairing = false;
124 QSharedPointer<QDBusInterface> m_audioInterface;125 QScopedPointer<BluezDevice1> m_bluezDevice;
125 QSharedPointer<QDBusInterface> m_audioSourceInterface;126 QScopedPointer<FreeDesktopProperties> m_bluezDeviceProperties;
126 QSharedPointer<QDBusInterface> m_audioSinkInterface;127 bool m_isPairing = false;
127 QSharedPointer<QDBusInterface> m_headsetInterface;
128 QSharedPointer<QDBusInterface> m_inputInterface;
129 QList<ConnectionMode> m_connectAfterPairing;
130128
131 protected:129 protected:
132 void setName(const QString &name);130 void setName(const QString &name);
@@ -142,30 +140,29 @@
142140
143 public:141 public:
144 Device() {}142 Device() {}
143 Device(const QString &path, QDBusConnection &bus);
145 ~Device() {}144 ~Device() {}
146 Device(const QString &path, QDBusConnection &bus);
147 Device(const QMap<QString,QVariant> &properties);
148 void initDevice(const QString &path, QDBusConnection &bus);
149 bool isValid() const { return getType() != Type::Other; }145 bool isValid() const { return getType() != Type::Other; }
150 void connect(ConnectionMode);146 void pair();
147 Q_INVOKABLE void cancelPairing();
148 void connect();
151 void makeTrusted(bool trusted);149 void makeTrusted(bool trusted);
152 void disconnect(ConnectionMode);150 void disconnect();
153 void setProperties(const QMap<QString,QVariant> &properties);151 void setProperties(const QMap<QString,QVariant> &properties);
154 void addConnectAfterPairing(const ConnectionMode mode);152 void setConnectAfterPairing(bool value);
155
156 public Q_SLOTS:
157 void connectPending();
158153
159 private Q_SLOTS:154 private Q_SLOTS:
160 void slotPropertyChanged(const QString &key, const QDBusVariant &value);155 void slotPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
156 const QStringList &invalidatedProperties);
161 void slotMakeTrustedDone(QDBusPendingCallWatcher *call);157 void slotMakeTrustedDone(QDBusPendingCallWatcher *call);
162158
163 private:159 private:
160 void initDevice(const QString &path, QDBusConnection &bus);
164 void updateProperties(QSharedPointer<QDBusInterface>);161 void updateProperties(QSharedPointer<QDBusInterface>);
165 void initInterface(QSharedPointer<QDBusInterface>&, const QString &path, const QString &name, QDBusConnection&);
166 void updateProperty(const QString &key, const QVariant &value);162 void updateProperty(const QString &key, const QVariant &value);
167 static Type getTypeFromClass(quint32 bluetoothClass);163 static Type getTypeFromClass(quint32 bluetoothClass);
168 Device::Strength getStrengthFromRssi(int rssi);164 Device::Strength getStrengthFromRssi(int rssi);
165 void connectAfterPairing();
169};166};
170167
171Q_DECLARE_METATYPE(Device*)168Q_DECLARE_METATYPE(Device*)
172169
=== modified file 'plugins/bluetooth/devicemodel.cpp'
--- plugins/bluetooth/devicemodel.cpp 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/devicemodel.cpp 2015-11-20 08:48:08 +0000
@@ -27,33 +27,81 @@
2727
28namespace28namespace
29{29{
30 const int SCANNING_ACTIVE_DURATION_MSEC = (10 * 1000);30 const int SCANNING_ACTIVE_DURATION_MSEC = (30 * 1000);
31
32 const int SCANNING_IDLE_DURATION_MSEC = (10 * 1000);31 const int SCANNING_IDLE_DURATION_MSEC = (10 * 1000);
33}32}
3433
35DeviceModel::DeviceModel(QDBusConnection &dbus, QObject *parent):34DeviceModel::DeviceModel(QDBusConnection &dbus, QObject *parent):
36 QAbstractListModel(parent),35 QAbstractListModel(parent),
37 m_dbus(dbus),36 m_dbus(dbus),
38 m_bluezManager("org.bluez", "/", "org.bluez.Manager", m_dbus)37 m_bluezManager("org.bluez", "/", m_dbus),
38 m_bluezAgentManager("org.bluez", "/org/bluez", m_dbus),
39 m_isPowered(false),
40 m_isPairable(false),
41 m_isDiscovering(false),
42 m_isDiscoverable(false)
39{43{
40 if (m_bluezManager.isValid()) {44 if (m_bluezManager.isValid()) {
4145
42 QDBusReply<QDBusObjectPath> qObjectPath = m_bluezManager.call("DefaultAdapter");46 connect(&m_bluezManager, SIGNAL(InterfacesAdded(const QDBusObjectPath&, InterfaceList)),
43 if (qObjectPath.isValid())47 this, SLOT(slotInterfacesAdded(const QDBusObjectPath&, InterfaceList)));
44 setAdapterFromPath(qObjectPath.value().path());48
4549 connect(&m_bluezManager, SIGNAL(InterfacesRemoved(const QDBusObjectPath&, const QStringList&)),
46 m_dbus.connect (m_bluezManager.service(),50 this, SLOT(slotInterfacesRemoved(const QDBusObjectPath&, const QStringList&)));
47 m_bluezManager.path(),51
48 m_bluezManager.interface(),52 watchCall(m_bluezManager.GetManagedObjects(), [=](QDBusPendingCallWatcher *watcher) {
49 "DefaultAdapterChanged",53 QDBusPendingReply<ManagedObjectList> reply = *watcher;
50 this, SLOT(slotDefaultAdapterChanged(const QDBusObjectPath&)));54
5155 if (reply.isError()) {
52 m_dbus.connect (m_bluezManager.service(),56 qWarning() << "Failed to retrieve list of managed objects from BlueZ service: "
53 m_bluezManager.path(),57 << reply.error().message();
54 m_bluezManager.interface(),58 watcher->deleteLater();
55 "AdapterRemoved",59 return;
56 this, SLOT(slotAdapterRemoved(const QDBusObjectPath&)));60 }
61
62 auto objectList = reply.argumentAt<0>();
63
64 for (QDBusObjectPath path : objectList.keys()) {
65 InterfaceList ifaces = objectList.value(path);
66
67 if (!ifaces.contains(BLUEZ_ADAPTER_IFACE))
68 continue;
69
70 // Ok, here we've found an adapter. As we don't expect multiple at the
71 // moment we just take the first one we find.
72 setAdapterFromPath(path.path(), ifaces.value(BLUEZ_ADAPTER_IFACE));
73 break;
74 }
75
76 watcher->deleteLater();
77 });
78 }
79
80 if (m_bluezAgentManager.isValid()) {
81 // NOTE: We can safely register our agent here even if we don't
82 // manage any adapter yet. BlueZ makes sure our agent will only
83 // process requests related to actions we do unless we our agent
84 // the system default one.
85 auto call = m_bluezAgentManager.RegisterAgent(QDBusObjectPath(DBUS_ADAPTER_AGENT_PATH),
86 DBUS_AGENT_CAPABILITY);
87
88 watchCall(call, [=](QDBusPendingCallWatcher *watcher) {
89 QDBusPendingReply<void> reply = *watcher;
90
91 if (reply.isError()) {
92 qWarning() << "Failed to register our agent with BlueZ:"
93 << reply.error().message();
94 }
95 else {
96 setupAsDefaultAgent();
97 }
98
99 watcher->deleteLater();
100 });
101 }
102 else {
103 qWarning() << "Could not register agent with BlueZ service as "
104 << "the agent manager is not available!";
57 }105 }
58106
59 connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));107 connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
@@ -62,6 +110,89 @@
62DeviceModel::~DeviceModel()110DeviceModel::~DeviceModel()
63{111{
64 clearAdapter();112 clearAdapter();
113
114 qWarning() << "Releasing device model ..";
115
116 if (m_bluezAgentManager.isValid()) {
117 auto call = m_bluezAgentManager.UnregisterAgent(QDBusObjectPath(DBUS_ADAPTER_AGENT_PATH));
118 watchCall(call, [=](QDBusPendingCallWatcher *watcher) {
119 QDBusPendingReply<void> reply = *watcher;
120
121 if (reply.isError()) {
122 qWarning() << "Failed to unregister our agent with BlueZ:"
123 << reply.error().message();
124 }
125
126 watcher->deleteLater();
127 });
128 }
129}
130
131void DeviceModel::setupAsDefaultAgent()
132{
133 auto call = m_bluezAgentManager.RequestDefaultAgent(QDBusObjectPath(DBUS_ADAPTER_AGENT_PATH));
134 watchCall(call, [=](QDBusPendingCallWatcher *watcher) {
135 QDBusPendingReply<void> reply = *watcher;
136
137 if (reply.isError()) {
138 qWarning() << "Failed to setup ourself as default agent: "
139 << reply.error().message();
140 }
141
142 watcher->deleteLater();
143 });
144}
145
146void DeviceModel::slotInterfacesAdded(const QDBusObjectPath &objectPath, InterfaceList ifacesAndProps)
147{
148 Q_UNUSED(ifacesAndProps);
149
150 auto candidatedPath = objectPath.path();
151
152 if (!m_bluezAdapter) {
153 // Maybe we have a new adapter we can start to use?
154 if (ifacesAndProps.contains(BLUEZ_ADAPTER_IFACE))
155 setAdapterFromPath(candidatedPath, ifacesAndProps.value(BLUEZ_ADAPTER_IFACE));
156
157 return;
158 }
159
160 // At this point we can only get new devices
161 if (!candidatedPath.startsWith(m_bluezAdapter->path()))
162 return;
163
164 if (!ifacesAndProps.contains(BLUEZ_DEVICE_IFACE))
165 return;
166
167 addDevice(candidatedPath, ifacesAndProps.value(BLUEZ_DEVICE_IFACE));
168}
169
170void DeviceModel::slotInterfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces)
171{
172 auto candidatedPath = objectPath.path();
173
174 if (!m_bluezAdapter)
175 return;
176
177 if (candidatedPath == m_bluezAdapter->path() &&
178 interfaces.contains(BLUEZ_ADAPTER_IFACE)) {
179 clearAdapter();
180 return;
181 }
182
183 if (!candidatedPath.startsWith(m_bluezAdapter->path()))
184 return;
185
186 if (!interfaces.contains(BLUEZ_DEVICE_IFACE))
187 return;
188
189 auto device = getDeviceFromPath(candidatedPath);
190 if (!device)
191 return;
192
193 const int row = findRowFromAddress(device->getAddress());
194 if ((row >= 0))
195 removeRow(row);
65}196}
66197
67int DeviceModel::findRowFromAddress(const QString &address) const198int DeviceModel::findRowFromAddress(const QString &address) const
@@ -79,27 +210,45 @@
79 : SCANNING_IDLE_DURATION_MSEC);210 : SCANNING_IDLE_DURATION_MSEC);
80}211}
81212
213void DeviceModel::setDiscovering(bool value)
214{
215 if (value == m_isDiscovering)
216 return;
217
218 m_isDiscovering = value;
219 Q_EMIT(discoveringChanged(m_isDiscovering));
220}
221
82void DeviceModel::stopDiscovery()222void DeviceModel::stopDiscovery()
83{223{
84 if (m_isDiscovering) {224 if (m_bluezAdapter && m_isPowered && m_isDiscovering) {
85 if (m_bluezAdapter)225
86 m_bluezAdapter->asyncCall("StopDiscovery");226 watchCall(m_bluezAdapter->StopDiscovery(), [=](QDBusPendingCallWatcher *watcher) {
87 m_isDiscovering = false;227 QDBusPendingReply<void> reply = *watcher;
88 Q_EMIT(discoveringChanged(m_isDiscovering));228 if (reply.isError()) {
229 qWarning() << "Failed to stop device discovery:"
230 << reply.error().message();
231 }
232
233 watcher->deleteLater();
234 });
89 }235 }
90
91 restartTimer();
92}236}
93237
94void DeviceModel::startDiscovery()238void DeviceModel::startDiscovery()
95{239{
96 if (m_bluezAdapter && m_isPowered && !m_isDiscovering) {240 if (m_bluezAdapter && m_isPowered && !m_isDiscovering) {
97 m_bluezAdapter->asyncCall("StartDiscovery");241
98 m_isDiscovering = true;242 watchCall(m_bluezAdapter->StartDiscovery(), [=](QDBusPendingCallWatcher *watcher) {
99 Q_EMIT(discoveringChanged(m_isDiscovering));243 QDBusPendingReply<void> reply = *watcher;
244 if (reply.isError()) {
245 qWarning() << "Failed to start device discovery:"
246 << reply.error().message();
247 }
248
249 watcher->deleteLater();
250 });
100 }251 }
101
102 restartTimer();
103}252}
104253
105void DeviceModel::toggleDiscovery()254void DeviceModel::toggleDiscovery()
@@ -119,27 +268,12 @@
119{268{
120 if (m_bluezAdapter) {269 if (m_bluezAdapter) {
121270
122 QDBusConnection bus = m_bluezAdapter->connection();
123 const QString service = m_bluezAdapter->service();
124 const QString path = m_bluezAdapter->path();
125 const QString interface = m_bluezAdapter->interface();
126
127 stopDiscovery();271 stopDiscovery();
128 m_discoverableTimer.stop();272 m_discoverableTimer.stop();
129 trySetDiscoverable(false);273 trySetDiscoverable(false);
130274
131 bus.disconnect(service, path, interface, "DeviceCreated",
132 this, SLOT(slotDeviceCreated(const QDBusObjectPath&)));
133 bus.disconnect(service, path, interface, "DeviceRemoved",
134 this, SLOT(slotDeviceRemoved(const QDBusObjectPath&)));
135 bus.disconnect(service, path, interface, "DeviceFound",
136 this, SLOT(slotDeviceFound(const QString&, const QMap<QString,QVariant>&)));
137 bus.disconnect(service, path, interface, "DeviceDisappeared",
138 this, SLOT(slotDeviceDisappeared(const QString&)));
139 bus.disconnect(service, path, interface, "PropertyChanged",
140 this, SLOT(slotPropertyChanged(const QString&, const QDBusVariant&)));
141
142 m_bluezAdapter.reset(0);275 m_bluezAdapter.reset(0);
276 m_bluezAdapterProperties.reset(0);
143 m_adapterName.clear();277 m_adapterName.clear();
144278
145 beginResetModel();279 beginResetModel();
@@ -148,68 +282,75 @@
148 }282 }
149}283}
150284
151void DeviceModel::setAdapterFromPath(const QString &path)285void DeviceModel::setAdapterFromPath(const QString &path, const QVariantMap &properties)
152{286{
153 clearAdapter();287 clearAdapter();
154288
155 if (!path.isEmpty()) {289 if (!path.isEmpty()) {
156290
157 const QString service = "org.bluez";291 auto adapter = new BluezAdapter1(BLUEZ_SERVICE, path, m_dbus);
158 const QString interface = "org.bluez.Adapter";292 auto adapterProperties = new FreeDesktopProperties(BLUEZ_SERVICE, path, m_dbus);
159 auto i = new QDBusInterface(service, path, interface, m_dbus);293
160294 m_bluezAdapter.reset(adapter);
161 m_dbus.connect(service, path, interface, "DeviceCreated",295 m_bluezAdapterProperties.reset(adapterProperties);
162 this, SLOT(slotDeviceCreated(const QDBusObjectPath&)));296
163 m_dbus.connect(service, path, interface, "DeviceRemoved",
164 this, SLOT(slotDeviceRemoved(const QDBusObjectPath&)));
165 m_dbus.connect(service, path, interface, "DeviceFound",
166 this, SLOT(slotDeviceFound(const QString&, const QMap<QString,QVariant>&)));
167 m_dbus.connect(service, path, interface, "DeviceDisappeared",
168 this, SLOT(slotDeviceDisappeared(const QString&)));
169 m_dbus.connect(service, path, interface, "PropertyChanged",
170 this, SLOT(slotPropertyChanged(const QString&, const QDBusVariant&)));
171
172 m_bluezAdapter.reset(i);
173 startDiscovery();297 startDiscovery();
174 updateDevices();298 updateDevices();
175299
176 QDBusReply<QMap<QString,QVariant> > properties = m_bluezAdapter->call("GetProperties");300 setProperties(properties);
177 if (properties.isValid())301
178 setProperties(properties.value());302 connect(adapterProperties, SIGNAL(PropertiesChanged(const QString&, const QVariantMap&, const QStringList&)),
303 this, SLOT(slotAdapterPropertiesChanged(const QString&, const QVariantMap&, const QStringList&)));
179304
180 // Delay enabling discoverability by 1 second.305 // Delay enabling discoverability by 1 second.
181 m_discoverableTimer.setSingleShot(true);306 m_discoverableTimer.setSingleShot(true);
182 connect(&m_discoverableTimer, SIGNAL(timeout()), this, SLOT(slotEnableDiscoverable()));307 connect(&m_discoverableTimer, SIGNAL(timeout()), this, SLOT(slotEnableDiscoverable()));
183 m_discoverableTimer.start(1000);308 m_discoverableTimer.start(1000);
184
185 // With the agent registered on the bus, make it known by the adapter
186 QDBusReply<void > reply = m_bluezAdapter->call("RegisterAgent",
187 qVariantFromValue(QDBusObjectPath(DBUS_ADAPTER_AGENT_PATH)),
188 QString(DBUS_AGENT_CAPABILITY));
189 if (!reply.isValid())
190 qWarning() << "Error registering agent for the default adapter:" << reply.error();
191 }309 }
192}310}
193311
194void DeviceModel::slotAdapterRemoved(const QDBusObjectPath &path)312void DeviceModel::slotAdapterPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
195{313 const QStringList &invalidatedProperties)
196 if (m_bluezAdapter && (m_bluezAdapter->path()==path.path()))314{
197 clearAdapter();315 Q_UNUSED(invalidatedProperties);
198}316
199317 if (interface != BLUEZ_ADAPTER_IFACE)
200void DeviceModel::slotDefaultAdapterChanged(const QDBusObjectPath &objectPath)318 return;
201{319
202 setAdapterFromPath (objectPath.path());320 setProperties(changedProperties);
203}321}
204322
205void DeviceModel::updateDevices()323void DeviceModel::updateDevices()
206{324{
207 if (m_bluezAdapter && m_bluezAdapter->isValid()) {325 watchCall(m_bluezManager.GetManagedObjects(), [=](QDBusPendingCallWatcher *watcher) {
208 QDBusReply<QList<QDBusObjectPath> > reply = m_bluezAdapter->call("ListDevices");326 QDBusPendingReply<ManagedObjectList> reply = *watcher;
209 if (reply.isValid())327
210 for (auto path : reply.value())328 if (reply.isError()) {
211 addDevice(path.path());329 qWarning() << "Failed to retrieve list of managed objects from BlueZ service: "
212 }330 << reply.error().message();
331 watcher->deleteLater();
332 return;
333 }
334
335 auto objectList = reply.argumentAt<0>();
336
337 for (auto objectPath : objectList.keys()) {
338 auto candidatePath = objectPath.path();
339
340 if (!candidatePath.startsWith(m_bluezAdapter->path()))
341 continue;
342
343 InterfaceList ifaces = objectList.value(objectPath);
344
345 if (!ifaces.contains(BLUEZ_DEVICE_IFACE))
346 continue;
347
348 auto properties = ifaces.value(BLUEZ_DEVICE_IFACE);
349
350 addDevice(candidatePath, properties);
351 }
352
353 });
213}354}
214355
215void DeviceModel::setProperties(const QMap<QString,QVariant> &properties)356void DeviceModel::setProperties(const QMap<QString,QVariant> &properties)
@@ -231,6 +372,9 @@
231 m_isPairable = value.toBool();372 m_isPairable = value.toBool();
232 } else if (key == "Discoverable") {373 } else if (key == "Discoverable") {
233 setDiscoverable(value.toBool());374 setDiscoverable(value.toBool());
375 } else if (key == "Discovering") {
376 setDiscovering(value.toBool());
377 restartTimer();
234 } else if (key == "Powered") {378 } else if (key == "Powered") {
235 setPowered(value.toBool());379 setPowered(value.toBool());
236 if (m_isPowered)380 if (m_isPowered)
@@ -268,7 +412,7 @@
268 value.setValue(disc);412 value.setValue(disc);
269413
270 if (m_bluezAdapter && m_bluezAdapter->isValid() && m_isPowered) {414 if (m_bluezAdapter && m_bluezAdapter->isValid() && m_isPowered) {
271 reply = m_bluezAdapter->call("SetProperty", "Discoverable", value);415 reply = m_bluezAdapterProperties->call("Set", BLUEZ_ADAPTER_IFACE, "Discoverable", value);
272 if (!reply.isValid())416 if (!reply.isValid())
273 qWarning() << "Error setting device discoverable:" << reply.error();417 qWarning() << "Error setting device discoverable:" << reply.error();
274 }418 }
@@ -280,12 +424,23 @@
280 updateProperty (key, value.variant());424 updateProperty (key, value.variant());
281}425}
282426
283void DeviceModel::addDevice(const QString &path)427void DeviceModel::slotDevicePairingDone(bool success)
428{
429 Device *device = static_cast<Device*>(sender());
430
431 Q_EMIT(devicePairingDone(device, success));
432}
433
434void DeviceModel::addDevice(const QString &path, const QVariantMap &properties)
284{435{
285 QSharedPointer<Device> device(new Device(path, m_dbus));436 QSharedPointer<Device> device(new Device(path, m_dbus));
437 device->setProperties(properties);
438
286 if (device->isValid()) {439 if (device->isValid()) {
287 QObject::connect(device.data(), SIGNAL(deviceChanged()),440 QObject::connect(device.data(), SIGNAL(deviceChanged()),
288 this, SLOT(slotDeviceChanged()));441 this, SLOT(slotDeviceChanged()));
442 QObject::connect(device.data(), SIGNAL(pairingDone(bool)),
443 this, SLOT(slotDevicePairingDone(bool)));
289 addDevice(device);444 addDevice(device);
290 }445 }
291}446}
@@ -322,78 +477,6 @@
322 }477 }
323}478}
324479
325void DeviceModel::slotDeviceCreated(const QDBusObjectPath &path)
326{
327 const QString service = "org.bluez";
328 const QString interface = "org.bluez.Device";
329 QScopedPointer<QDBusInterface> bluezDevice(
330 new QDBusInterface(service, path.path(), interface, m_dbus));
331
332 // A device was created. Now, we likely already have it, so let's find it
333 // again and finish the initialization.
334 QDBusReply<QMap<QString,QVariant> > properties
335 = bluezDevice->call("GetProperties");
336 if (properties.isValid()) {
337 QMapIterator<QString,QVariant> it(properties);
338 while (it.hasNext()) {
339 it.next();
340 if (it.key() == "Address") {
341 QSharedPointer<Device> device = getDeviceFromAddress(it.value().toString());
342
343 if (device) {
344 device->initDevice(path.path(), m_dbus);
345 QObject::connect(device.data(), SIGNAL(deviceChanged()),
346 this, SLOT(slotDeviceChanged()));
347 addDevice(device);
348 } else {
349 addDevice(path.path());
350 }
351 break;
352 }
353 }
354 } else {
355 qWarning() << "Invalid device properties for" << path.path();
356 }
357}
358
359void DeviceModel::slotDeviceFound(const QString &address,
360 const QMap<QString,QVariant> &properties)
361{
362 Q_UNUSED(properties);
363
364 QSharedPointer<Device> device = getDeviceFromAddress(address);
365
366 if (!device) {
367 QSharedPointer<Device> device(new Device(properties));
368 if (device->isValid()) {
369 addDevice(device);
370 }
371 } else {
372 device->setProperties(properties);
373 }
374}
375
376void DeviceModel::slotDeviceRemoved(const QDBusObjectPath &path)
377{
378 /* Remove the device immediately, it will be listed again
379 once discovery results are returned. */
380
381 auto device = getDeviceFromPath(path.path());
382
383 if (device != nullptr) {
384 const int row = findRowFromAddress(device->getAddress());
385 if ((row >= 0))
386 removeRow(row);
387 }
388}
389
390void DeviceModel::slotDeviceDisappeared(const QString &address)
391{
392 const int row = findRowFromAddress(address);
393 if ((row >= 0) && !m_devices[row]->isPaired())
394 removeRow(row);
395}
396
397void DeviceModel::slotDeviceChanged()480void DeviceModel::slotDeviceChanged()
398{481{
399 const Device * device = qobject_cast<Device*>(sender());482 const Device * device = qobject_cast<Device*>(sender());
@@ -429,61 +512,6 @@
429 return QSharedPointer<Device>();512 return QSharedPointer<Device>();
430}513}
431514
432void DeviceModel::addConnectAfterPairing(const QString &address, Device::ConnectionMode mode)
433{
434 QSharedPointer<Device> device = getDeviceFromAddress(address);
435 if (device) {
436 device->addConnectAfterPairing(mode);
437 } else {
438 qWarning() << "Device could not be found, can't add an operation";
439 }
440}
441
442void DeviceModel::slotCreateFinished(QDBusPendingCallWatcher *call)
443{
444 QDBusPendingReply<QDBusObjectPath> reply = *call;
445
446 if (reply.isError()) {
447 qWarning() << "Could not create device:" << reply.error().message();
448 }
449
450 call->deleteLater();
451}
452
453void DeviceModel::createDevice (const QString &address, QObject *agent)
454{
455 if (m_bluezAdapter) {
456 QString agent_path(DBUS_AGENT_PATH);
457 agent_path.append("/");
458 agent_path.append(address);
459 agent_path.replace(":", "_");
460
461 if(!m_dbus.registerObject(agent_path, agent))
462 qCritical() << "Couldn't register agent at" << agent_path;
463
464 QDBusPendingCall pcall = m_bluezAdapter->asyncCall("CreatePairedDevice",
465 address,
466 qVariantFromValue(QDBusObjectPath(agent_path)),
467 QString(DBUS_AGENT_CAPABILITY));
468
469 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
470 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [this, address](QDBusPendingCallWatcher *watcher) {
471 QDBusPendingReply<QDBusObjectPath> reply = *watcher;
472
473 if (reply.isError()) {
474 qWarning() << "Could not create device:" << reply.error().message();
475 } else {
476 QSharedPointer<Device> device = getDeviceFromAddress(address);
477 device->connectPending();
478 }
479
480 watcher->deleteLater();
481 });
482 } else {
483 qWarning() << "Default adapter is not available for device creation";
484 }
485}
486
487void DeviceModel::slotRemoveFinished(QDBusPendingCallWatcher *call)515void DeviceModel::slotRemoveFinished(QDBusPendingCallWatcher *call)
488{516{
489 QDBusPendingReply<void> reply = *call;517 QDBusPendingReply<void> reply = *call;
@@ -496,19 +524,19 @@
496524
497void DeviceModel::removeDevice (const QString &path)525void DeviceModel::removeDevice (const QString &path)
498{526{
499 if (m_bluezAdapter) {527 if (!m_bluezAdapter) {
500 QDBusPendingCall pcall = m_bluezAdapter->asyncCall("RemoveDevice", qVariantFromValue(QDBusObjectPath(path)));
501
502 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
503 QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
504 this, SLOT(slotRemoveFinished(QDBusPendingCallWatcher*)));
505 } else {
506 qWarning() << "Default adapter is not available for device removal";528 qWarning() << "Default adapter is not available for device removal";
529 return;
507 }530 }
531
532 QDBusPendingCall call = m_bluezAdapter->RemoveDevice(QDBusObjectPath(path));
533
534 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
535 QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
536 this, SLOT(slotRemoveFinished(QDBusPendingCallWatcher*)));
508}537}
509538
510int539int DeviceModel::rowCount(const QModelIndex &parent) const
511DeviceModel::rowCount(const QModelIndex &parent) const
512{540{
513 Q_UNUSED(parent);541 Q_UNUSED(parent);
514542
@@ -583,13 +611,6 @@
583 return ret;611 return ret;
584}612}
585613
586
587/***
588****
589**** Filter
590****
591***/
592
593void DeviceFilter::filterOnType(QVector<Device::Type> types)614void DeviceFilter::filterOnType(QVector<Device::Type> types)
594{615{
595 m_types = types;616 m_types = types;
596617
=== modified file 'plugins/bluetooth/devicemodel.h'
--- plugins/bluetooth/devicemodel.h 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/devicemodel.h 2015-11-20 08:48:08 +0000
@@ -35,6 +35,11 @@
3535
36#include "device.h"36#include "device.h"
3737
38#include "freedesktop_objectmanager.h"
39#include "freedesktop_properties.h"
40#include "bluez_adapter1.h"
41#include "bluez_agentmanager1.h"
42
38class DeviceModel: public QAbstractListModel43class DeviceModel: public QAbstractListModel
39{44{
40 Q_OBJECT45 Q_OBJECT
@@ -68,8 +73,6 @@
68 bool isPowered() const { return m_isPowered; }73 bool isPowered() const { return m_isPowered; }
69 bool isDiscovering() const { return m_isDiscovering; }74 bool isDiscovering() const { return m_isDiscovering; }
70 bool isDiscoverable() const { return m_isDiscoverable; }75 bool isDiscoverable() const { return m_isDiscoverable; }
71 void addConnectAfterPairing(const QString &address, Device::ConnectionMode mode);
72 void createDevice(const QString &address, QObject *agent);
73 void removeDevice(const QString &path);76 void removeDevice(const QString &path);
74 void stopDiscovery();77 void stopDiscovery();
75 void startDiscovery();78 void startDiscovery();
@@ -80,10 +83,12 @@
80 void poweredChanged(bool powered);83 void poweredChanged(bool powered);
81 void discoveringChanged(bool isDiscovering);84 void discoveringChanged(bool isDiscovering);
82 void discoverableChanged(bool isDiscoverable);85 void discoverableChanged(bool isDiscoverable);
86 void devicePairingDone(Device *device, bool success);
8387
84private:88private:
85 QDBusConnection m_dbus;89 QDBusConnection m_dbus;
86 QDBusInterface m_bluezManager;90 DBusObjectManagerInterface m_bluezManager;
91 BluezAgentManager1 m_bluezAgentManager;
8792
88 void setProperties(const QMap<QString,QVariant> &properties);93 void setProperties(const QMap<QString,QVariant> &properties);
89 void updateProperty(const QString &key, const QVariant &value);94 void updateProperty(const QString &key, const QVariant &value);
@@ -100,31 +105,34 @@
100 void setDiscoverable(bool discoverable);105 void setDiscoverable(bool discoverable);
101 void setPowered(bool powered);106 void setPowered(bool powered);
102107
103 QScopedPointer<QDBusInterface> m_bluezAdapter;108 QScopedPointer<BluezAdapter1> m_bluezAdapter;
109 QScopedPointer<FreeDesktopProperties> m_bluezAdapterProperties;
110
104 void clearAdapter();111 void clearAdapter();
105 void setAdapterFromPath(const QString &objectPath);112 void setAdapterFromPath(const QString &objectPath, const QVariantMap &properties);
106113
107 QList<QSharedPointer<Device> > m_devices;114 QList<QSharedPointer<Device> > m_devices;
108 void updateDevices();115 void updateDevices();
109 void addDevice(QSharedPointer<Device> &device);116 void addDevice(QSharedPointer<Device> &device);
110 void addDevice(const QString &objectPath);117 void addDevice(const QString &objectPath, const QVariantMap &properties);
111 void removeRow(int i);118 void removeRow(int i);
112 int findRowFromAddress(const QString &address) const;119 int findRowFromAddress(const QString &address) const;
113 void emitRowChanged(int row);120 void emitRowChanged(int row);
114121
122 void setDiscovering(bool value);
123 void setupAsDefaultAgent();
124
115private Q_SLOTS:125private Q_SLOTS:
116 void slotCreateFinished(QDBusPendingCallWatcher *call);126 void slotInterfacesAdded(const QDBusObjectPath &objectPath, InterfaceList ifacesAndProps);
127 void slotInterfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces);
128 void slotAdapterPropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
129 const QStringList &invalidatedProperties);
117 void slotRemoveFinished(QDBusPendingCallWatcher *call);130 void slotRemoveFinished(QDBusPendingCallWatcher *call);
118 void slotPropertyChanged(const QString &key, const QDBusVariant &value);131 void slotPropertyChanged(const QString &key, const QDBusVariant &value);
119 void slotTimeout();132 void slotTimeout();
120 void slotEnableDiscoverable();133 void slotEnableDiscoverable();
121 void slotDeviceChanged();134 void slotDeviceChanged();
122 void slotDeviceCreated(const QDBusObjectPath &);135 void slotDevicePairingDone(bool success);
123 void slotDeviceRemoved(const QDBusObjectPath &);
124 void slotDeviceFound(const QString &, const QMap<QString,QVariant>&);
125 void slotDeviceDisappeared(const QString&);
126 void slotDefaultAdapterChanged(const QDBusObjectPath&);
127 void slotAdapterRemoved(const QDBusObjectPath& path);
128};136};
129137
130class DeviceFilter: public QSortFilterProxyModel138class DeviceFilter: public QSortFilterProxyModel
131139
=== added file 'plugins/bluetooth/freedesktop_objectmanager.cpp'
--- plugins/bluetooth/freedesktop_objectmanager.cpp 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/freedesktop_objectmanager.cpp 2015-11-20 08:48:08 +0000
@@ -0,0 +1,26 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -p freedesktop_objectmanager -i bluez_helper.h -v -c DBusObjectManagerInterface org.freedesktop.DBus.ObjectManager.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * This file may have been hand-edited. Look for HAND-EDIT comments
9 * before re-generating it.
10 */
11
12#include "freedesktop_objectmanager.h"
13
14/*
15 * Implementation of interface class DBusObjectManagerInterface
16 */
17
18DBusObjectManagerInterface::DBusObjectManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
19 : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
20{
21}
22
23DBusObjectManagerInterface::~DBusObjectManagerInterface()
24{
25}
26
027
=== added file 'plugins/bluetooth/freedesktop_objectmanager.h'
--- plugins/bluetooth/freedesktop_objectmanager.h 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/freedesktop_objectmanager.h 2015-11-20 08:48:08 +0000
@@ -0,0 +1,58 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -p freedesktop_objectmanager -i bluez_helper.h -v -c DBusObjectManagerInterface org.freedesktop.DBus.ObjectManager.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * Do not edit! All changes made to it will be lost.
9 */
10
11#ifndef FREEDESKTOP_OBJECTMANAGER_H_1442473386
12#define FREEDESKTOP_OBJECTMANAGER_H_1442473386
13
14#include <QtCore/QObject>
15#include <QtCore/QByteArray>
16#include <QtCore/QList>
17#include <QtCore/QMap>
18#include <QtCore/QString>
19#include <QtCore/QStringList>
20#include <QtCore/QVariant>
21#include <QtDBus/QtDBus>
22#include "bluez_helper.h"
23
24/*
25 * Proxy class for interface org.freedesktop.DBus.ObjectManager
26 */
27class DBusObjectManagerInterface: public QDBusAbstractInterface
28{
29 Q_OBJECT
30public:
31 static inline const char *staticInterfaceName()
32 { return "org.freedesktop.DBus.ObjectManager"; }
33
34public:
35 DBusObjectManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
36
37 ~DBusObjectManagerInterface();
38
39public Q_SLOTS: // METHODS
40 inline QDBusPendingReply<ManagedObjectList> GetManagedObjects()
41 {
42 QList<QVariant> argumentList;
43 return asyncCallWithArgumentList(QStringLiteral("GetManagedObjects"), argumentList);
44 }
45
46Q_SIGNALS: // SIGNALS
47 void InterfacesAdded(const QDBusObjectPath &object_path, InterfaceList interfaces_and_properties);
48 void InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces);
49};
50
51namespace org {
52 namespace freedesktop {
53 namespace DBus {
54 typedef ::DBusObjectManagerInterface ObjectManager;
55 }
56 }
57}
58#endif
059
=== added file 'plugins/bluetooth/freedesktop_properties.cpp'
--- plugins/bluetooth/freedesktop_properties.cpp 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/freedesktop_properties.cpp 2015-11-20 08:48:08 +0000
@@ -0,0 +1,26 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -c FreeDesktopProperties -p freedesktop_properties -v org.freedesktop.DBus.Properties.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * This file may have been hand-edited. Look for HAND-EDIT comments
9 * before re-generating it.
10 */
11
12#include "freedesktop_properties.h"
13
14/*
15 * Implementation of interface class FreeDesktopProperties
16 */
17
18FreeDesktopProperties::FreeDesktopProperties(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
19 : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
20{
21}
22
23FreeDesktopProperties::~FreeDesktopProperties()
24{
25}
26
027
=== added file 'plugins/bluetooth/freedesktop_properties.h'
--- plugins/bluetooth/freedesktop_properties.h 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/freedesktop_properties.h 2015-11-20 08:48:08 +0000
@@ -0,0 +1,71 @@
1/*
2 * This file was generated by qdbusxml2cpp version 0.8
3 * Command line was: qdbusxml2cpp -c FreeDesktopProperties -p freedesktop_properties -v org.freedesktop.DBus.Properties.xml
4 *
5 * qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
6 *
7 * This is an auto-generated file.
8 * Do not edit! All changes made to it will be lost.
9 */
10
11#ifndef FREEDESKTOP_PROPERTIES_H_1442473392
12#define FREEDESKTOP_PROPERTIES_H_1442473392
13
14#include <QtCore/QObject>
15#include <QtCore/QByteArray>
16#include <QtCore/QList>
17#include <QtCore/QMap>
18#include <QtCore/QString>
19#include <QtCore/QStringList>
20#include <QtCore/QVariant>
21#include <QtDBus/QtDBus>
22
23/*
24 * Proxy class for interface org.freedesktop.DBus.Properties
25 */
26class FreeDesktopProperties: public QDBusAbstractInterface
27{
28 Q_OBJECT
29public:
30 static inline const char *staticInterfaceName()
31 { return "org.freedesktop.DBus.Properties"; }
32
33public:
34 FreeDesktopProperties(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
35
36 ~FreeDesktopProperties();
37
38public Q_SLOTS: // METHODS
39 inline QDBusPendingReply<QDBusVariant> Get(const QString &interface, const QString &name)
40 {
41 QList<QVariant> argumentList;
42 argumentList << QVariant::fromValue(interface) << QVariant::fromValue(name);
43 return asyncCallWithArgumentList(QStringLiteral("Get"), argumentList);
44 }
45
46 inline QDBusPendingReply<QVariantMap> GetAll(const QString &interface)
47 {
48 QList<QVariant> argumentList;
49 argumentList << QVariant::fromValue(interface);
50 return asyncCallWithArgumentList(QStringLiteral("GetAll"), argumentList);
51 }
52
53 inline QDBusPendingReply<> Set(const QString &interface, const QString &name, const QDBusVariant &value)
54 {
55 QList<QVariant> argumentList;
56 argumentList << QVariant::fromValue(interface) << QVariant::fromValue(name) << QVariant::fromValue(value);
57 return asyncCallWithArgumentList(QStringLiteral("Set"), argumentList);
58 }
59
60Q_SIGNALS: // SIGNALS
61 void PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, const QStringList &invalidated_properties);
62};
63
64namespace org {
65 namespace freedesktop {
66 namespace DBus {
67 typedef ::FreeDesktopProperties Properties;
68 }
69 }
70}
71#endif
072
=== added file 'plugins/bluetooth/org.bluez.Adapter1.xml'
--- plugins/bluetooth/org.bluez.Adapter1.xml 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/org.bluez.Adapter1.xml 2015-11-20 08:48:08 +0000
@@ -0,0 +1,11 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.bluez.Adapter1">
5 <method name="StartDiscovery"></method>
6 <method name="StopDiscovery"></method>
7 <method name="RemoveDevice">
8 <arg name="device" type="o" direction="in"/>
9 </method>
10 </interface>
11</node>
012
=== added file 'plugins/bluetooth/org.bluez.Agent1.xml'
--- plugins/bluetooth/org.bluez.Agent1.xml 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/org.bluez.Agent1.xml 2015-11-20 08:48:08 +0000
@@ -0,0 +1,55 @@
1<?xml version="1.0" encoding="UTF-8" ?>
2
3<node name="/">
4 <interface name="org.bluez.Agent1">
5 <method name="RequestPinCode">
6 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
7 <arg type="o" name="device"/>
8 <arg type="s" name="pincode" direction="out"/>
9 </method>
10
11 <method name="DisplayPinCode">
12 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
13 <arg type="o" name="device"/>
14 <arg type="s" name="pincode"/>
15 </method>
16
17 <method name="RequestPasskey">
18 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
19 <arg type="o" name="device"/>
20 <arg type="u" name="passkey" direction="out"/>
21 </method>
22
23 <method name="DisplayPasskey">
24 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
25 <arg type="o" name="device"/>
26 <arg type="u" name="passkey"/>
27 <arg type="q" name="entered"/>
28 </method>
29
30 <method name="RequestConfirmation">
31 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
32 <arg type="o" name="device"/>
33 <arg type="u" name="passkey"/>
34 </method>
35
36 <method name="RequestAuthorization">
37 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
38 <arg type="o" name="device"/>
39 </method>
40
41 <method name="AuthorizeService">
42 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
43 <arg type="o" name="device"/>
44 <arg type="s" name="uuid"/>
45 </method>
46
47 <method name="Cancel">
48 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
49 </method>
50
51 <method name="Release">
52 <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
53 </method>
54 </interface>
55</node>
056
=== added file 'plugins/bluetooth/org.bluez.AgentManager1.xml'
--- plugins/bluetooth/org.bluez.AgentManager1.xml 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/org.bluez.AgentManager1.xml 2015-11-20 08:48:08 +0000
@@ -0,0 +1,16 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.bluez.AgentManager1">
5 <method name="RegisterAgent">
6 <arg type="o" name="agent"/>
7 <arg type="s" name="capability"/>
8 </method>
9 <method name="UnregisterAgent">
10 <arg type="o" name="agent"/>
11 </method>
12 <method name="RequestDefaultAgent">
13 <arg type="o" name="agent"/>
14 </method>
15 </interface>
16</node>
017
=== added file 'plugins/bluetooth/org.bluez.Device1.xml'
--- plugins/bluetooth/org.bluez.Device1.xml 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/org.bluez.Device1.xml 2015-11-20 08:48:08 +0000
@@ -0,0 +1,16 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.bluez.Device1">
5 <method name="Disconnect"></method>
6 <method name="Connect"></method>
7 <method name="ConnectProfile">
8 <arg name="UUID" type="s" direction="in"/>
9 </method>
10 <method name="DisconnectProfile">
11 <arg name="UUID" type="s" direction="in"/>
12 </method>
13 <method name="Pair"></method>
14 <method name="CancelPairing"></method>
15 </interface>
16</node>
017
=== added file 'plugins/bluetooth/org.freedesktop.DBus.ObjectManager.xml'
--- plugins/bluetooth/org.freedesktop.DBus.ObjectManager.xml 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/org.freedesktop.DBus.ObjectManager.xml 2015-11-20 08:48:08 +0000
@@ -0,0 +1,19 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
4 <interface name="org.freedesktop.DBus.ObjectManager">
5 <method name="GetManagedObjects">
6 <arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
7 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ManagedObjectList"/>
8 </method>
9 <signal name="InterfacesAdded">
10 <arg type="o" name="object_path"/>
11 <arg type="a{sa{sv}}" name="interfaces_and_properties"/>
12 <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="InterfaceList"/>
13 </signal>
14 <signal name="InterfacesRemoved">
15 <arg type="o" name="object_path"/>
16 <arg type="as" name="interfaces"/>
17 </signal>
18 </interface>
19</node>
020
=== added file 'plugins/bluetooth/org.freedesktop.DBus.Properties.xml'
--- plugins/bluetooth/org.freedesktop.DBus.Properties.xml 1970-01-01 00:00:00 +0000
+++ plugins/bluetooth/org.freedesktop.DBus.Properties.xml 2015-11-20 08:48:08 +0000
@@ -0,0 +1,27 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.freedesktop.DBus.Properties">
5 <method name="Get">
6 <arg name="interface" type="s" direction="in"/>
7 <arg name="name" type="s" direction="in"/>
8 <arg name="value" type="v" direction="out"/>
9 </method>
10 <method name="Set">
11 <arg name="interface" type="s" direction="in"/>
12 <arg name="name" type="s" direction="in"/>
13 <arg name="value" type="v" direction="in"/>
14 </method>
15 <method name="GetAll">
16 <arg name="interface" type="s" direction="in"/>
17 <arg name="properties" type="a{sv}" direction="out"/>
18 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
19 </method>
20 <signal name="PropertiesChanged">
21 <arg name="interface" type="s"/>
22 <arg name="changed_properties" type="a{sv}"/>
23 <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
24 <arg name="invalidated_properties" type="as"/>
25 </signal>
26 </interface>
27</node>
028
=== modified file 'plugins/bluetooth/plugin.cpp'
--- plugins/bluetooth/plugin.cpp 2015-08-28 09:32:38 +0000
+++ plugins/bluetooth/plugin.cpp 2015-11-20 08:48:08 +0000
@@ -24,11 +24,17 @@
24#include <QtQml/QQmlContext>24#include <QtQml/QQmlContext>
25#include "bluetooth.h"25#include "bluetooth.h"
26#include "device.h"26#include "device.h"
27#include "bluez_helper.h"
2728
28void BackendPlugin::registerTypes(const char *uri)29void BackendPlugin::registerTypes(const char *uri)
29{30{
30 Q_ASSERT(uri == QLatin1String("Ubuntu.SystemSettings.Bluetooth"));31 Q_ASSERT(uri == QLatin1String("Ubuntu.SystemSettings.Bluetooth"));
3132
33 // Register additional QtDBus types we need
34 qDBusRegisterMetaType<InterfaceList>();
35 qDBusRegisterMetaType<ManagedObjectList>();
36
37 // .. now register our real QML types
32 qmlRegisterType<Bluetooth>(uri, 1, 0, "UbuntuBluetoothPanel");38 qmlRegisterType<Bluetooth>(uri, 1, 0, "UbuntuBluetoothPanel");
33 qmlRegisterType<Device>(uri, 1, 0, "Device");39 qmlRegisterType<Device>(uri, 1, 0, "Device");
34 qmlRegisterType<Device>(uri, 1, 0, "Agent");40 qmlRegisterType<Device>(uri, 1, 0, "Agent");
3541
=== modified file 'tests/plugins/bluetooth/CMakeLists.txt'
--- tests/plugins/bluetooth/CMakeLists.txt 2014-07-29 20:45:24 +0000
+++ tests/plugins/bluetooth/CMakeLists.txt 2015-11-20 08:48:08 +0000
@@ -4,14 +4,23 @@
4include_directories(${QTDBUSTEST_INCLUDE_DIRS})4include_directories(${QTDBUSTEST_INCLUDE_DIRS})
5add_definitions(-DTESTS)5add_definitions(-DTESTS)
66
7set(PLUGIN_SOURCES
8 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluetooth.cpp
9 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/devicemodel.cpp
10 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/device.cpp
11 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agent.cpp
12 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluez_agent1adaptor.cpp
13 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluez_agentmanager1.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluez_device1.cpp
15 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluez_adapter1.cpp
16 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/freedesktop_objectmanager.cpp
17 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/freedesktop_properties.cpp
18)
19
7add_executable(tst-bluetooth20add_executable(tst-bluetooth
8 tst_bluetooth.cpp21 tst_bluetooth.cpp
9 fakebluez.cpp22 fakebluez.cpp
10 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluetooth.cpp23 ${PLUGIN_SOURCES}
11 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/devicemodel.cpp
12 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/device.cpp
13 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agent.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agentadaptor.cpp
15)24)
1625
17target_link_libraries(tst-bluetooth26target_link_libraries(tst-bluetooth
@@ -22,11 +31,7 @@
22add_executable(tst-bluetooth-devicemodel31add_executable(tst-bluetooth-devicemodel
23 tst_devicemodel.cpp32 tst_devicemodel.cpp
24 fakebluez.cpp33 fakebluez.cpp
25 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluetooth.cpp34 ${PLUGIN_SOURCES}
26 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/devicemodel.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/device.cpp
28 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agent.cpp
29 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agentadaptor.cpp
30)35)
3136
32target_link_libraries(tst-bluetooth-devicemodel37target_link_libraries(tst-bluetooth-devicemodel
@@ -35,13 +40,9 @@
35)40)
3641
37add_executable(tst-bluetooth-device42add_executable(tst-bluetooth-device
38 tst_devicemodel.cpp43 tst_device.cpp
39 fakebluez.cpp44 fakebluez.cpp
40 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/bluetooth.cpp45 ${PLUGIN_SOURCES}
41 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/devicemodel.cpp
42 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/device.cpp
43 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agent.cpp
44 ${CMAKE_SOURCE_DIR}/plugins/bluetooth/agentadaptor.cpp
45)46)
4647
47target_link_libraries(tst-bluetooth-device48target_link_libraries(tst-bluetooth-device
4849
=== modified file 'tests/plugins/bluetooth/fakebluez.cpp'
--- tests/plugins/bluetooth/fakebluez.cpp 2014-07-29 20:53:16 +0000
+++ tests/plugins/bluetooth/fakebluez.cpp 2015-11-20 08:48:08 +0000
@@ -29,7 +29,7 @@
29{29{
30 DBusMock::registerMetaTypes();30 DBusMock::registerMetaTypes();
3131
32 m_dbusMock.registerTemplate(BLUEZ_SERVICE, "bluez4",32 m_dbusMock.registerTemplate(BLUEZ_SERVICE, "bluez5",
33 QDBusConnection::SystemBus);33 QDBusConnection::SystemBus);
34 m_dbusTestRunner.startServices();34 m_dbusTestRunner.startServices();
3535
@@ -75,13 +75,49 @@
75 return reply.isValid() ? reply.value() : QString();75 return reply.isValid() ? reply.value() : QString();
76}76}
7777
78void
79FakeBluez::pairDevice(const QString &address)
80{
81 QDBusReply<void> reply = m_bluezMock->call("PairDevice",
82 m_currentAdapter,
83 address);
84
85 if (!reply.isValid()) {
86 qWarning() << "Failed to pair mock device:" << reply.error().message();
87 }
88}
89
90void
91FakeBluez::connectDevice(const QString &address)
92{
93 QDBusReply<void> reply = m_bluezMock->call("ConnectDevice",
94 m_currentAdapter,
95 address);
96
97 if (!reply.isValid()) {
98 qWarning() << "Failed to connect mock device:" << reply.error().message();
99 }
100}
101
102void
103FakeBluez::disconnectDevice(const QString &address)
104{
105 QDBusReply<void> reply = m_bluezMock->call("DisconnectDevice",
106 m_currentAdapter,
107 address);
108
109 if (!reply.isValid()) {
110 qWarning() << "Failed to disconnect mock device:" << reply.error().message();
111 }
112}
113
78QVariant114QVariant
79FakeBluez::getProperty(const QString &path,115FakeBluez::getProperty(const QString &path,
80 const QString &interface,116 const QString &interface,
81 const QString &property)117 const QString &property)
82{118{
83 QDBusInterface iface(BLUEZ_SERVICE, path,119 QDBusInterface iface(BLUEZ_SERVICE, path,
84 "org.freedesktop.DBus.Properties",120 FREEDESKTOP_PROPERTIES_IFACE,
85 m_dbusTestRunner.systemConnection());121 m_dbusTestRunner.systemConnection());
86122
87 QDBusReply<QVariant> reply = iface.call("Get", interface, property);123 QDBusReply<QVariant> reply = iface.call("Get", interface, property);
@@ -103,10 +139,11 @@
103 const QVariant &value)139 const QVariant &value)
104{140{
105 QDBusInterface iface(BLUEZ_SERVICE, path,141 QDBusInterface iface(BLUEZ_SERVICE, path,
106 interface,142 FREEDESKTOP_PROPERTIES_IFACE,
107 m_dbusTestRunner.systemConnection());143 m_dbusTestRunner.systemConnection());
108144
109 QDBusReply<void> reply = iface.call("SetProperty",145 QDBusReply<void> reply = iface.call("Set",
146 interface,
110 property, value);147 property, value);
111148
112 if (!reply.isValid()) {149 if (!reply.isValid()) {
113150
=== modified file 'tests/plugins/bluetooth/fakebluez.h'
--- tests/plugins/bluetooth/fakebluez.h 2014-07-29 20:53:16 +0000
+++ tests/plugins/bluetooth/fakebluez.h 2015-11-20 08:48:08 +0000
@@ -32,10 +32,10 @@
32#define BLUEZ_MAIN_OBJECT "/"32#define BLUEZ_MAIN_OBJECT "/"
33#define BLUEZ_MOCK_IFACE "org.bluez.Mock"33#define BLUEZ_MOCK_IFACE "org.bluez.Mock"
3434
35#define BLUEZ_MANAGER_IFACE "org.bluez.Manager"35#define BLUEZ_ADAPTER_IFACE "org.bluez.Adapter1"
36#define BLUEZ_ADAPTER_IFACE "org.bluez.Adapter"36#define BLUEZ_DEVICE_IFACE "org.bluez.Device1"
37#define BLUEZ_DEVICE_IFACE "org.bluez.Device"37
38#define BLUEZ_AUDIO_IFACE "org.bluez.Audio"38#define FREEDESKTOP_PROPERTIES_IFACE "org.freedesktop.DBus.Properties"
3939
40using namespace QtDBusTest;40using namespace QtDBusTest;
41using namespace QtDBusMock;41using namespace QtDBusMock;
@@ -61,17 +61,20 @@
6161
62 ~FakeBluez();62 ~FakeBluez();
6363
64 const QString currentAdapter() { return m_currentAdapter; }64 const QString currentAdapterPath() { return QString("/org/bluez/%1").arg(m_currentAdapter); }
65 const QList<QString> devices() { return m_devices; }65 const QList<QString> devices() { return m_devices; }
66 const QDBusConnection & dbus() { return m_dbusTestRunner.systemConnection(); }66 const QDBusConnection & dbus() { return m_dbusTestRunner.systemConnection(); }
6767
68 QString addAdapter(const QString &name, const QString &system_name);68 QString addAdapter(const QString &name, const QString &system_name);
69 QString addDevice(const QString &name, const QString &address);69 QString addDevice(const QString &name, const QString &address);
70 void pairDevice(const QString &address);
71 void connectDevice(const QString &address);
72 void disconnectDevice(const QString &address);
7073
71 QVariant getProperty(const QString &path,74 QVariant getProperty(const QString &path,
72 const QString &interface,75 const QString &interface,
73 const QString &property);76 const QString &property);
74 77
75 void setProperty(const QString &path,78 void setProperty(const QString &path,
76 const QString &interface,79 const QString &interface,
77 const QString &property,80 const QString &property,
7881
=== modified file 'tests/plugins/bluetooth/tst_bluetooth.cpp'
--- tests/plugins/bluetooth/tst_bluetooth.cpp 2015-02-10 11:19:53 +0000
+++ tests/plugins/bluetooth/tst_bluetooth.cpp 2015-11-20 08:48:08 +0000
@@ -23,6 +23,7 @@
23#include "bluetooth.h"23#include "bluetooth.h"
24#include "device.h"24#include "device.h"
25#include "agent.h"25#include "agent.h"
26#include "bluez_helper.h"
26#include "fakebluez.h"27#include "fakebluez.h"
2728
28using namespace Bluez;29using namespace Bluez;
@@ -36,6 +37,9 @@
36 Bluetooth *m_bluetooth;37 Bluetooth *m_bluetooth;
37 QDBusConnection *m_dbus;38 QDBusConnection *m_dbus;
3839
40 void processEvents(unsigned int msecs = 500);
41 void setDiscovering(bool value);
42
39private Q_SLOTS:43private Q_SLOTS:
40 void init();44 void init();
41 void testGotAdapter();45 void testGotAdapter();
@@ -48,16 +52,38 @@
4852
49};53};
5054
55void BluetoothTest::processEvents(unsigned int msecs)
56{
57 QTimer::singleShot(msecs, [=]() { QCoreApplication::instance()->exit(); });
58 QCoreApplication::instance()->exec();
59}
60
61void BluetoothTest::setDiscovering(bool value)
62{
63 m_bluezMock->setProperty(m_bluezMock->currentAdapterPath(),
64 BLUEZ_ADAPTER_IFACE,
65 "Discovering",
66 QVariant(value));
67}
68
51void BluetoothTest::init()69void BluetoothTest::init()
52{70{
71 qWarning() << "init test";
72
73 qDBusRegisterMetaType<InterfaceList>();
74 qDBusRegisterMetaType<ManagedObjectList>();
75
53 m_bluezMock = new FakeBluez();76 m_bluezMock = new FakeBluez();
54 m_bluezMock->addAdapter("new0", "bluetoothTest");77 m_bluezMock->addAdapter("new0", "bluetoothTest");
55 m_dbus = new QDBusConnection(m_bluezMock->dbus());78 m_dbus = new QDBusConnection(m_bluezMock->dbus());
56 m_bluetooth = new Bluetooth(*m_dbus);79 m_bluetooth = new Bluetooth(*m_dbus);
80
81 processEvents();
57}82}
5883
59void BluetoothTest::cleanup()84void BluetoothTest::cleanup()
60{85{
86 qWarning() << "cleanup";
61 delete m_bluezMock;87 delete m_bluezMock;
62 delete m_bluetooth;88 delete m_bluetooth;
63}89}
@@ -67,6 +93,8 @@
67 QString expected = "bluetoothTest";93 QString expected = "bluetoothTest";
68 QString result;94 QString result;
6995
96 processEvents();
97
70 result = m_bluetooth->adapterName();98 result = m_bluetooth->adapterName();
7199
72 QCOMPARE(result, expected);100 QCOMPARE(result, expected);
@@ -74,70 +102,100 @@
74102
75void BluetoothTest::testStartDiscovery()103void BluetoothTest::testStartDiscovery()
76{104{
77 bool expected = true;
78 QVariant result;105 QVariant result;
79106
80 QSKIP("Fails due to a bug in bluez4 dbusmock template", SkipAll);107 // This is what our test expects the adapter to have set
108 setDiscovering(false);
109 processEvents();
81110
82 result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),111 result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
83 "org.bluez.Adapter",112 BLUEZ_ADAPTER_IFACE,
84 "Discovering");113 "Discovering");
85 qWarning() << result;114 qWarning() << result;
86 QCOMPARE(result.toBool(), !expected);115 QCOMPARE(result.toBool(), false);
87116
88 m_bluetooth->startDiscovery();117 m_bluetooth->startDiscovery();
89118 setDiscovering(true);
90 result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),119
91 "org.bluez.Adapter",120 processEvents();
121
122 result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
123 BLUEZ_ADAPTER_IFACE,
92 "Discovering");124 "Discovering");
93 qWarning() << result;125 qWarning() << result;
94 QCOMPARE(result.toBool(), expected);126 QCOMPARE(result.toBool(), true);
95}127}
96128
97void BluetoothTest::testStopDiscovery()129void BluetoothTest::testStopDiscovery()
98{130{
99 bool expected = false;
100 QVariant result;131 QVariant result;
101132
102 QSKIP("Fails due to a bug in bluez4 dbusmock template", SkipAll);133 // This is what our test expects the adapter to have set
134 setDiscovering(true);
135 processEvents();
103136
104 result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),137 result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
105 "org.bluez.Adapter",138 BLUEZ_ADAPTER_IFACE,
106 "Discovering");139 "Discovering");
107 QCOMPARE(result.toBool(), !expected);140 QCOMPARE(result.toBool(), true);
108141
109 m_bluetooth->stopDiscovery();142 m_bluetooth->stopDiscovery();
110143 setDiscovering(false);
111 result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),144
112 "org.bluez.Adapter",145 processEvents();
146
147 result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
148 BLUEZ_ADAPTER_IFACE,
113 "Discovering");149 "Discovering");
114 QCOMPARE(result.toBool(), expected);150 QCOMPARE(result.toBool(), false);
115}151}
116152
153/*
154 * NOTE: The bluez5 mock template currently doesn't send PropertiesChanged
155 * events when StartDiscovery/StopDiscovery is called on the adapter interface.
156 * To accomondate this we're calling the org.freedesktop.DBus.Properties.Set
157 * method here manually to simulate a property change. However this means
158 * that other than doing a dumb call to StartDiscovery/StopDiscovery nothing
159 * else will happen when those methods are called of the Bluetooth class we're
160 * testing here.
161 *
162 * This affects the following tested methods:
163 * - Bluetooth::startDiscovering
164 * - Bluetooth::stopDiscovery
165 * - Bluetooth::toggleDiscovery
166 */
167
117void BluetoothTest::testToggleDiscovery()168void BluetoothTest::testToggleDiscovery()
118{169{
119 QVariant result;170 QVariant result;
120171
121 QSKIP("Fails due to a bug in bluez4 dbusmock template", SkipAll);
122
123 m_bluetooth->stopDiscovery();172 m_bluetooth->stopDiscovery();
124173 setDiscovering(false);
125 result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),174
126 "org.bluez.Adapter",175 processEvents();
176
177 result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
178 BLUEZ_ADAPTER_IFACE,
127 "Discovering");179 "Discovering");
128 QCOMPARE(result.toBool(), false);180 QCOMPARE(result.toBool(), false);
129181
130 m_bluetooth->toggleDiscovery();182 m_bluetooth->toggleDiscovery();
131183 setDiscovering(true);
132 result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),184
133 "org.bluez.Adapter",185 processEvents();
186
187 result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
188 BLUEZ_ADAPTER_IFACE,
134 "Discovering");189 "Discovering");
135 QCOMPARE(result.toBool(), true);190 QCOMPARE(result.toBool(), true);
136191
137 m_bluetooth->toggleDiscovery();192 m_bluetooth->toggleDiscovery();
138193 setDiscovering(false);
139 result = m_bluezMock->getProperty(m_bluezMock->currentAdapter(),194
140 "org.bluez.Adapter",195 processEvents();
196
197 result = m_bluezMock->getProperty(m_bluezMock->currentAdapterPath(),
198 BLUEZ_ADAPTER_IFACE,
141 "Discovering");199 "Discovering");
142 QCOMPARE(result.toBool(), false);200 QCOMPARE(result.toBool(), false);
143}201}
@@ -149,21 +207,34 @@
149 QCOMPARE(Bluetooth::isSupportedType(Device::Type::Tablet), false);207 QCOMPARE(Bluetooth::isSupportedType(Device::Type::Tablet), false);
150}208}
151209
210
152void BluetoothTest::testIsDiscovering()211void BluetoothTest::testIsDiscovering()
153{212{
154 m_bluetooth->stopDiscovery();213 m_bluetooth->stopDiscovery();
214 setDiscovering(false);
215
216 processEvents();
155217
156 QCOMPARE(m_bluetooth->isDiscovering(), false);218 QCOMPARE(m_bluetooth->isDiscovering(), false);
157219
158 m_bluetooth->startDiscovery();220 m_bluetooth->startDiscovery();
221 setDiscovering(true);
222
223 processEvents();
159224
160 QCOMPARE(m_bluetooth->isDiscovering(), true);225 QCOMPARE(m_bluetooth->isDiscovering(), true);
161226
162 m_bluetooth->toggleDiscovery();227 m_bluetooth->toggleDiscovery();
228 setDiscovering(false);
229
230 processEvents();
163231
164 QCOMPARE(m_bluetooth->isDiscovering(), false);232 QCOMPARE(m_bluetooth->isDiscovering(), false);
165233
166 m_bluetooth->toggleDiscovery();234 m_bluetooth->toggleDiscovery();
235 setDiscovering(true);
236
237 processEvents();
167238
168 QCOMPARE(m_bluetooth->isDiscovering(), true);239 QCOMPARE(m_bluetooth->isDiscovering(), true);
169}240}
170241
=== modified file 'tests/plugins/bluetooth/tst_device.cpp'
--- tests/plugins/bluetooth/tst_device.cpp 2015-08-25 16:41:10 +0000
+++ tests/plugins/bluetooth/tst_device.cpp 2015-11-20 08:48:08 +0000
@@ -36,7 +36,7 @@
36 QDBusConnection *m_dbus;36 QDBusConnection *m_dbus;
3737
38private:38private:
39 void checkAudioState(const QString &expected);39 void processEvents(unsigned int msecs = 500);
4040
41private Q_SLOTS:41private Q_SLOTS:
42 void init();42 void init();
@@ -50,16 +50,29 @@
50 void testGetStrength();50 void testGetStrength();
51 void testGetPath();51 void testGetPath();
52 void testMakeTrusted();52 void testMakeTrusted();
53 53 void testConnect();
54 void testDisconnect();
55
54 void cleanup();56 void cleanup();
5557
56};58};
5759
60void DeviceTest::processEvents(unsigned int msecs)
61{
62 QTimer::singleShot(msecs, [=]() { QCoreApplication::instance()->exit(); });
63 QCoreApplication::instance()->exec();
64}
65
58void DeviceTest::init()66void DeviceTest::init()
59{67{
68 qDBusRegisterMetaType<InterfaceList>();
69 qDBusRegisterMetaType<ManagedObjectList>();
70
60 m_bluezMock = new FakeBluez();71 m_bluezMock = new FakeBluez();
61 m_bluezMock->addAdapter("new0", "bluetoothTest");72 m_bluezMock->addAdapter("new0", "bluetoothTest");
62 m_bluezMock->addDevice("My Phone", "00:00:de:ad:be:ef");73 m_bluezMock->addDevice("My Phone", "00:00:de:ad:be:ef");
74 // Only this will set the 'Class' and 'Icon' properties for the device ...
75 m_bluezMock->pairDevice("00:00:de:ad:be:ef");
63 m_dbus = new QDBusConnection(m_bluezMock->dbus());76 m_dbus = new QDBusConnection(m_bluezMock->dbus());
6477
65 QList<QString> devices = m_bluezMock->devices();78 QList<QString> devices = m_bluezMock->devices();
@@ -67,6 +80,8 @@
67 QFAIL("No devices in mock to be tested.");80 QFAIL("No devices in mock to be tested.");
6881
69 m_device = new Device(devices.first(), *m_dbus);82 m_device = new Device(devices.first(), *m_dbus);
83
84 processEvents();
70}85}
7186
72void DeviceTest::cleanup()87void DeviceTest::cleanup()
@@ -77,29 +92,37 @@
7792
78void DeviceTest::testGetName()93void DeviceTest::testGetName()
79{94{
80 QCOMPARE(m_device->getName(), "My Phone");95 QCOMPARE(m_device->getName(), QString("My Phone"));
81}96}
8297
83void DeviceTest::testAddress()98void DeviceTest::testGetAddress()
84{99{
85 QCOMPARE(m_device->getAddress(), "00:00:de:ad:be:ef");100 QCOMPARE(m_device->getAddress(), QString("00:00:de:ad:be:ef"));
86}101}
87102
88void DeviceTest::testIconName()103void DeviceTest::testGetIconName()
89{104{
90 QCOMPARE(m_device->getIconName(), "image://theme/audio-headset");105 QCOMPARE(m_device->getIconName(), QString("image://theme/phone-smartphone-symbolic"));
91}106}
92107
93void DeviceTest::testGetType()108void DeviceTest::testGetType()
94{109{
95 QCOMPARE(m_device->getType(), Device::Type::Headset);110 QCOMPARE(m_device->getType(), Device::Type::Smartphone);
96}111}
97112
98void DeviceTest::testIsPaired()113void DeviceTest::testIsPaired()
99{114{
115 QCOMPARE(m_device->isPaired(), true);
116
117 m_bluezMock->setProperty("/org/bluez/new0/dev_00_00_DE_AD_BE_EF", "org.bluez.Device1", "Paired", QVariant(false));
118
119 processEvents();
120
100 QCOMPARE(m_device->isPaired(), false);121 QCOMPARE(m_device->isPaired(), false);
101122
102 m_bluezMock->setProperty("org.bluez.Device", "Paired", QVariant(true));123 m_bluezMock->setProperty("/org/bluez/new0/dev_00_00_DE_AD_BE_EF", "org.bluez.Device1", "Paired", QVariant(true));
124
125 processEvents();
103126
104 QCOMPARE(m_device->isPaired(), true);127 QCOMPARE(m_device->isPaired(), true);
105}128}
@@ -108,26 +131,28 @@
108{131{
109 QCOMPARE(m_device->isTrusted(), false);132 QCOMPARE(m_device->isTrusted(), false);
110133
111 m_bluezMock->setProperty("org.bluez.Device", "Trusted", QVariant(true));134 m_bluezMock->setProperty("/org/bluez/new0/dev_00_00_DE_AD_BE_EF", "org.bluez.Device1", "Trusted", QVariant(true));
135
136 processEvents();
112137
113 QCOMPARE(m_device->isTrusted(), true);138 QCOMPARE(m_device->isTrusted(), true);
114}139}
115140
116void DeviceTest::testGetConnection()141void DeviceTest::testGetConnection()
117{142{
118 QCOMPARE(m_device.getConnection(), Device::Connection::Disconnected);143 QCOMPARE(m_device->getConnection(), Device::Connection::Disconnected);
119}144}
120145
121void DeviceTest::testGetStrength()146void DeviceTest::testGetStrength()
122{147{
123 QCOMPARE(m_device.getStrength(), Device::Strength::Good);148 QCOMPARE(m_device->getStrength(), Device::Strength::Fair);
124}149}
125150
126void DeviceTest::testGetPath()151void DeviceTest::testGetPath()
127{152{
128 QCOMPARE(m_device.getPath(),153 QCOMPARE(m_device->getPath(),
129 "/org/bluez/" + m_bluezMock->currentAdapter() + "/"154 m_bluezMock->currentAdapterPath() + "/"
130 + "dev_00_00_de_ad_be_ef");155 + "dev_00_00_DE_AD_BE_EF");
131}156}
132157
133void DeviceTest::testMakeTrusted()158void DeviceTest::testMakeTrusted()
@@ -136,52 +161,40 @@
136161
137 m_device->makeTrusted(true);162 m_device->makeTrusted(true);
138163
164 processEvents();
165
139 QCOMPARE(m_device->isTrusted(), true);166 QCOMPARE(m_device->isTrusted(), true);
140167
141 m_device->makeTrusted(false);168 m_device->makeTrusted(false);
142169
170 processEvents();
171
143 QCOMPARE(m_device->isTrusted(), false);172 QCOMPARE(m_device->isTrusted(), false);
144}173}
145174
146void DeviceTest::checkAudioState(const QString &expected)
147{
148 QVariant state = m_bluezMock->getProperty("org.bluez.Audio", "State");
149
150 QVERIFY(state.type() == QMetaType::QString);
151 QCOMPARE(state.toString(), expected);
152}
153
154void DeviceTest::testConnect()175void DeviceTest::testConnect()
155{176{
156 testDiscoverServices();177 m_device->connect();
157178
158 m_device->connect(Device::ConnectionMode::Audio);179 m_bluezMock->connectDevice("00:00:de:ad:be:ef");
159180
160 checkAudioState("connected");181 processEvents();
182
183 QCOMPARE(m_device->getConnection(), Device::Connected);
161}184}
162185
163void DeviceTest::testDisconnect()186void DeviceTest::testDisconnect()
164{187{
165 testConnect();188 testConnect();
166189
167 m_device->disconnect(Device::ConnectionMode::Audio);190 m_device->disconnect();
168191
169 checkAudioState("disconnected");192 m_bluezMock->disconnectDevice("00:00:de:ad:be:ef");
170}193
171194 processEvents();
172void DeviceTest::testConnectPending()195
173{196 QCOMPARE(m_device->getConnection(), Device::Disconnected);
174 testIsPaired();197}
175 testIsTrusted();198
176199QTEST_MAIN(DeviceTest)
177 m_device->addConnectAfterPairing(Device::ConnectionMode::Audio);
178
179 checkAudioState("disconnected");
180
181 m_device->connectPending();
182
183 checkAudioState("connected");
184}
185
186QTEST_MAIN(DeviceTest);
187#include "tst_device.moc"200#include "tst_device.moc"
188201
=== modified file 'tests/plugins/bluetooth/tst_devicemodel.cpp'
--- tests/plugins/bluetooth/tst_devicemodel.cpp 2014-08-20 12:50:09 +0000
+++ tests/plugins/bluetooth/tst_devicemodel.cpp 2015-11-20 08:48:08 +0000
@@ -35,6 +35,9 @@
35 DeviceModel *m_devicemodel;35 DeviceModel *m_devicemodel;
36 QDBusConnection *m_dbus;36 QDBusConnection *m_dbus;
3737
38private:
39 void processEvents(unsigned int msecs = 500);
40
38private Q_SLOTS:41private Q_SLOTS:
39 void init();42 void init();
40 void testDeviceFoundOnStart();43 void testDeviceFoundOnStart();
@@ -45,15 +48,28 @@
4548
46};49};
4750
51void DeviceModelTest::processEvents(unsigned int msecs)
52{
53 QTimer::singleShot(msecs, [=]() { QCoreApplication::instance()->exit(); });
54 QCoreApplication::instance()->exec();
55}
56
48void DeviceModelTest::init()57void DeviceModelTest::init()
49{58{
59 qDBusRegisterMetaType<InterfaceList>();
60 qDBusRegisterMetaType<ManagedObjectList>();
61
50 m_bluezMock = new FakeBluez();62 m_bluezMock = new FakeBluez();
5163
52 m_bluezMock->addAdapter("new0", "bluetoothTest");64 m_bluezMock->addAdapter("new0", "bluetoothTest");
53 m_bluezMock->addDevice("My Phone", "00:00:de:ad:be:ef");65 m_bluezMock->addDevice("My Phone", "00:00:de:ad:be:ef");
66 // Only this will set the 'Class' and 'Icon' properties for the device ...
67 m_bluezMock->pairDevice("00:00:de:ad:be:ef");
5468
55 m_dbus = new QDBusConnection(m_bluezMock->dbus());69 m_dbus = new QDBusConnection(m_bluezMock->dbus());
56 m_devicemodel = new DeviceModel(*m_dbus);70 m_devicemodel = new DeviceModel(*m_dbus);
71
72 processEvents();
57}73}
5874
59void DeviceModelTest::cleanup()75void DeviceModelTest::cleanup()
@@ -64,6 +80,9 @@
6480
65void DeviceModelTest::testDeviceFoundOnStart()81void DeviceModelTest::testDeviceFoundOnStart()
66{82{
83 // FIXME needs to take a bit more time especially on i386
84 processEvents();
85
67 QCOMPARE(m_devicemodel->rowCount(), 1);86 QCOMPARE(m_devicemodel->rowCount(), 1);
68}87}
6988

Subscribers

People subscribed via source and target branches