summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/bluez
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@qt.io>2017-10-17 09:42:01 +0200
committerAlex Blasche <alexander.blasche@qt.io>2017-10-17 09:42:13 +0200
commitfc2a206322f6190226ebc1f04062f2c9170f0bac (patch)
tree7df8ca41816c24ccfa6e0c6add4612689a933bdd /src/bluetooth/bluez
parentca5490859338f28e30104668a353275d23df1ec6 (diff)
parent125cdccc346903d6e70ed26289cdaed85e26ec3f (diff)
Merge remote-tracking branch 'gerrit/dev' into btle
Diffstat (limited to 'src/bluetooth/bluez')
-rw-r--r--src/bluetooth/bluez/adapter1_bluez5.cpp4
-rw-r--r--src/bluetooth/bluez/adapter1_bluez5_p.h23
-rw-r--r--src/bluetooth/bluez/bluetoothmanagement.cpp314
-rw-r--r--src/bluetooth/bluez/bluetoothmanagement_p.h98
-rw-r--r--src/bluetooth/bluez/bluez.pri8
-rw-r--r--src/bluetooth/bluez/bluez5_helper.cpp1
-rw-r--r--src/bluetooth/bluez/bluez5_helper_p.h2
-rw-r--r--src/bluetooth/bluez/bluez_data_p.h11
-rw-r--r--src/bluetooth/bluez/device1_bluez5.cpp3
-rw-r--r--src/bluetooth/bluez/device1_bluez5_p.h38
-rwxr-xr-xsrc/bluetooth/bluez/generate14
-rw-r--r--src/bluetooth/bluez/hcimanager.cpp44
-rw-r--r--src/bluetooth/bluez/hcimanager_p.h4
-rw-r--r--src/bluetooth/bluez/objectmanager_p.h4
-rw-r--r--src/bluetooth/bluez/org.bluez.Adapter1.xml4
-rw-r--r--src/bluetooth/bluez/org.bluez.Device1.xml10
-rw-r--r--src/bluetooth/bluez/remotedevicemanager.cpp170
-rw-r--r--src/bluetooth/bluez/remotedevicemanager_p.h99
18 files changed, 816 insertions, 35 deletions
diff --git a/src/bluetooth/bluez/adapter1_bluez5.cpp b/src/bluetooth/bluez/adapter1_bluez5.cpp
index 0f1e0acd..b1aefc8d 100644
--- a/src/bluetooth/bluez/adapter1_bluez5.cpp
+++ b/src/bluetooth/bluez/adapter1_bluez5.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p adapter1 -v org.bluez.Adapter1.xml
+ * Command line was: qdbusxml2cpp -p adapter1_bluez5_p.h:adapter1_bluez5.cpp org.bluez.Adapter1.xml
*
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
diff --git a/src/bluetooth/bluez/adapter1_bluez5_p.h b/src/bluetooth/bluez/adapter1_bluez5_p.h
index 5568da4c..ce108ad0 100644
--- a/src/bluetooth/bluez/adapter1_bluez5_p.h
+++ b/src/bluetooth/bluez/adapter1_bluez5_p.h
@@ -1,15 +1,15 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p adapter1 -v org.bluez.Adapter1.xml
+ * Command line was: qdbusxml2cpp -p adapter1_bluez5_p.h:adapter1_bluez5.cpp org.bluez.Adapter1.xml
*
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
-#ifndef ADAPTER1_H_1396951555
-#define ADAPTER1_H_1396951555
+#ifndef ADAPTER1_BLUEZ5_P_H
+#define ADAPTER1_BLUEZ5_P_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
@@ -31,7 +31,7 @@ public:
{ return "org.bluez.Adapter1"; }
public:
- OrgBluezAdapter1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
+ OrgBluezAdapter1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
~OrgBluezAdapter1Interface();
@@ -100,19 +100,26 @@ public Q_SLOTS: // METHODS
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(device);
- return asyncCallWithArgumentList(QLatin1String("RemoveDevice"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("RemoveDevice"), argumentList);
+ }
+
+ inline QDBusPendingReply<> SetDiscoveryFilter(const QVariantMap &properties)
+ {
+ QList<QVariant> argumentList;
+ argumentList << QVariant::fromValue(properties);
+ return asyncCallWithArgumentList(QStringLiteral("SetDiscoveryFilter"), argumentList);
}
inline QDBusPendingReply<> StartDiscovery()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("StartDiscovery"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("StartDiscovery"), argumentList);
}
inline QDBusPendingReply<> StopDiscovery()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("StopDiscovery"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("StopDiscovery"), argumentList);
}
Q_SIGNALS: // SIGNALS
diff --git a/src/bluetooth/bluez/bluetoothmanagement.cpp b/src/bluetooth/bluez/bluetoothmanagement.cpp
new file mode 100644
index 00000000..9df74b34
--- /dev/null
+++ b/src/bluetooth/bluez/bluetoothmanagement.cpp
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qsocketnotifier.h>
+#include <QtCore/qtimer.h>
+
+#include "bluetoothmanagement_p.h"
+#include "bluez_data_p.h"
+#include "../qbluetoothsocket_p.h"
+
+#include <unistd.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <linux/capability.h>
+
+
+QT_BEGIN_NAMESPACE
+
+// Packet data structures for Mgmt API bluez.git/doc/mgmt-api.txt
+
+enum class EventCode {
+ DeviceFound = 0x0012,
+};
+
+struct MgmtHdr {
+ quint16 cmdCode;
+ quint16 controllerIndex;
+ quint16 length;
+} __attribute__((packed));
+
+struct MgmtEventDeviceFound {
+ bdaddr_t bdaddr;
+ quint8 type;
+ quint8 rssi;
+ quint32 flags;
+ quint16 eirLength;
+ quint8 eirData[0];
+} __attribute__((packed));
+
+
+/*
+ * This class encapsulates access to the Bluetooth Management API as introduced by
+ * Linux kernel 3.4. Some Bluetooth information is not exposed via the usual DBus
+ * API (e.g. the random/public address type info). In those cases we have to fall back
+ * to this mgmt API.
+ *
+ * Note that opening such a Bluetooth mgmt socket requires CAP_NET_ADMIN (root) capability.
+ *
+ * Documentation can be found in bluez-git/doc/mgmt-api.txt
+ */
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
+// These structs and defines come straight from linux/capability.h.
+// To avoid missing definitions we re-define them if not existing.
+// In addition, we don't want to pull in a libcap2 dependency
+struct capHdr {
+ quint32 version;
+ int pid;
+};
+
+struct capData {
+ quint32 effective;
+ quint32 permitted;
+ quint32 inheritable;
+};
+
+#ifndef _LINUX_CAPABILITY_VERSION_3
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#endif
+
+#ifndef _LINUX_CAPABILITY_U32S_3
+#define _LINUX_CAPABILITY_U32S_3 2
+#endif
+
+#ifndef CAP_NET_ADMIN
+#define CAP_NET_ADMIN 12
+#endif
+
+#ifndef CAP_TO_INDEX
+#define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */
+#endif
+
+#ifndef CAP_TO_MASK
+#define CAP_TO_MASK(x) (1 << ((x) & 31)) /* mask for indexed __u32 */
+#endif
+
+const int msecInADay = 1000*60*60*24;
+
+inline uint qHash(const QBluetoothAddress& address)
+{
+ return qHash(address.toUInt64());
+}
+
+static int sysCallCapGet(capHdr *header, capData *data)
+{
+ return syscall(__NR_capget, header, data);
+}
+
+/*!
+ * Checks that the current process has the effective CAP_NET_ADMIN permission.
+ */
+static bool hasBtMgmtPermission()
+{
+ // We only care for cap version 3 introduced by kernel 2.6.26
+ // because the new BlueZ management API only exists since kernel 3.4.
+
+ struct capHdr header = {};
+ struct capData data[_LINUX_CAPABILITY_U32S_3] = {{}};
+ header.version = _LINUX_CAPABILITY_VERSION_3;
+ header.pid = getpid();
+
+ if (sysCallCapGet(&header, data) < 0) {
+ qCWarning(QT_BT_BLUEZ, "BluetoothManangement: getCap failed with %s",
+ qPrintable(qt_error_string(errno)));
+ return false;
+ }
+
+ return (data[CAP_TO_INDEX(CAP_NET_ADMIN)].effective & CAP_TO_MASK(CAP_NET_ADMIN));
+}
+
+BluetoothManagement::BluetoothManagement(QObject *parent) : QObject(parent)
+{
+ bool hasPermission = hasBtMgmtPermission();
+ if (!hasPermission) {
+ qCInfo(QT_BT_BLUEZ, "Missing CAP_NET_ADMIN permission. Cannot determine whether "
+ "a found address is of random or public type.");
+ return;
+ }
+
+ sockaddr_hci hciAddr;
+
+ fd = ::socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);
+ if (fd < 0) {
+ qCWarning(QT_BT_BLUEZ, "Cannot open Bluetooth Management socket: %s",
+ qPrintable(qt_error_string(errno)));
+ return;
+ }
+
+ memset(&hciAddr, 0, sizeof(hciAddr));
+ hciAddr.hci_dev = HCI_DEV_NONE;
+ hciAddr.hci_channel = HCI_CHANNEL_CONTROL;
+ hciAddr.hci_family = AF_BLUETOOTH;
+
+ if (::bind(fd, (struct sockaddr *)(&hciAddr), sizeof(hciAddr)) < 0) {
+ qCWarning(QT_BT_BLUEZ, "Cannot bind Bluetooth Management socket: %s",
+ qPrintable(qt_error_string(errno)));
+ ::close(fd);
+ fd = -1;
+ return;
+ }
+
+ notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
+ connect(notifier, &QSocketNotifier::activated, this, &BluetoothManagement::_q_readNotifier);
+
+ // ensure cache is regularly cleaned (once every 24h)
+ QTimer* timer = new QTimer(this);
+ timer->setInterval(msecInADay);
+ timer->setTimerType(Qt::VeryCoarseTimer);
+ connect(timer, &QTimer::timeout, this, &BluetoothManagement::cleanupOldAddressFlags);
+ timer->start();
+}
+
+Q_GLOBAL_STATIC(BluetoothManagement, bluetoothKernelManager)
+
+BluetoothManagement *BluetoothManagement::instance()
+{
+ return bluetoothKernelManager();
+}
+
+void BluetoothManagement::_q_readNotifier()
+{
+ char *dst = buffer.reserve(QPRIVATELINEARBUFFER_BUFFERSIZE);
+ int readCount = ::read(fd, dst, QPRIVATELINEARBUFFER_BUFFERSIZE);
+ buffer.chop(QPRIVATELINEARBUFFER_BUFFERSIZE - (readCount < 0 ? 0 : readCount));
+ if (readCount < 0) {
+ qCWarning(QT_BT_BLUEZ, "Management Control read error %s", qPrintable(qt_error_string(errno)));
+ return;
+ }
+
+ // do we have at least one complete mgmt header?
+ if ((uint)buffer.size() < sizeof(MgmtHdr))
+ return;
+
+ QByteArray data = buffer.readAll();
+
+ while (true) {
+ if ((uint)data.size() < sizeof(MgmtHdr))
+ break;
+
+ const MgmtHdr *hdr = reinterpret_cast<const MgmtHdr*>(data.constData());
+ const int nextPackageSize = qFromLittleEndian(hdr->length) + sizeof(MgmtHdr);
+ const int remainingPackageSize = data.length() - nextPackageSize;
+
+ if (data.length() < nextPackageSize)
+ break; // not a complete event header -> wait for next notifier
+
+ switch (static_cast<EventCode>(qFromLittleEndian(hdr->cmdCode))) {
+ case EventCode::DeviceFound:
+ {
+ const MgmtEventDeviceFound *event = reinterpret_cast<const MgmtEventDeviceFound*>
+ (data.constData() + sizeof(MgmtHdr));
+
+ if (event->type == BDADDR_LE_RANDOM) {
+ const bdaddr_t address = event->bdaddr;
+ quint64 bdaddr;
+
+ convertAddress(address.b, &bdaddr);
+ const QBluetoothAddress qtAddress(bdaddr);
+ qCDebug(QT_BT_BLUEZ) << "BluetoothManagement: found random device"
+ << qtAddress;
+ processRandomAddressFlagInformation(qtAddress);
+ }
+
+ break;
+ }
+ default:
+ qCDebug(QT_BT_BLUEZ) << "BluetoothManagement: Ignored event:"
+ << hex << qFromLittleEndian(hdr->cmdCode);
+ break;
+ }
+
+ if (data.length() > nextPackageSize)
+ data = data.right(remainingPackageSize);
+ else
+ data.clear();
+
+ if (data.isEmpty())
+ break;
+ }
+
+ if (!data.isEmpty())
+ buffer.ungetBlock(data.constData(), data.size());
+}
+
+void BluetoothManagement::processRandomAddressFlagInformation(const QBluetoothAddress &address)
+{
+ // insert or update
+ QMutexLocker locker(&accessLock);
+ privateFlagAddresses[address] = QDateTime::currentDateTimeUtc();
+}
+
+/*
+ * Ensure that private address cache is not older than 24h.
+ */
+void BluetoothManagement::cleanupOldAddressFlags()
+{
+ const auto cutOffTime = QDateTime::currentDateTimeUtc().addDays(-1);
+
+ QMutexLocker locker(&accessLock);
+
+ auto i = privateFlagAddresses.begin();
+ while (i != privateFlagAddresses.end()) {
+ if (i.value() < cutOffTime)
+ i = privateFlagAddresses.erase(i);
+ else
+ i++;
+ }
+}
+
+bool BluetoothManagement::isAddressRandom(const QBluetoothAddress &address) const
+{
+ if (fd == -1 || address.isNull())
+ return false;
+
+ QMutexLocker locker(&accessLock);
+ return privateFlagAddresses.contains(address);
+}
+
+bool BluetoothManagement::isMonitoringEnabled() const
+{
+ return (fd == -1) ? false : true;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/bluez/bluetoothmanagement_p.h b/src/bluetooth/bluez/bluetoothmanagement_p.h
new file mode 100644
index 00000000..954f6e03
--- /dev/null
+++ b/src/bluetooth/bluez/bluetoothmanagement_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BLUETOOTHMANAGEMENT_P_H
+#define BLUETOOTHMANAGEMENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qobject.h>
+
+#include <QtBluetooth/qbluetoothaddress.h>
+
+#ifndef QPRIVATELINEARBUFFER_BUFFERSIZE
+#define QPRIVATELINEARBUFFER_BUFFERSIZE Q_INT64_C(16384)
+#endif
+#include "../qprivatelinearbuffer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSocketNotifier;
+
+class BluetoothManagement : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit BluetoothManagement(QObject *parent = nullptr);
+ static BluetoothManagement *instance();
+
+ bool isAddressRandom(const QBluetoothAddress &address) const;
+ bool isMonitoringEnabled() const;
+
+private slots:
+ void _q_readNotifier();
+ void processRandomAddressFlagInformation(const QBluetoothAddress &address);
+ void cleanupOldAddressFlags();
+
+private:
+ void readyRead();
+
+ int fd = -1;
+ QSocketNotifier* notifier;
+ QPrivateLinearBuffer buffer;
+ QHash<QBluetoothAddress, QDateTime> privateFlagAddresses;
+ mutable QMutex accessLock;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // BLUETOOTHMANAGEMENT_P_H
diff --git a/src/bluetooth/bluez/bluez.pri b/src/bluetooth/bluez/bluez.pri
index 46727cbc..b99f2712 100644
--- a/src/bluetooth/bluez/bluez.pri
+++ b/src/bluetooth/bluez/bluez.pri
@@ -18,7 +18,9 @@ HEADERS += bluez/manager_p.h \
bluez/obex_objectpush1_bluez5_p.h \
bluez/obex_transfer1_bluez5_p.h \
bluez/bluez_data_p.h \
- bluez/hcimanager_p.h
+ bluez/hcimanager_p.h \
+ bluez/remotedevicemanager_p.h \
+ bluez/bluetoothmanagement_p.h
SOURCES += bluez/manager.cpp \
bluez/adapter.cpp \
@@ -39,4 +41,6 @@ SOURCES += bluez/manager.cpp \
bluez/obex_client1_bluez5.cpp \
bluez/obex_objectpush1_bluez5.cpp \
bluez/obex_transfer1_bluez5.cpp \
- bluez/hcimanager.cpp
+ bluez/hcimanager.cpp \
+ bluez/remotedevicemanager.cpp \
+ bluez/bluetoothmanagement.cpp
diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp
index 8871a872..de41003f 100644
--- a/src/bluetooth/bluez/bluez5_helper.cpp
+++ b/src/bluetooth/bluez/bluez5_helper.cpp
@@ -69,6 +69,7 @@ bool isBluez5()
qDBusRegisterMetaType<InterfaceList>();
qDBusRegisterMetaType<ManagedObjectList>();
+ qDBusRegisterMetaType<ManufacturerDataList>();
QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
reply.waitForFinished();
diff --git a/src/bluetooth/bluez/bluez5_helper_p.h b/src/bluetooth/bluez/bluez5_helper_p.h
index a46810fc..2d72caf1 100644
--- a/src/bluetooth/bluez/bluez5_helper_p.h
+++ b/src/bluetooth/bluez/bluez5_helper_p.h
@@ -57,8 +57,10 @@
typedef QMap<QString, QVariantMap> InterfaceList;
typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList;
+typedef QMap<quint16, QDBusVariant> ManufacturerDataList;
Q_DECLARE_METATYPE(InterfaceList)
+Q_DECLARE_METATYPE(ManufacturerDataList)
Q_DECLARE_METATYPE(ManagedObjectList)
QT_BEGIN_NAMESPACE
diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h
index 8c2dc43e..684cd5b8 100644
--- a/src/bluetooth/bluez/bluez_data_p.h
+++ b/src/bluetooth/bluez/bluez_data_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
@@ -99,6 +99,10 @@ struct bt_security {
#define BDADDR_LE_PUBLIC 0x01
#define BDADDR_LE_RANDOM 0x02
+#define SCO_LINK 0x00
+#define ACL_LINK 0x01
+#define ESCO_LINK 0x02
+#define LE_LINK 0x80 // based on hcitool.c -> no fixed constant available
/* Byte order conversions */
#if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -200,7 +204,10 @@ template<> inline void putBtData(quint128 src, void *dst)
// HCI related
-#define HCI_MAX_DEV 16
+#define HCI_MAX_DEV 16
+#define HCI_DEV_NONE 0xffff
+
+#define HCI_CHANNEL_CONTROL 0x3
#define HCI_MAX_EVENT_SIZE 260
diff --git a/src/bluetooth/bluez/device1_bluez5.cpp b/src/bluetooth/bluez/device1_bluez5.cpp
index a4c01d3f..491a365d 100644
--- a/src/bluetooth/bluez/device1_bluez5.cpp
+++ b/src/bluetooth/bluez/device1_bluez5.cpp
@@ -1,8 +1,7 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p device1_bluez5 -v org.bluez.Device1.xml
*
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
diff --git a/src/bluetooth/bluez/device1_bluez5_p.h b/src/bluetooth/bluez/device1_bluez5_p.h
index d6181b34..4feb5318 100644
--- a/src/bluetooth/bluez/device1_bluez5_p.h
+++ b/src/bluetooth/bluez/device1_bluez5_p.h
@@ -1,15 +1,14 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p device1_bluez5 -v org.bluez.Device1.xml
*
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
-#ifndef DEVICE1_BLUEZ5_H_1396951960
-#define DEVICE1_BLUEZ5_H_1396951960
+#ifndef DEVICE1_BLUEZ5_P_H
+#define DEVICE1_BLUEZ5_P_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
@@ -19,6 +18,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include "bluez5_helper_p.h"
/*
* Proxy class for interface org.bluez.Device1
@@ -31,7 +31,7 @@ public:
{ return "org.bluez.Device1"; }
public:
- OrgBluezDevice1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
+ OrgBluezDevice1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
~OrgBluezDevice1Interface();
@@ -75,6 +75,10 @@ public:
inline bool legacyPairing() const
{ return qvariant_cast< bool >(property("LegacyPairing")); }
+ Q_PROPERTY(ManufacturerDataList ManufacturerData READ manufacturerData)
+ inline ManufacturerDataList manufacturerData() const
+ { return qvariant_cast< ManufacturerDataList >(property("ManufacturerData")); }
+
Q_PROPERTY(QString Modalias READ modalias)
inline QString modalias() const
{ return qvariant_cast< QString >(property("Modalias")); }
@@ -91,12 +95,24 @@ public:
inline short rSSI() const
{ return qvariant_cast< short >(property("RSSI")); }
+ Q_PROPERTY(QVariantMap ServiceData READ serviceData)
+ inline QVariantMap serviceData() const
+ { return qvariant_cast< QVariantMap >(property("ServiceData")); }
+
+ Q_PROPERTY(bool ServicesResolved READ servicesResolved)
+ inline bool servicesResolved() const
+ { return qvariant_cast< bool >(property("ServicesResolved")); }
+
Q_PROPERTY(bool Trusted READ trusted WRITE setTrusted)
inline bool trusted() const
{ return qvariant_cast< bool >(property("Trusted")); }
inline void setTrusted(bool value)
{ setProperty("Trusted", QVariant::fromValue(value)); }
+ Q_PROPERTY(short TxPower READ txPower)
+ inline short txPower() const
+ { return qvariant_cast< short >(property("TxPower")); }
+
Q_PROPERTY(QStringList UUIDs READ uUIDs)
inline QStringList uUIDs() const
{ return qvariant_cast< QStringList >(property("UUIDs")); }
@@ -105,39 +121,39 @@ public Q_SLOTS: // METHODS
inline QDBusPendingReply<> CancelPairing()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("CancelPairing"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("CancelPairing"), argumentList);
}
inline QDBusPendingReply<> Connect()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Connect"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Connect"), argumentList);
}
inline QDBusPendingReply<> ConnectProfile(const QString &UUID)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(UUID);
- return asyncCallWithArgumentList(QLatin1String("ConnectProfile"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("ConnectProfile"), argumentList);
}
inline QDBusPendingReply<> Disconnect()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Disconnect"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Disconnect"), argumentList);
}
inline QDBusPendingReply<> DisconnectProfile(const QString &UUID)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(UUID);
- return asyncCallWithArgumentList(QLatin1String("DisconnectProfile"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("DisconnectProfile"), argumentList);
}
inline QDBusPendingReply<> Pair()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Pair"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Pair"), argumentList);
}
Q_SIGNALS: // SIGNALS
diff --git a/src/bluetooth/bluez/generate b/src/bluetooth/bluez/generate
index 14bcaea8..cdba18c4 100755
--- a/src/bluetooth/bluez/generate
+++ b/src/bluetooth/bluez/generate
@@ -1,5 +1,6 @@
#!/bin/sh
+#Bluez 4
qdbusxml2cpp -p manager_p.h:manager.cpp org.bluez.Manager.xml org.bluez.Manager
qdbusxml2cpp -p adapter_p.h:adapter.cpp org.bluez.all.xml org.bluez.Adapter
qdbusxml2cpp -i servicemap_p.h -p device_p.h:device.cpp org.bluez.Device.xml org.bluez.Device
@@ -9,8 +10,13 @@ qdbusxml2cpp -p obex_manager_p.h:obex_manager.cpp org.openobex.all.xml org.openo
qdbusxml2cpp -p obex_client_p.h:obex_client.cpp org.openobex.client.xml org.openobex.Client
qdbusxml2cpp -p obex_transfer_p.h:obex_transfer.cpp org.openobex.transfer.xml org.openobex.Transfer
qdbusxml2cpp -a obex_agent_p.h:obex_agent.cpp org.openobex.agent.xml org.openobex.Agent
-#qdbusxml2cpp -p serialproxymanager_p.h:serialproxymanager.cpp org.bluez.all.xml org.bluez.SerialProxyManager
-#qdbusxml2cpp -p networkpeer_p.h:networkpeer.cpp org.bluez.all.xml org.bluez.NetworkPeer
-#qdbusxml2cpp -p networkhub_p.h:networkhub.cpp org.bluez.all.xml org.bluez.NetworkHub
-#qdbusxml2cpp -p networkrouter_p.h:networkrouter.cpp org.bluez.all.xml org.bluez.NetworkRouter
+#Bluez 5
+qdbusxml2cpp -p adapter1_bluez5_p.h:adapter1_bluez5.cpp org.bluez.Adapter1.xml
+qdbusxml2cpp -p device1_bluez5_p.h:device1_bluez5.cpp org.bluez.Device1.xml
+qdbusxml2cpp -p profile1_p.h:profile1.cpp org.bluez.ProfileManager1.xml
+qdbusxml2cpp -p objectmanager_p.h:objectmanager.cpp org.freedesktop.dbus.objectmanager.xml
+qdbusxml2cpp -p properties_p.h:properties.cpp org.freedesktop.dbus.properties.xml
+qdbusxml2cpp -p obex_client1_bluez5_p.h:obex_client1_bluez5_p.h org.bluez.Client1.xml
+qdbusxml2cpp -p obex_objectpush1_bluez5_p.h:obex_objectpush1_bluez5.cpp org.bluez.obex.ObjectPush1.xml
+qdbusxml2cpp -p obex_transfer1_bluez5_p.h:obex_transfer1_bluez5_p.h org.bluez.obex.Transfer1.xml
diff --git a/src/bluetooth/bluez/hcimanager.cpp b/src/bluetooth/bluez/hcimanager.cpp
index 93bf941b..c524117c 100644
--- a/src/bluetooth/bluez/hcimanager.cpp
+++ b/src/bluetooth/bluez/hcimanager.cpp
@@ -288,6 +288,50 @@ QBluetoothAddress HciManager::addressForConnectionHandle(quint16 handle) const
return QBluetoothAddress();
}
+QVector<quint16> HciManager::activeLowEnergyConnections() const
+{
+ if (!isValid())
+ return QVector<quint16>();
+
+ hci_conn_info *info;
+ hci_conn_list_req *infoList;
+
+ const int maxNoOfConnections = 20;
+ infoList = (hci_conn_list_req *)
+ malloc(sizeof(hci_conn_list_req) + maxNoOfConnections * sizeof(hci_conn_info));
+
+ if (!infoList)
+ return QVector<quint16>();
+
+ QScopedPointer<hci_conn_list_req, QScopedPointerPodDeleter> p(infoList);
+ p->conn_num = maxNoOfConnections;
+ p->dev_id = hciDev;
+ info = p->conn_info;
+
+ if (ioctl(hciSocket, HCIGETCONNLIST, (void *) infoList) < 0) {
+ qCWarning(QT_BT_BLUEZ) << "Cannot retrieve connection list";
+ return QVector<quint16>();
+ }
+
+ QVector<quint16> activeLowEnergyHandles;
+ for (int i = 0; i < infoList->conn_num; i++) {
+ switch (info[i].type) {
+ case SCO_LINK:
+ case ACL_LINK:
+ case ESCO_LINK:
+ continue;
+ case LE_LINK:
+ activeLowEnergyHandles.append(info[i].handle);
+ break;
+ default:
+ qCWarning(QT_BT_BLUEZ) << "Unknown active connection type:" << hex << info[i].type;
+ break;
+ }
+ }
+
+ return activeLowEnergyHandles;
+}
+
quint16 forceIntervalIntoRange(double connectionInterval)
{
return qMin<double>(qMax<double>(7.5, connectionInterval), 4000) / 1.25;
diff --git a/src/bluetooth/bluez/hcimanager_p.h b/src/bluetooth/bluez/hcimanager_p.h
index 3bae92e5..3127a747 100644
--- a/src/bluetooth/bluez/hcimanager_p.h
+++ b/src/bluetooth/bluez/hcimanager_p.h
@@ -55,6 +55,7 @@
#include <QtCore/QSet>
#include <QtCore/QSocketNotifier>
#include <QtBluetooth/QBluetoothAddress>
+#include <QVector>
#include "bluez/bluez_data_p.h"
QT_BEGIN_NAMESPACE
@@ -82,6 +83,9 @@ public:
void stopEvents();
QBluetoothAddress addressForConnectionHandle(quint16 handle) const;
+ // active connections
+ QVector<quint16> activeLowEnergyConnections() const;
+
bool sendConnectionUpdateCommand(quint16 handle, const QLowEnergyConnectionParameters &params);
bool sendConnectionParameterUpdateRequest(quint16 handle,
const QLowEnergyConnectionParameters &params);
diff --git a/src/bluetooth/bluez/objectmanager_p.h b/src/bluetooth/bluez/objectmanager_p.h
index 823badeb..74f5ab43 100644
--- a/src/bluetooth/bluez/objectmanager_p.h
+++ b/src/bluetooth/bluez/objectmanager_p.h
@@ -20,10 +20,6 @@
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
-/* Temporary hack to merge branches until Bluez headers are removed
- * from bluez5_helpers_p.h.
- */
-#define NO_BLUEZ_INCLUDES
#include "bluez5_helper_p.h"
/*
diff --git a/src/bluetooth/bluez/org.bluez.Adapter1.xml b/src/bluetooth/bluez/org.bluez.Adapter1.xml
index a1e6babe..121c277e 100644
--- a/src/bluetooth/bluez/org.bluez.Adapter1.xml
+++ b/src/bluetooth/bluez/org.bluez.Adapter1.xml
@@ -7,6 +7,10 @@
<method name="RemoveDevice">
<arg name="device" type="o" direction="in"/>
</method>
+ <method name="SetDiscoveryFilter">
+ <arg name="properties" type="a{sv}" direction="in"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
+ </method>
<property name="Address" type="s" access="read"></property>
<property name="Name" type="s" access="read"></property>
<property name="Alias" type="s" access="readwrite"></property>
diff --git a/src/bluetooth/bluez/org.bluez.Device1.xml b/src/bluetooth/bluez/org.bluez.Device1.xml
index 1f8fd2c1..554d0b53 100644
--- a/src/bluetooth/bluez/org.bluez.Device1.xml
+++ b/src/bluetooth/bluez/org.bluez.Device1.xml
@@ -27,5 +27,15 @@
<property name="UUIDs" type="as" access="read"></property>
<property name="Modalias" type="s" access="read"></property>
<property name="Adapter" type="o" access="read"></property>
+ <!-- ManufacturerData & ServiceData introduced by Bluez 5.31 -->
+ <property name="ManufacturerData" type="a{qv}" access="read">
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="ManufacturerDataList"/>
+ </property>
+ <property name="ServiceData" type="a{sv}" access="read">
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/>
+ </property>
+ <!-- TxPower and ServicesResolved introduced by Bluez 5.42 -->
+ <property name="TxPower" type="n" access="read"></property>
+ <property name="ServicesResolved" type="b" access="read"></property>
</interface>
</node>
diff --git a/src/bluetooth/bluez/remotedevicemanager.cpp b/src/bluetooth/bluez/remotedevicemanager.cpp
new file mode 100644
index 00000000..f63b21e6
--- /dev/null
+++ b/src/bluetooth/bluez/remotedevicemanager.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QLoggingCategory>
+
+#include "remotedevicemanager_p.h"
+#include "bluez5_helper_p.h"
+#include "device1_bluez5_p.h"
+#include "objectmanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
+/*!
+ * Convenience wrapper around org.bluez.Device1 management
+ *
+ * Very simple and not thread safe.
+ */
+
+RemoteDeviceManager::RemoteDeviceManager(
+ const QBluetoothAddress &address, QObject *parent)
+ : QObject(parent), localAddress(address)
+{
+ if (!isBluez5())
+ return;
+
+ bool ok = false;
+ adapterPath = findAdapterForAddress(address, &ok);
+ if (!ok || adapterPath.isEmpty()) {
+ qCWarning(QT_BT_BLUEZ) << "Cannot initialize RemoteDeviceManager";
+ }
+}
+
+bool RemoteDeviceManager::scheduleJob(
+ JobType job, const QVector<QBluetoothAddress> &remoteDevices)
+{
+ if (adapterPath.isEmpty())
+ return false;
+
+ for (const auto& remote : remoteDevices)
+ jobQueue.push_back(std::make_pair(job, remote));
+
+ QTimer::singleShot(0, this, [this](){ runQueue(); });
+ return true;
+}
+
+void RemoteDeviceManager::runQueue()
+{
+ if (jobInProgress || adapterPath.isEmpty())
+ return;
+
+ if (jobQueue.empty())
+ return;
+
+ jobInProgress = true;
+ switch (jobQueue.front().first) {
+ case JobType::JobDisconnectDevice:
+ disconnectDevice(jobQueue.front().second);
+ break;
+ default:
+ break;
+ }
+}
+
+void RemoteDeviceManager::prepareNextJob()
+{
+ Q_ASSERT(!jobQueue.empty());
+
+ jobQueue.pop_front();
+ jobInProgress = false;
+
+ if (jobQueue.empty())
+ emit finished();
+ else
+ runQueue();
+}
+
+void RemoteDeviceManager::disconnectDevice(const QBluetoothAddress &remote)
+{
+ // collect initial set of information
+ OrgFreedesktopDBusObjectManagerInterface managerBluez5(
+ QStringLiteral("org.bluez"),
+ QStringLiteral("/"),
+ QDBusConnection::systemBus(), this);
+ QDBusPendingReply<ManagedObjectList> reply = managerBluez5.GetManagedObjects();
+ reply.waitForFinished();
+ if (reply.isError()) {
+ QTimer::singleShot(0, this, [this](){ prepareNextJob(); });
+ return;
+ }
+
+ bool jobStarted = false;
+ ManagedObjectList managedObjectList = reply.value();
+ for (auto it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
+ const QDBusObjectPath &path = it.key();
+ const InterfaceList &ifaceList = it.value();
+
+ for (auto jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
+ const QString &iface = jt.key();
+
+ if (path.path().indexOf(adapterPath) != 0)
+ continue; //devices whose path doesn't start with same path we skip
+
+ if (iface != QStringLiteral("org.bluez.Device1"))
+ continue;
+
+ const QBluetoothAddress foundAddress(ifaceList.value(iface).value(QStringLiteral("Address")).toString());
+ if (foundAddress != remote)
+ continue;
+
+ // found the correct Device1 path
+ OrgBluezDevice1Interface* device1 = new OrgBluezDevice1Interface(QStringLiteral("org.bluez"),
+ path.path(),
+ QDBusConnection::systemBus(),
+ this);
+ QDBusPendingReply<> asyncReply = device1->Disconnect();
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(asyncReply, this);
+ const auto watcherFinished = [this, device1](QDBusPendingCallWatcher* call) {
+ call->deleteLater();
+ device1->deleteLater();
+ prepareNextJob();
+ };
+ connect(watcher, &QDBusPendingCallWatcher::finished, this, watcherFinished);
+ jobStarted = true;
+ break;
+ }
+ }
+
+ if (!jobStarted)
+ QTimer::singleShot(0, this, [this](){ prepareNextJob(); });
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/bluez/remotedevicemanager_p.h b/src/bluetooth/bluez/remotedevicemanager_p.h
new file mode 100644
index 00000000..a6af8f44
--- /dev/null
+++ b/src/bluetooth/bluez/remotedevicemanager_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REMOTEDEVICEMANAGER_P_H
+#define REMOTEDEVICEMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <deque>
+
+#include <QMutex>
+#include <QObject>
+#include <QVector>
+
+#include <QtBluetooth/qbluetoothaddress.h>
+
+
+QT_BEGIN_NAMESPACE
+
+// This API is kept a bit more generic in anticipation of further changes in the future.
+
+class RemoteDeviceManager : public QObject
+{
+ Q_OBJECT
+public:
+ enum class JobType
+ {
+ JobDisconnectDevice,
+ };
+
+ explicit RemoteDeviceManager(const QBluetoothAddress& localAddress, QObject *parent = 0);
+
+ bool isJobInProgress() const { return jobInProgress; }
+ bool scheduleJob(JobType job, const QVector<QBluetoothAddress>& remoteDevices);
+
+signals:
+ void finished();
+
+private slots:
+ void runQueue();
+ void prepareNextJob();
+
+private:
+ void disconnectDevice(const QBluetoothAddress& remote);
+
+ bool jobInProgress = false;
+ QBluetoothAddress localAddress;
+ std::deque<std::pair<JobType, QBluetoothAddress>> jobQueue;
+ QString adapterPath;
+};
+
+QT_END_NAMESPACE
+
+#endif // REMOTEDEVICEMANAGER_P_H