diff options
-rw-r--r-- | src/bluetooth/bluez/adapter1_bluez5.cpp | 26 | ||||
-rw-r--r-- | src/bluetooth/bluez/adapter1_bluez5_p.h | 126 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez.pri | 14 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez5_helper.cpp | 84 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez5_helper_p.h | 60 | ||||
-rw-r--r-- | src/bluetooth/bluez/device1_bluez5.cpp | 26 | ||||
-rw-r--r-- | src/bluetooth/bluez/device1_bluez5_p.h | 151 | ||||
-rw-r--r-- | src/bluetooth/bluez/objectmanager.cpp | 26 | ||||
-rw-r--r-- | src/bluetooth/bluez/objectmanager_p.h | 58 | ||||
-rw-r--r-- | src/bluetooth/bluez/org.bluez.Adapter1.xml | 23 | ||||
-rw-r--r-- | src/bluetooth/bluez/org.bluez.Device1.xml | 31 | ||||
-rw-r--r-- | src/bluetooth/bluez/org.freedesktop.dbus.objectmanager.xml | 19 | ||||
-rw-r--r-- | src/bluetooth/bluez/org.freedesktop.dbus.properties.xml | 27 | ||||
-rw-r--r-- | src/bluetooth/bluez/properties.cpp | 26 | ||||
-rw-r--r-- | src/bluetooth/bluez/properties_p.h | 71 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothlocaldevice_bluez.cpp | 752 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothlocaldevice_p.h | 30 | ||||
-rw-r--r-- | tests/bttestui/btlocaldevice.cpp | 16 |
18 files changed, 1453 insertions, 113 deletions
diff --git a/src/bluetooth/bluez/adapter1_bluez5.cpp b/src/bluetooth/bluez/adapter1_bluez5.cpp new file mode 100644 index 00000000..8de63d32 --- /dev/null +++ b/src/bluetooth/bluez/adapter1_bluez5.cpp @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -p adapter1 -v org.bluez.Adapter1.xml + * + * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "adapter1_bluez5_p.h" + +/* + * Implementation of interface class OrgBluezAdapter1Interface + */ + +OrgBluezAdapter1Interface::OrgBluezAdapter1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +OrgBluezAdapter1Interface::~OrgBluezAdapter1Interface() +{ +} + diff --git a/src/bluetooth/bluez/adapter1_bluez5_p.h b/src/bluetooth/bluez/adapter1_bluez5_p.h new file mode 100644 index 00000000..32a70b3d --- /dev/null +++ b/src/bluetooth/bluez/adapter1_bluez5_p.h @@ -0,0 +1,126 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -p adapter1 -v org.bluez.Adapter1.xml + * + * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). + * + * 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 + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface org.bluez.Adapter1 + */ +class OrgBluezAdapter1Interface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.bluez.Adapter1"; } + +public: + OrgBluezAdapter1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~OrgBluezAdapter1Interface(); + + Q_PROPERTY(QString Address READ address) + inline QString address() const + { return qvariant_cast< QString >(property("Address")); } + + Q_PROPERTY(QString Alias READ alias WRITE setAlias) + inline QString alias() const + { return qvariant_cast< QString >(property("Alias")); } + inline void setAlias(const QString &value) + { setProperty("Alias", QVariant::fromValue(value)); } + + Q_PROPERTY(uint Class READ classProperty) + inline uint classProperty() const + { return qvariant_cast< uint >(property("Class")); } + + Q_PROPERTY(bool Discoverable READ discoverable WRITE setDiscoverable) + inline bool discoverable() const + { return qvariant_cast< bool >(property("Discoverable")); } + inline void setDiscoverable(bool value) + { setProperty("Discoverable", QVariant::fromValue(value)); } + + Q_PROPERTY(uint DiscoverableTimeout READ discoverableTimeout WRITE setDiscoverableTimeout) + inline uint discoverableTimeout() const + { return qvariant_cast< uint >(property("DiscoverableTimeout")); } + inline void setDiscoverableTimeout(uint value) + { setProperty("DiscoverableTimeout", QVariant::fromValue(value)); } + + Q_PROPERTY(bool Discovering READ discovering) + inline bool discovering() const + { return qvariant_cast< bool >(property("Discovering")); } + + Q_PROPERTY(QString Modalias READ modalias) + inline QString modalias() const + { return qvariant_cast< QString >(property("Modalias")); } + + Q_PROPERTY(QString Name READ name) + inline QString name() const + { return qvariant_cast< QString >(property("Name")); } + + Q_PROPERTY(bool Pairable READ pairable WRITE setPairable) + inline bool pairable() const + { return qvariant_cast< bool >(property("Pairable")); } + inline void setPairable(bool value) + { setProperty("Pairable", QVariant::fromValue(value)); } + + Q_PROPERTY(uint PairableTimeout READ pairableTimeout WRITE setPairableTimeout) + inline uint pairableTimeout() const + { return qvariant_cast< uint >(property("PairableTimeout")); } + inline void setPairableTimeout(uint value) + { setProperty("PairableTimeout", QVariant::fromValue(value)); } + + Q_PROPERTY(bool Powered READ powered WRITE setPowered) + inline bool powered() const + { return qvariant_cast< bool >(property("Powered")); } + inline void setPowered(bool value) + { setProperty("Powered", QVariant::fromValue(value)); } + + Q_PROPERTY(QStringList UUIDs READ uUIDs) + inline QStringList uUIDs() const + { return qvariant_cast< QStringList >(property("UUIDs")); } + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> RemoveDevice(const QDBusObjectPath &device) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(device); + return asyncCallWithArgumentList(QLatin1String("RemoveDevice"), argumentList); + } + + inline QDBusPendingReply<> StartDiscovery() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("StartDiscovery"), argumentList); + } + + inline QDBusPendingReply<> StopDiscovery() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("StopDiscovery"), argumentList); + } + +Q_SIGNALS: // SIGNALS +}; + +namespace org { + namespace bluez { + typedef ::OrgBluezAdapter1Interface Adapter1; + } +} +#endif diff --git a/src/bluetooth/bluez/bluez.pri b/src/bluetooth/bluez/bluez.pri index 5a679091..5bfea6c2 100644 --- a/src/bluetooth/bluez/bluez.pri +++ b/src/bluetooth/bluez/bluez.pri @@ -20,7 +20,12 @@ HEADERS += bluez/manager_p.h \ bluez/obex_client_p.h \ bluez/obex_agent_p.h \ bluez/obex_transfer_p.h \ - bluez/obex_manager_p.h + bluez/obex_manager_p.h \ + bluez/bluez5_helper_p.h \ + bluez/objectmanager_p.h \ + bluez/properties_p.h \ + bluez/adapter1_bluez5_p.h \ + bluez/device1_bluez5_p.h SOURCES += bluez/manager.cpp \ @@ -32,4 +37,9 @@ SOURCES += bluez/manager.cpp \ bluez/obex_client.cpp \ bluez/obex_agent.cpp \ bluez/obex_transfer.cpp \ - bluez/obex_manager.cpp + bluez/obex_manager.cpp \ + bluez/objectmanager.cpp \ + bluez/properties.cpp \ + bluez/adapter1_bluez5.cpp \ + bluez/device1_bluez5.cpp \ + bluez/bluez5_helper.cpp diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp new file mode 100644 index 00000000..09b50146 --- /dev/null +++ b/src/bluetooth/bluez/bluez5_helper.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QGlobalStatic> +#include <QtCore/QLoggingCategory> +#include "bluez5_helper_p.h" +#include "objectmanager_p.h" + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) + +typedef enum Bluez5TestResultType +{ + Unknown, + Bluez4, + Bluez5 +} Bluez5TestResult; + +Q_GLOBAL_STATIC_WITH_ARGS(Bluez5TestResult, bluezVersion, (Bluez5TestResult::Unknown)); + +bool isBluez5() +{ + if (*bluezVersion() == Bluez5TestResultType::Unknown) { + OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"), + QStringLiteral("/"), + QDBusConnection::systemBus()); + + qDBusRegisterMetaType<InterfaceList>(); + qDBusRegisterMetaType<ManagedObjectList>(); + + QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects(); + reply.waitForFinished(); + if (reply.isError()) { + *bluezVersion() = Bluez5TestResultType::Bluez4; + qCDebug(QT_BT_BLUEZ) << "Bluez 4 detected."; + } else { + *bluezVersion() = Bluez5TestResultType::Bluez5; + qCDebug(QT_BT_BLUEZ) << "Bluez 5 detected."; + } + } + + return (*bluezVersion() == Bluez5TestResultType::Bluez5); +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/bluez/bluez5_helper_p.h b/src/bluetooth/bluez/bluez5_helper_p.h new file mode 100644 index 00000000..8e81f4c6 --- /dev/null +++ b/src/bluetooth/bluez/bluez5_helper_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BLUEZ5_HELPER_H +#define BLUEZ5_HELPER_H + +#include <QtCore/QObject> +#include <QtDBus/QtDBus> + +typedef QMap<QString, QVariantMap> InterfaceList; +typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList; + +Q_DECLARE_METATYPE(InterfaceList) +Q_DECLARE_METATYPE(ManagedObjectList) + +QT_BEGIN_NAMESPACE + +bool isBluez5(); + +QT_END_NAMESPACE + +#endif diff --git a/src/bluetooth/bluez/device1_bluez5.cpp b/src/bluetooth/bluez/device1_bluez5.cpp new file mode 100644 index 00000000..50bef4cb --- /dev/null +++ b/src/bluetooth/bluez/device1_bluez5.cpp @@ -0,0 +1,26 @@ +/* + * 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) 2014 Digia Plc and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "device1_bluez5_p.h" + +/* + * Implementation of interface class OrgBluezDevice1Interface + */ + +OrgBluezDevice1Interface::OrgBluezDevice1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +OrgBluezDevice1Interface::~OrgBluezDevice1Interface() +{ +} + diff --git a/src/bluetooth/bluez/device1_bluez5_p.h b/src/bluetooth/bluez/device1_bluez5_p.h new file mode 100644 index 00000000..4caae28a --- /dev/null +++ b/src/bluetooth/bluez/device1_bluez5_p.h @@ -0,0 +1,151 @@ +/* + * 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) 2014 Digia Plc and/or its subsidiary(-ies). + * + * 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 + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface org.bluez.Device1 + */ +class OrgBluezDevice1Interface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.bluez.Device1"; } + +public: + OrgBluezDevice1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~OrgBluezDevice1Interface(); + + Q_PROPERTY(QDBusObjectPath Adapter READ adapter) + inline QDBusObjectPath adapter() const + { return qvariant_cast< QDBusObjectPath >(property("Adapter")); } + + Q_PROPERTY(QString Address READ address) + inline QString address() const + { return qvariant_cast< QString >(property("Address")); } + + Q_PROPERTY(QString Alias READ alias WRITE setAlias) + inline QString alias() const + { return qvariant_cast< QString >(property("Alias")); } + inline void setAlias(const QString &value) + { setProperty("Alias", QVariant::fromValue(value)); } + + Q_PROPERTY(ushort Appearance READ appearance) + inline ushort appearance() const + { return qvariant_cast< ushort >(property("Appearance")); } + + Q_PROPERTY(bool Blocked READ blocked WRITE setBlocked) + inline bool blocked() const + { return qvariant_cast< bool >(property("Blocked")); } + inline void setBlocked(bool value) + { setProperty("Blocked", QVariant::fromValue(value)); } + + Q_PROPERTY(uint Class READ classProperty) + inline uint classProperty() const + { return qvariant_cast< uint >(property("Class")); } + + Q_PROPERTY(bool Connected READ connected) + inline bool connected() const + { return qvariant_cast< bool >(property("Connected")); } + + Q_PROPERTY(QString Icon READ icon) + inline QString icon() const + { return qvariant_cast< QString >(property("Icon")); } + + Q_PROPERTY(bool LegacyPairing READ legacyPairing) + inline bool legacyPairing() const + { return qvariant_cast< bool >(property("LegacyPairing")); } + + Q_PROPERTY(QString Modalias READ modalias) + inline QString modalias() const + { return qvariant_cast< QString >(property("Modalias")); } + + Q_PROPERTY(QString Name READ name) + inline QString name() const + { return qvariant_cast< QString >(property("Name")); } + + Q_PROPERTY(bool Paired READ paired) + inline bool paired() const + { return qvariant_cast< bool >(property("Paired")); } + + Q_PROPERTY(short RSSI READ rSSI) + inline short rSSI() const + { return qvariant_cast< short >(property("RSSI")); } + + 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(QStringList UUIDs READ uUIDs) + inline QStringList uUIDs() const + { return qvariant_cast< QStringList >(property("UUIDs")); } + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> CancelPairing() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("CancelPairing"), argumentList); + } + + inline QDBusPendingReply<> Connect() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("Connect"), argumentList); + } + + inline QDBusPendingReply<> ConnectProfile(const QString &UUID) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(UUID); + return asyncCallWithArgumentList(QLatin1String("ConnectProfile"), argumentList); + } + + inline QDBusPendingReply<> Disconnect() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("Disconnect"), argumentList); + } + + inline QDBusPendingReply<> DisconnectProfile(const QString &UUID) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(UUID); + return asyncCallWithArgumentList(QLatin1String("DisconnectProfile"), argumentList); + } + + inline QDBusPendingReply<> Pair() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("Pair"), argumentList); + } + +Q_SIGNALS: // SIGNALS +}; + +namespace org { + namespace bluez { + typedef ::OrgBluezDevice1Interface Device1; + } +} +#endif diff --git a/src/bluetooth/bluez/objectmanager.cpp b/src/bluetooth/bluez/objectmanager.cpp new file mode 100644 index 00000000..521012f6 --- /dev/null +++ b/src/bluetooth/bluez/objectmanager.cpp @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -p objectmanager -v -i bluez5_helper.h org.freedesktop.dbus.objectmanager.xml + * + * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "objectmanager_p.h" + +/* + * Implementation of interface class OrgFreedesktopDBusObjectManagerInterface + */ + +OrgFreedesktopDBusObjectManagerInterface::OrgFreedesktopDBusObjectManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +OrgFreedesktopDBusObjectManagerInterface::~OrgFreedesktopDBusObjectManagerInterface() +{ +} + diff --git a/src/bluetooth/bluez/objectmanager_p.h b/src/bluetooth/bluez/objectmanager_p.h new file mode 100644 index 00000000..6acf3d6d --- /dev/null +++ b/src/bluetooth/bluez/objectmanager_p.h @@ -0,0 +1,58 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -p objectmanager -v -i bluez5_helper.h org.freedesktop.dbus.objectmanager.xml + * + * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef OBJECTMANAGER_H_1396883000 +#define OBJECTMANAGER_H_1396883000 + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> +#include "bluez5_helper_p.h" + +/* + * Proxy class for interface org.freedesktop.DBus.ObjectManager + */ +class OrgFreedesktopDBusObjectManagerInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.freedesktop.DBus.ObjectManager"; } + +public: + OrgFreedesktopDBusObjectManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~OrgFreedesktopDBusObjectManagerInterface(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<ManagedObjectList> GetManagedObjects() + { + QList<QVariant> argumentList; + return asyncCallWithArgumentList(QLatin1String("GetManagedObjects"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void InterfacesAdded(const QDBusObjectPath &object_path, InterfaceList interfaces_and_properties); + void InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces); +}; + +namespace org { + namespace freedesktop { + namespace DBus { + typedef ::OrgFreedesktopDBusObjectManagerInterface ObjectManager; + } + } +} +#endif diff --git a/src/bluetooth/bluez/org.bluez.Adapter1.xml b/src/bluetooth/bluez/org.bluez.Adapter1.xml new file mode 100644 index 00000000..a1e6babe --- /dev/null +++ b/src/bluetooth/bluez/org.bluez.Adapter1.xml @@ -0,0 +1,23 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.bluez.Adapter1"> + <method name="StartDiscovery"></method> + <method name="StopDiscovery"></method> + <method name="RemoveDevice"> + <arg name="device" type="o" direction="in"/> + </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> + <property name="Class" type="u" access="read"></property> + <property name="Powered" type="b" access="readwrite"></property> + <property name="Discoverable" type="b" access="readwrite"></property> + <property name="DiscoverableTimeout" type="u" access="readwrite"></property> + <property name="Pairable" type="b" access="readwrite"></property> + <property name="PairableTimeout" type="u" access="readwrite"></property> + <property name="Discovering" type="b" access="read"></property> + <property name="UUIDs" type="as" access="read"></property> + <property name="Modalias" type="s" access="read"></property> + </interface> +</node> diff --git a/src/bluetooth/bluez/org.bluez.Device1.xml b/src/bluetooth/bluez/org.bluez.Device1.xml new file mode 100644 index 00000000..1f8fd2c1 --- /dev/null +++ b/src/bluetooth/bluez/org.bluez.Device1.xml @@ -0,0 +1,31 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.bluez.Device1"> + <method name="Disconnect"></method> + <method name="Connect"></method> + <method name="ConnectProfile"> + <arg name="UUID" type="s" direction="in"/> + </method> + <method name="DisconnectProfile"> + <arg name="UUID" type="s" direction="in"/> + </method> + <method name="Pair"></method> + <method name="CancelPairing"></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> + <property name="Class" type="u" access="read"></property> + <property name="Appearance" type="q" access="read"></property> + <property name="Icon" type="s" access="read"></property> + <property name="Paired" type="b" access="read"></property> + <property name="Trusted" type="b" access="readwrite"></property> + <property name="Blocked" type="b" access="readwrite"></property> + <property name="LegacyPairing" type="b" access="read"></property> + <property name="RSSI" type="n" access="read"></property> + <property name="Connected" type="b" access="read"></property> + <property name="UUIDs" type="as" access="read"></property> + <property name="Modalias" type="s" access="read"></property> + <property name="Adapter" type="o" access="read"></property> + </interface> +</node> diff --git a/src/bluetooth/bluez/org.freedesktop.dbus.objectmanager.xml b/src/bluetooth/bluez/org.freedesktop.dbus.objectmanager.xml new file mode 100644 index 00000000..8ab2a6e1 --- /dev/null +++ b/src/bluetooth/bluez/org.freedesktop.dbus.objectmanager.xml @@ -0,0 +1,19 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> + <interface name="org.freedesktop.DBus.ObjectManager"> + <method name="GetManagedObjects"> + <arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ManagedObjectList"/> + </method> + <signal name="InterfacesAdded"> + <arg type="o" name="object_path"/> + <arg type="a{sa{sv}}" name="interfaces_and_properties"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="InterfaceList"/> + </signal> + <signal name="InterfacesRemoved"> + <arg type="o" name="object_path"/> + <arg type="as" name="interfaces"/> + </signal> + </interface> +</node> diff --git a/src/bluetooth/bluez/org.freedesktop.dbus.properties.xml b/src/bluetooth/bluez/org.freedesktop.dbus.properties.xml new file mode 100644 index 00000000..5dc94f5d --- /dev/null +++ b/src/bluetooth/bluez/org.freedesktop.dbus.properties.xml @@ -0,0 +1,27 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.freedesktop.DBus.Properties"> + <method name="Get"> + <arg name="interface" type="s" direction="in"/> + <arg name="name" type="s" direction="in"/> + <arg name="value" type="v" direction="out"/> + </method> + <method name="Set"> + <arg name="interface" type="s" direction="in"/> + <arg name="name" type="s" direction="in"/> + <arg name="value" type="v" direction="in"/> + </method> + <method name="GetAll"> + <arg name="interface" type="s" direction="in"/> + <arg name="properties" type="a{sv}" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <signal name="PropertiesChanged"> + <arg name="interface" type="s"/> + <arg name="changed_properties" type="a{sv}"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> + <arg name="invalidated_properties" type="as"/> + </signal> + </interface> +</node> diff --git a/src/bluetooth/bluez/properties.cpp b/src/bluetooth/bluez/properties.cpp new file mode 100644 index 00000000..53c9021c --- /dev/null +++ b/src/bluetooth/bluez/properties.cpp @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -p properties -v org.freedesktop.dbus.properties.xml + * + * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "properties_p.h" + +/* + * Implementation of interface class OrgFreedesktopDBusPropertiesInterface + */ + +OrgFreedesktopDBusPropertiesInterface::OrgFreedesktopDBusPropertiesInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +OrgFreedesktopDBusPropertiesInterface::~OrgFreedesktopDBusPropertiesInterface() +{ +} + diff --git a/src/bluetooth/bluez/properties_p.h b/src/bluetooth/bluez/properties_p.h new file mode 100644 index 00000000..44a79664 --- /dev/null +++ b/src/bluetooth/bluez/properties_p.h @@ -0,0 +1,71 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -p properties -v org.freedesktop.dbus.properties.xml + * + * qdbusxml2cpp is Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef PROPERTIES_H_1396952220 +#define PROPERTIES_H_1396952220 + +#include <QtCore/QObject> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtDBus/QtDBus> + +/* + * Proxy class for interface org.freedesktop.DBus.Properties + */ +class OrgFreedesktopDBusPropertiesInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.freedesktop.DBus.Properties"; } + +public: + OrgFreedesktopDBusPropertiesInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~OrgFreedesktopDBusPropertiesInterface(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<QDBusVariant> Get(const QString &interface, const QString &name) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(interface) << QVariant::fromValue(name); + return asyncCallWithArgumentList(QLatin1String("Get"), argumentList); + } + + inline QDBusPendingReply<QVariantMap> GetAll(const QString &interface) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(interface); + return asyncCallWithArgumentList(QLatin1String("GetAll"), argumentList); + } + + inline QDBusPendingReply<> Set(const QString &interface, const QString &name, const QDBusVariant &value) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(interface) << QVariant::fromValue(name) << QVariant::fromValue(value); + return asyncCallWithArgumentList(QLatin1String("Set"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, const QStringList &invalidated_properties); +}; + +namespace org { + namespace freedesktop { + namespace DBus { + typedef ::OrgFreedesktopDBusPropertiesInterface Properties; + } + } +} +#endif diff --git a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp index 348378f3..b9117ac8 100644 --- a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp +++ b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtBluetooth module of the Qt Toolkit. @@ -50,6 +50,11 @@ #include "bluez/adapter_p.h" #include "bluez/agent_p.h" #include "bluez/device_p.h" +#include "bluez/bluez5_helper_p.h" +#include "bluez/objectmanager_p.h" +#include "bluez/properties_p.h" +#include "bluez/adapter1_bluez5_p.h" +#include "bluez/device1_bluez5_p.h" QT_BEGIN_NAMESPACE @@ -76,90 +81,124 @@ QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, Q QString QBluetoothLocalDevice::name() const { - if (!d_ptr || !d_ptr->adapter) - return QString(); + if (d_ptr->adapter) { + QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties(); + reply.waitForFinished(); + if (reply.isError()) + return QString(); - QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties(); - reply.waitForFinished(); - if (reply.isError()) - return QString(); + return reply.value().value(QStringLiteral("Name")).toString(); + } else if (d_ptr->adapterBluez5) { + return d_ptr->adapterBluez5->name(); + } - return reply.value().value(QLatin1String("Name")).toString(); + return QString(); } QBluetoothAddress QBluetoothLocalDevice::address() const { - if (!d_ptr || !d_ptr->adapter) - return QBluetoothAddress(); + if (d_ptr->adapter) { + QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties(); + reply.waitForFinished(); + if (reply.isError()) + return QBluetoothAddress(); - QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties(); - reply.waitForFinished(); - if (reply.isError()) - return QBluetoothAddress(); + return QBluetoothAddress(reply.value().value(QStringLiteral("Address")).toString()); + } else if (d_ptr->adapterBluez5) { + return QBluetoothAddress(d_ptr->adapterBluez5->address()); + } - return QBluetoothAddress(reply.value().value(QLatin1String("Address")).toString()); + return QBluetoothAddress(); } void QBluetoothLocalDevice::powerOn() { - if (!d_ptr || !d_ptr->adapter) - return; - - d_ptr->adapter->SetProperty(QLatin1String("Powered"), QDBusVariant(QVariant::fromValue(true))); + if (d_ptr->adapter) + d_ptr->adapter->SetProperty(QStringLiteral("Powered"), QDBusVariant(QVariant::fromValue(true))); + else if (d_ptr->adapterBluez5) + d_ptr->adapterBluez5->setPowered(true); } void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode) { - if (!d_ptr || !d_ptr->adapter) + if (!isValid()) return; + Q_D(QBluetoothLocalDevice); + switch (mode) { case HostDiscoverableLimitedInquiry: case HostDiscoverable: if (hostMode() == HostPoweredOff) { // We first have to wait for BT to be powered on, // then we can set the host mode correctly - d_ptr->pendingHostModeChange = (int)HostDiscoverable; - d_ptr->adapter->SetProperty(QStringLiteral("Powered"), + d->pendingHostModeChange = static_cast<int>(HostDiscoverable); + if (d->adapter) { + d->adapter->SetProperty(QStringLiteral("Powered"), QDBusVariant(QVariant::fromValue(true))); + } else { + d->adapterBluez5->setPowered(true); + } } else { - d_ptr->adapter->SetProperty(QStringLiteral("Discoverable"), + if (d->adapter) { + d->adapter->SetProperty(QStringLiteral("Discoverable"), QDBusVariant(QVariant::fromValue(true))); + } else { + d->adapterBluez5->setDiscoverable(true); + } } break; case HostConnectable: if (hostMode() == HostPoweredOff) { - d_ptr->pendingHostModeChange = (int)HostConnectable; - d_ptr->adapter->SetProperty(QStringLiteral("Powered"), + d->pendingHostModeChange = static_cast<int>(HostConnectable); + if (d->adapter) { + d->adapter->SetProperty(QStringLiteral("Powered"), QDBusVariant(QVariant::fromValue(true))); + } else { + d->adapterBluez5->setPowered(true); + } } else { - d_ptr->adapter->SetProperty(QStringLiteral("Discoverable"), + if (d->adapter) { + d->adapter->SetProperty(QStringLiteral("Discoverable"), QDBusVariant(QVariant::fromValue(false))); + } else { + d->adapterBluez5->setDiscoverable(false); + } } break; case HostPoweredOff: - d_ptr->adapter->SetProperty(QLatin1String("Powered"), + if (d->adapter) { + d->adapter->SetProperty(QStringLiteral("Powered"), QDBusVariant(QVariant::fromValue(false))); + } else { + d->adapterBluez5->setPowered(false); + } break; } } QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const { - if (!d_ptr || !d_ptr->adapter) - return HostPoweredOff; - - QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties(); - reply.waitForFinished(); - if (reply.isError()) - return HostPoweredOff; - - if (!reply.value().value(QLatin1String("Powered")).toBool()) - return HostPoweredOff; - else if (reply.value().value(QLatin1String("Discoverable")).toBool()) - return HostDiscoverable; - else if (reply.value().value(QLatin1String("Powered")).toBool()) - return HostConnectable; + if (d_ptr->adapter) { + QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties(); + reply.waitForFinished(); + if (reply.isError()) + return HostPoweredOff; + + if (!reply.value().value(QStringLiteral("Powered")).toBool()) + return HostPoweredOff; + else if (reply.value().value(QStringLiteral("Discoverable")).toBool()) + return HostDiscoverable; + else if (reply.value().value(QStringLiteral("Powered")).toBool()) + return HostConnectable; + } else if (d_ptr->adapterBluez5) { + if (!d_ptr->adapterBluez5->powered()) + return HostPoweredOff; + else if (d_ptr->adapterBluez5->discoverable()) + return HostDiscoverable; + else if (d_ptr->adapterBluez5->powered()) + return HostConnectable; + } return HostPoweredOff; } @@ -173,29 +212,55 @@ QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices() { QList<QBluetoothHostInfo> localDevices; - OrgBluezManagerInterface manager(QLatin1String("org.bluez"), QLatin1String("/"), - QDBusConnection::systemBus()); - - QDBusPendingReply<QList<QDBusObjectPath> > reply = manager.ListAdapters(); - reply.waitForFinished(); - if (reply.isError()) - return localDevices; - - foreach (const QDBusObjectPath &path, reply.value()) { - QBluetoothHostInfo hostinfo; - OrgBluezAdapterInterface adapter(QLatin1String("org.bluez"), path.path(), + if (isBluez5()) { + OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"), + QStringLiteral("/"), + QDBusConnection::systemBus()); + QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects(); + reply.waitForFinished(); + if (reply.isError()) + return localDevices; + + foreach (const QDBusObjectPath &path, reply.value().keys()) { + const InterfaceList ifaceList = reply.value().value(path); + foreach (const QString &iface, ifaceList.keys()) { + if (iface == QStringLiteral("org.bluez.Adapter1")) { + QBluetoothHostInfo hostInfo; + const QString temp = ifaceList.value(iface).value(QStringLiteral("Address")).toString(); + + hostInfo.setAddress(QBluetoothAddress(temp)); + if (hostInfo.address().isNull()) + continue; + hostInfo.setName(ifaceList.value(iface).value(QStringLiteral("Name")).toString()); + localDevices.append(hostInfo); + } + } + } + } else { + OrgBluezManagerInterface manager(QStringLiteral("org.bluez"), QStringLiteral("/"), QDBusConnection::systemBus()); - QDBusPendingReply<QVariantMap> reply = adapter.GetProperties(); + QDBusPendingReply<QList<QDBusObjectPath> > reply = manager.ListAdapters(); reply.waitForFinished(); if (reply.isError()) - continue; + return localDevices; + + foreach (const QDBusObjectPath &path, reply.value()) { + QBluetoothHostInfo hostinfo; + OrgBluezAdapterInterface adapter(QStringLiteral("org.bluez"), path.path(), + QDBusConnection::systemBus()); + + QDBusPendingReply<QVariantMap> reply = adapter.GetProperties(); + reply.waitForFinished(); + if (reply.isError()) + continue; - hostinfo.setAddress(QBluetoothAddress( - reply.value().value(QLatin1String("Address")).toString())); - hostinfo.setName(reply.value().value(QLatin1String("Name")).toString()); + hostinfo.setAddress(QBluetoothAddress( + reply.value().value(QStringLiteral("Address")).toString())); + hostinfo.setName(reply.value().value(QStringLiteral("Name")).toString()); - localDevices.append(hostinfo); + localDevices.append(hostinfo); + } } return localDevices; @@ -221,7 +286,7 @@ static inline OrgBluezDeviceInterface *getDevice(const QBluetoothAddress &addres void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing) { - if (address.isNull()) { + if (address.isNull() || !isValid()) { QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(QBluetoothLocalDevice::Error, QBluetoothLocalDevice::PairingError)); @@ -230,12 +295,32 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai const Pairing current_pairing = pairingStatus(address); if (current_pairing == pairing) { + if (d_ptr->adapterBluez5) { + // A possibly running discovery or pending pairing request should be canceled + if (d_ptr->pairingDiscoveryTimer && d_ptr->pairingDiscoveryTimer->isActive()) { + d_ptr->pairingDiscoveryTimer->stop(); + } + + if (d_ptr->pairingTarget) { + qCDebug(QT_BT_BLUEZ) << "Cancelling pending pairing request to" << d_ptr->pairingTarget->address(); + QDBusPendingReply<> cancelReply = d_ptr->pairingTarget->CancelPairing(); + cancelReply.waitForFinished(); + delete d_ptr->pairingTarget; + d_ptr->pairingTarget = 0; + } + + } QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection, Q_ARG(QBluetoothAddress, address), Q_ARG(QBluetoothLocalDevice::Pairing, pairing)); return; } + if (d_ptr->adapterBluez5) { + d_ptr->requestPairingBluez5(address, pairing); + return; + } + if (pairing == Paired || pairing == AuthorizedPaired) { d_ptr->address = address; d_ptr->pairing = pairing; @@ -339,43 +424,238 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai } } +void QBluetoothLocalDevicePrivate::requestPairingBluez5(const QBluetoothAddress &targetAddress, + QBluetoothLocalDevice::Pairing targetPairing) +{ + if (!managerBluez5) + return; + + //are we already discovering something? -> abort those attempts + if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) { + pairingDiscoveryTimer->stop(); + if (!discoveryWasAlreadyActive) + adapterBluez5->StopDiscovery(); + } + + if (pairingTarget) { + delete pairingTarget; + pairingTarget = 0; + } + + // pairing implies that the device was found + // if we cannot find it we may have to turn on Discovery mode for a limited amount of time + + // check device doesn't already exist + QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects(); + reply.waitForFinished(); + if (reply.isError()) { + emit q_ptr->error(QBluetoothLocalDevice::PairingError); + return; + } + + + foreach (const QDBusObjectPath &path, reply.value().keys()) { + const InterfaceList ifaceList = reply.value().value(path); + foreach (const QString &iface, ifaceList.keys()) { + + if (iface == QStringLiteral("org.bluez.Device1")) { + + OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), + path.path(), + QDBusConnection::systemBus()); + if (targetAddress == QBluetoothAddress(device.address())) { + qCDebug(QT_BT_BLUEZ) << "Initiating direct pair to" << targetAddress.toString(); + //device exist -> directly work with it + processPairingBluez5(path.path(), targetPairing); + return; + } + } + } + } + + //no device matching -> turn on discovery + + //remember whether we were discovering already + //if it was on don't modify it + discoveryWasAlreadyActive = adapterBluez5->discovering(); + + if (!discoveryWasAlreadyActive) + adapterBluez5->StartDiscovery(); + + address = targetAddress; + pairing = targetPairing; + if (!pairingDiscoveryTimer) { + pairingDiscoveryTimer = new QTimer(this); + pairingDiscoveryTimer->setSingleShot(true); + pairingDiscoveryTimer->setInterval(20000); //20s + connect(pairingDiscoveryTimer, SIGNAL(timeout()), + SLOT(pairingDiscoveryTimedOut())); + } + + qCDebug(QT_BT_BLUEZ) << "Initiating discovery for pairing on" << targetAddress.toString(); + pairingDiscoveryTimer->start(); +} + +/*! + * \internal + * + * Found a matching device. Now we must ensure its pairing/trusted state is as desired. + * If it has to be paired then we need another roundtrip through the event loop + * while we wait for the user to accept the pairing dialogs. + */ +void QBluetoothLocalDevicePrivate::processPairingBluez5(const QString &objectPath, + QBluetoothLocalDevice::Pairing target) +{ + if (pairingTarget) + delete pairingTarget; + + //stop possibly running discovery + if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) { + pairingDiscoveryTimer->stop(); + + if (!discoveryWasAlreadyActive) + adapterBluez5->StopDiscovery(); + } + + pairingTarget = new OrgBluezDevice1Interface(QStringLiteral("org.bluez"), objectPath, + QDBusConnection::systemBus(), this); + const QBluetoothAddress targetAddress(pairingTarget->address()); + + Q_Q(QBluetoothLocalDevice); + + switch (target) { + case QBluetoothLocalDevice::Unpaired: { + delete pairingTarget; + pairingTarget = 0; + + QDBusPendingReply<> removeReply = adapterBluez5->RemoveDevice(QDBusObjectPath(objectPath)); + removeReply.waitForFinished(); + + if (removeReply.isError()) + emit q->error(QBluetoothLocalDevice::PairingError); + else + emit q->pairingFinished(targetAddress, QBluetoothLocalDevice::Unpaired); + + break; + } + case QBluetoothLocalDevice::Paired: + case QBluetoothLocalDevice::AuthorizedPaired: + pairing = target; + + if (!pairingTarget->paired()) { + qCDebug(QT_BT_BLUEZ) << "Sending pairing request to" << pairingTarget->address(); + //initiate the pairing + QDBusPendingReply<> pairReply = pairingTarget->Pair(); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pairReply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + SLOT(pairingCompleted(QDBusPendingCallWatcher*))); + return; + } + + //already paired but Trust level must be adjusted + if (target == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted()) + pairingTarget->setTrusted(true); + else if (target == QBluetoothLocalDevice::Paired && pairingTarget->trusted()) + pairingTarget->setTrusted(false); + + delete pairingTarget; + pairingTarget = 0; + + emit q->pairingFinished(targetAddress, target); + + break; + default: + break; + } +} + +void QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut() +{ + qCWarning(QT_BT_BLUEZ) << "Discovery for pairing purposes failed. Cannot find parable device."; + + if (!discoveryWasAlreadyActive) + adapterBluez5->StopDiscovery(); + + emit q_ptr->error(QBluetoothLocalDevice::PairingError); +} + QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus( const QBluetoothAddress &address) const { if (address.isNull()) return Unpaired; - OrgBluezDeviceInterface *device = getDevice(address, d_ptr); + if (d_ptr->adapter) { + OrgBluezDeviceInterface *device = getDevice(address, d_ptr); - if (!device) - return Unpaired; + if (!device) + return Unpaired; - QDBusPendingReply<QVariantMap> deviceReply = device->GetProperties(); - deviceReply.waitForFinished(); - if (deviceReply.isError()) - return Unpaired; + QDBusPendingReply<QVariantMap> deviceReply = device->GetProperties(); + deviceReply.waitForFinished(); + if (deviceReply.isError()) + return Unpaired; - QVariantMap map = deviceReply.value(); + QVariantMap map = deviceReply.value(); - if (map.value(QLatin1String("Trusted")).toBool() && map.value(QLatin1String("Paired")).toBool()) - return AuthorizedPaired; - else if (map.value(QLatin1String("Paired")).toBool()) - return Paired; - else - return Unpaired; + if (map.value(QLatin1String("Trusted")).toBool() && map.value(QLatin1String("Paired")).toBool()) + return AuthorizedPaired; + else if (map.value(QLatin1String("Paired")).toBool()) + return Paired; + } else if (d_ptr->adapterBluez5) { + + QDBusPendingReply<ManagedObjectList> reply = d_ptr->managerBluez5->GetManagedObjects(); + reply.waitForFinished(); + if (reply.isError()) + return Unpaired; + + foreach (const QDBusObjectPath &path, reply.value().keys()) { + const InterfaceList ifaceList = reply.value().value(path); + foreach (const QString &iface, ifaceList.keys()) { + + if (iface == QStringLiteral("org.bluez.Device1")) { + + OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), + path.path(), + QDBusConnection::systemBus()); + + if (address == QBluetoothAddress(device.address())) { + if (device.trusted() && device.paired()) + return AuthorizedPaired; + else if (device.paired()) + return Paired; + else + return Unpaired; + } + } + } + } + } + + return Unpaired; } QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q, QBluetoothAddress address) : - adapter(0), - agent(0), - localAddress(address), - pendingHostModeChange(-1), - msgConnection(0), - q_ptr(q), - connectedCached(false) -{ - initializeAdapter(); + adapter(0), + adapterBluez5(0), + adapterProperties(0), + managerBluez5(0), + agent(0), + localAddress(address), + pairingTarget(0), + pairingDiscoveryTimer(0), + discoveryWasAlreadyActive(true), + pendingHostModeChange(-1), + msgConnection(0), + q_ptr(q), + connectedCached(false) +{ + if (isBluez5()) + initializeAdapterBluez5(); + else + initializeAdapter(); + connectDeviceChanges(); } @@ -388,6 +668,33 @@ void QBluetoothLocalDevicePrivate::connectDeviceChanges() SLOT(_q_deviceCreated(QDBusObjectPath))); connect(adapter, SIGNAL(DeviceRemoved(QDBusObjectPath)), SLOT(_q_deviceRemoved(QDBusObjectPath))); + } else if (adapterBluez5 && managerBluez5) { + //setup property change notifications for all existing devices + QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects(); + reply.waitForFinished(); + if (reply.isError()) + return; + + OrgFreedesktopDBusPropertiesInterface *monitor = 0; + foreach (const QDBusObjectPath &path, reply.value().keys()) { + const InterfaceList ifaceList = reply.value().value(path); + foreach (const QString &iface, ifaceList.keys()) { + if (iface == QStringLiteral("org.bluez.Device1")) { + monitor = new OrgFreedesktopDBusPropertiesInterface(QStringLiteral("org.bluez"), + path.path(), + QDBusConnection::systemBus(), this); + connect(monitor, SIGNAL(PropertiesChanged(QString,QVariantMap,QStringList)), + SLOT(PropertiesChanged(QString,QVariantMap,QStringList))); + deviceChangeMonitors.insert(path.path(), monitor); + + const QVariantMap ifaceValues = ifaceList.value(QStringLiteral("org.bluez.Device1")); + if (ifaceValues.value(QStringLiteral("Connected"), false).toBool()) { + QBluetoothAddress address(ifaceValues.value(QStringLiteral("Address")).toString()); + connectedDevicesSet.insert(address); + } + } + } + } } } @@ -395,8 +702,13 @@ QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate() { delete msgConnection; delete adapter; + delete adapterBluez5; + delete adapterProperties; + delete managerBluez5; delete agent; + delete pairingTarget; qDeleteAll(devices); + qDeleteAll(deviceChangeMonitors); } void QBluetoothLocalDevicePrivate::initializeAdapter() @@ -453,9 +765,203 @@ void QBluetoothLocalDevicePrivate::initializeAdapter() } } +void QBluetoothLocalDevicePrivate::initializeAdapterBluez5() +{ + if (adapterBluez5) + return; + + //get all local adapters + if (!managerBluez5) + managerBluez5 = new OrgFreedesktopDBusObjectManagerInterface( + QStringLiteral("org.bluez"), + QStringLiteral("/"), + QDBusConnection::systemBus(), this); + + connect(managerBluez5, SIGNAL(InterfacesAdded(QDBusObjectPath,InterfaceList)), + SLOT(InterfacesAdded(QDBusObjectPath,InterfaceList))); + connect(managerBluez5, SIGNAL(InterfacesRemoved(QDBusObjectPath,QStringList)), + SLOT(InterfacesRemoved(QDBusObjectPath,QStringList))); + + QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects(); + reply.waitForFinished(); + if (reply.isError()) + return; + + typedef QPair<QString, QBluetoothAddress> AddressForPathType; + QList<AddressForPathType> localAdapters; + + foreach (const QDBusObjectPath &path, reply.value().keys()) { + const InterfaceList ifaceList = reply.value().value(path); + foreach (const QString &iface, ifaceList.keys()) { + if (iface == QStringLiteral("org.bluez.Adapter1")) { + AddressForPathType pair; + pair.first = path.path(); + pair.second = QBluetoothAddress(ifaceList.value(iface).value( + QStringLiteral("Address")).toString()); + if (!pair.second.isNull()) + localAdapters.append(pair); + break; + } + } + } + + if (localAdapters.isEmpty()) + return; + + if (localAddress.isNull()) { + //concept of DefaultAdapter doesn't exist anymore. + //we define the first adapter as default + adapterBluez5 = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"), + localAdapters.front().first, + QDBusConnection::systemBus(), this); + } else { + foreach (const AddressForPathType &pair, localAdapters) { + if (pair.second == localAddress) { + adapterBluez5 = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"), + pair.first, + QDBusConnection::systemBus(), this); + break; + } + } + + if (!adapterBluez5) //no match + return; + } + + if (adapterBluez5) { + //hook up propertiesChanged for current adapter + adapterProperties = new OrgFreedesktopDBusPropertiesInterface( + QStringLiteral("org.bluez"), adapterBluez5->path(), + QDBusConnection::systemBus(), this); + connect(adapterProperties, SIGNAL(PropertiesChanged(QString,QVariantMap,QStringList)), + SLOT(PropertiesChanged(QString,QVariantMap,QStringList))); + } + + currentMode = static_cast<QBluetoothLocalDevice::HostMode>(-1); +} + +// Bluez 5 +void QBluetoothLocalDevicePrivate::PropertiesChanged(const QString &interface, + const QVariantMap &changed_properties, + const QStringList &/*invalidated_properties*/) +{ + //qDebug() << "Change" << interface << changed_properties; + if (interface == QStringLiteral("org.bluez.Adapter1")) { + //update host mode + if (changed_properties.contains(QStringLiteral("Discoverable")) + || changed_properties.contains(QStringLiteral("Powered"))) { + + QBluetoothLocalDevice::HostMode mode; + + if (!adapterBluez5->powered()) { + mode = QBluetoothLocalDevice::HostPoweredOff; + } else { + if (adapterBluez5->discoverable()) + mode = QBluetoothLocalDevice::HostDiscoverable; + else + mode = QBluetoothLocalDevice::HostConnectable; + + if (pendingHostModeChange != -1) { + + if (static_cast<int>(mode) != pendingHostModeChange) { + adapterBluez5->setDiscoverable( + pendingHostModeChange + == static_cast<int>(QBluetoothLocalDevice::HostDiscoverable)); + pendingHostModeChange = -1; + return; + } + pendingHostModeChange = -1; + } + } + + if (mode != currentMode) + emit q_ptr->hostModeStateChanged(mode); + + currentMode = mode; + } + } else if (interface == QStringLiteral("org.bluez.Device1") + && changed_properties.contains(QStringLiteral("Connected"))) { + // update list of connected devices + OrgFreedesktopDBusPropertiesInterface *senderIface = + qobject_cast<OrgFreedesktopDBusPropertiesInterface*>(sender()); + if (!senderIface) + return; + + const QString currentPath = senderIface->path(); + bool isConnected = changed_properties.value(QStringLiteral("Connected"), false).toBool(); + OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), currentPath, + QDBusConnection::systemBus()); + const QBluetoothAddress changedAddress(device.address()); + bool isInSet = connectedDevicesSet.contains(changedAddress); + if (isConnected && !isInSet) { + connectedDevicesSet.insert(changedAddress); + emit q_ptr->deviceConnected(changedAddress); + } else if (!isConnected && isInSet) { + connectedDevicesSet.remove(changedAddress); + emit q_ptr->deviceDisconnected(changedAddress); + } + } +} + +void QBluetoothLocalDevicePrivate::InterfacesAdded(const QDBusObjectPath &object_path, InterfaceList interfaces_and_properties) +{ + if (interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1")) + && !deviceChangeMonitors.contains(object_path.path())) { + // a new device was added which we need to add to list of known devices + OrgFreedesktopDBusPropertiesInterface *monitor = new OrgFreedesktopDBusPropertiesInterface( + QStringLiteral("org.bluez"), + object_path.path(), + QDBusConnection::systemBus()); + connect(monitor, SIGNAL(PropertiesChanged(QString,QVariantMap,QStringList)), + SLOT(PropertiesChanged(QString,QVariantMap,QStringList))); + deviceChangeMonitors.insert(object_path.path(), monitor); + + const QVariantMap ifaceValues = interfaces_and_properties.value(QStringLiteral("org.bluez.Device1")); + if (ifaceValues.value(QStringLiteral("Connected"), false).toBool()) { + QBluetoothAddress address(ifaceValues.value(QStringLiteral("Address")).toString()); + connectedDevicesSet.insert(address); + emit q_ptr->deviceConnected(address); + } + } + + if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive() + && interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))) { + //device discovery for pairing found new remote device + OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), + object_path.path(), QDBusConnection::systemBus()); + if (!address.isNull() && address == QBluetoothAddress(device.address())) { + pairingDiscoveryTimer->stop(); + if (!discoveryWasAlreadyActive) + adapterBluez5->StopDiscovery(); + + processPairingBluez5(object_path.path(), pairing); + + } + } +} + +void QBluetoothLocalDevicePrivate::InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces) +{ + if (deviceChangeMonitors.contains(object_path.path()) + && interfaces.contains(QStringLiteral("org.bluez.Device1"))) { + + //a device was removed + delete deviceChangeMonitors.take(object_path.path()); + + //the path contains the address (e.g.: /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX) + //-> use it to update current list of connected devices + QString addressString = object_path.path().right(17); + addressString.replace(QStringLiteral("_"), QStringLiteral(":")); + const QBluetoothAddress address(addressString); + bool found = connectedDevicesSet.remove(address); + if (found) + emit q_ptr->deviceDisconnected(address); + } +} + bool QBluetoothLocalDevicePrivate::isValid() const { - return adapter; + return adapter || adapterBluez5; } void QBluetoothLocalDevicePrivate::RequestConfirmation(const QDBusObjectPath &in0, uint in1) @@ -564,9 +1070,8 @@ void QBluetoothLocalDevicePrivate::createCache() } if (properties.value().value(QLatin1String("Connected")).toBool()) { - connectedDevicesSet.insert(QBluetoothAddress(properties.value().value(QLatin1String( - "Address")). - toString())); + connectedDevicesSet.insert( + QBluetoothAddress(properties.value().value(QLatin1String("Address")).toString())); } } connectedCached = true; @@ -574,8 +1079,9 @@ void QBluetoothLocalDevicePrivate::createCache() QList<QBluetoothAddress> QBluetoothLocalDevicePrivate::connectedDevices() const { - if (!connectedCached) + if (adapter && !connectedCached) const_cast<QBluetoothLocalDevicePrivate *>(this)->createCache(); + return connectedDevicesSet.toList(); } @@ -618,32 +1124,63 @@ void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *wat QDBusPendingReply<> reply = *watcher; if (reply.isError()) { - qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to create pairing" << reply.error(); - emit q->error(QBluetoothLocalDevice::PairingError); - delete watcher; + qCWarning(QT_BT_BLUEZ) << "Failed to create pairing" << reply.error().name(); + if (reply.error().name() != QStringLiteral("org.bluez.Error.AuthenticationCanceled")) + emit q->error(QBluetoothLocalDevice::PairingError); + watcher->deleteLater(); return; } - QDBusPendingReply<QDBusObjectPath> findReply = adapter->FindDevice(address.toString()); - findReply.waitForFinished(); - if (findReply.isError()) { - qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to find device" << findReply.error(); - emit q->error(QBluetoothLocalDevice::PairingError); - delete watcher; - return; - } + if (adapter) { + QDBusPendingReply<QDBusObjectPath> findReply = adapter->FindDevice(address.toString()); + findReply.waitForFinished(); + if (findReply.isError()) { + qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to find device" << findReply.error(); + emit q->error(QBluetoothLocalDevice::PairingError); + watcher->deleteLater(); + return; + } - OrgBluezDeviceInterface device(QLatin1String("org.bluez"), findReply.value().path(), - QDBusConnection::systemBus()); + OrgBluezDeviceInterface device(QStringLiteral("org.bluez"), findReply.value().path(), + QDBusConnection::systemBus()); - if (pairing == QBluetoothLocalDevice::AuthorizedPaired) { - device.SetProperty(QLatin1String("Trusted"), QDBusVariant(QVariant(true))); - emit q->pairingFinished(address, QBluetoothLocalDevice::AuthorizedPaired); - } else { - device.SetProperty(QLatin1String("Trusted"), QDBusVariant(QVariant(false))); - emit q->pairingFinished(address, QBluetoothLocalDevice::Paired); + if (pairing == QBluetoothLocalDevice::AuthorizedPaired) { + device.SetProperty(QStringLiteral("Trusted"), QDBusVariant(QVariant(true))); + emit q->pairingFinished(address, QBluetoothLocalDevice::AuthorizedPaired); + } + else { + device.SetProperty(QStringLiteral("Trusted"), QDBusVariant(QVariant(false))); + emit q->pairingFinished(address, QBluetoothLocalDevice::Paired); + } + } else if (adapterBluez5) { + if (!pairingTarget) { + qCWarning(QT_BT_BLUEZ) << "Pairing target expected but found null pointer."; + emit q->error(QBluetoothLocalDevice::PairingError); + watcher->deleteLater(); + return; + } + + if (!pairingTarget->paired()) { + qCWarning(QT_BT_BLUEZ) << "Device was not paired as requested"; + emit q->error(QBluetoothLocalDevice::PairingError); + watcher->deleteLater(); + return; + } + + const QBluetoothAddress targetAddress(pairingTarget->address()); + + if (pairing == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted()) + pairingTarget->setTrusted(true); + else if (pairing == QBluetoothLocalDevice::Paired && pairingTarget->trusted()) + pairingTarget->setTrusted(false); + + delete pairingTarget; + pairingTarget = 0; + + emit q->pairingFinished(targetAddress, pairing); } - delete watcher; + + watcher->deleteLater(); } void QBluetoothLocalDevicePrivate::Authorize(const QDBusObjectPath &in0, const QString &in1) @@ -689,6 +1226,7 @@ uint QBluetoothLocalDevicePrivate::RequestPasskey(const QDBusObjectPath &in0) return qrand()&0x1000000; } +// Bluez 4 void QBluetoothLocalDevicePrivate::PropertyChanged(QString property, QDBusVariant value) { Q_UNUSED(value); diff --git a/src/bluetooth/qbluetoothlocaldevice_p.h b/src/bluetooth/qbluetoothlocaldevice_p.h index 24b42670..7fc82e2f 100644 --- a/src/bluetooth/qbluetoothlocaldevice_p.h +++ b/src/bluetooth/qbluetoothlocaldevice_p.h @@ -52,10 +52,15 @@ #include <QDBusObjectPath> #include <QDBusMessage> #include <QSet> +#include "bluez/bluez5_helper_p.h" class OrgBluezAdapterInterface; +class OrgBluezAdapter1Interface; +class OrgFreedesktopDBusPropertiesInterface; +class OrgFreedesktopDBusObjectManagerInterface; class OrgBluezAgentAdaptor; class OrgBluezDeviceInterface; +class OrgBluezDevice1Interface; QT_BEGIN_NAMESPACE class QDBusPendingCallWatcher; @@ -126,7 +131,11 @@ public: QSet<OrgBluezDeviceInterface *> devices; QSet<QBluetoothAddress> connectedDevicesSet; - OrgBluezAdapterInterface *adapter; + OrgBluezAdapterInterface *adapter; //Bluez 4 + OrgBluezAdapter1Interface *adapterBluez5; //Bluez 5 + OrgFreedesktopDBusPropertiesInterface *adapterProperties; //Bluez 5 + OrgFreedesktopDBusObjectManagerInterface *managerBluez5; //Bluez 5 + QMap<QString, OrgFreedesktopDBusPropertiesInterface *> deviceChangeMonitors; //Bluez 5 OrgBluezAgentAdaptor *agent; QList<QBluetoothAddress> connectedDevices() const; @@ -135,6 +144,9 @@ public: QBluetoothAddress localAddress; QBluetoothAddress address; QBluetoothLocalDevice::Pairing pairing; + OrgBluezDevice1Interface *pairingTarget; + QTimer *pairingDiscoveryTimer; + bool discoveryWasAlreadyActive; QBluetoothLocalDevice::HostMode currentMode; int pendingHostModeChange; @@ -157,6 +169,21 @@ public slots: void _q_devicePropertyChanged(const QString &property, const QDBusVariant &value); bool isValid() const; + void requestPairingBluez5(const QBluetoothAddress &address, + QBluetoothLocalDevice::Pairing targetPairing); + +private Q_SLOTS: + void PropertiesChanged(const QString &interface, + const QVariantMap &changed_properties, + const QStringList &invalidated_properties); + void InterfacesAdded(const QDBusObjectPath &object_path, + InterfaceList interfaces_and_properties); + void InterfacesRemoved(const QDBusObjectPath &object_path, + const QStringList &interfaces); + void processPairingBluez5(const QString &objectPath, + QBluetoothLocalDevice::Pairing target); + void pairingDiscoveryTimedOut(); + private: void createCache(); void connectDeviceChanges(); @@ -169,6 +196,7 @@ private: bool connectedCached; void initializeAdapter(); + void initializeAdapterBluez5(); }; #elif defined(QT_QNX_BLUETOOTH) diff --git a/tests/bttestui/btlocaldevice.cpp b/tests/bttestui/btlocaldevice.cpp index 3a9b52b5..d67b13fb 100644 --- a/tests/bttestui/btlocaldevice.cpp +++ b/tests/bttestui/btlocaldevice.cpp @@ -144,10 +144,20 @@ void BtLocalDevice::requestPairingUpdate(bool isPairing) if (baddr.isNull()) return; - if (isPairing) - localDevice->requestPairing(baddr, QBluetoothLocalDevice::Paired); - else + + + if (isPairing) { + //toggle between authorized and non-authorized pairing to achieve better + //level of testing + static short pairing = 0; + if ((pairing%2) == 1) + localDevice->requestPairing(baddr, QBluetoothLocalDevice::Paired); + else + localDevice->requestPairing(baddr, QBluetoothLocalDevice::AuthorizedPaired); + pairing++; + } else { localDevice->requestPairing(baddr, QBluetoothLocalDevice::Unpaired); + } for (int i = 0; i < foundTestServers.count(); i++) { if (isPairing) |