Search
SailfishOS Open Build Service
>
Projects
>
nemo
:
testing:hw
:
lge
:
hammerhead
>
kf5bluezqt
> _service:tar_git:0003-Add-limited-support-for-a-BlueZ-4-backend.-Fixes-JB-.patch
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File _service:tar_git:0003-Add-limited-support-for-a-BlueZ-4-backend.-Fixes-JB-.patch of Package kf5bluezqt
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Pekka Vuorela <pekka.vuorela@jolla.com> Date: Wed, 12 Jan 2022 15:07:40 +0200 Subject: [PATCH] Add (limited) support for a BlueZ 4 backend. Fixes JB#36054 Add limited support for a BlueZ 4 backend. The majority of the API is supported; see the README for details on current support. Instead of building kf5bluezqt packages, the spec sets 'Provides: kf5bluezqt' and builds either kf5bluezqt-bluez4-* or kf5bluezqt-bluez5-* packages depending on the value of the KF5BLUEZQT_BLUEZ_VERSION environment variable (defaulting to bluez5 if this is not set). BlueZ 4 support is #ifdef'd by the KF5BLUEZQT_BLUEZ_VERSION define. Changes mainly consist of: - Using the BlueZ 4 versions of the XML D-Bus interface definitions, added under bluezqt-/src/interfaces/bluez4 - Removing uses of DBusProperties - Adding proxy agents so that the default agent can be reused as the application agent - Returning PendingCall::NotSupported for features not provided by the BlueZ 4 API, such as MediaPlayer::play() - Manually managing OBEX OPP sessions in OBEX Manager, as session support was limited to FTP sessions in BlueZ 4 --- src/adapter.cpp | 10 + src/adapter.h | 3 + src/adapter_p.cpp | 70 ++++ src/adapter_p.h | 24 ++ src/agent.cpp | 141 ++++++++ src/agent.h | 35 ++ src/agentadaptor.cpp | 8 + src/agentadaptor.h | 8 + src/bluezqt_dbustypes.h | 8 + src/device.cpp | 42 +++ src/device_p.cpp | 47 ++- src/device_p.h | 21 ++ src/input.cpp | 8 + src/input_p.h | 6 + src/interfaces/bluez4/bluez4.pri | 47 +++ src/interfaces/bluez4/org.bluez.Adapter.xml | 65 ++++ src/interfaces/bluez4/org.bluez.Device.xml | 25 ++ src/interfaces/bluez4/org.bluez.Manager.xml | 32 ++ .../bluez4/org.bluez.MediaPlayer.xml | 15 + .../bluez4/org.bluez.MediaTransport.xml | 27 ++ .../bluez4/org.bluez.obex.Client.xml | 14 + .../bluez4/org.bluez.obex.FileTransfer.xml | 41 +++ .../bluez4/org.bluez.obex.Manager.xml | 24 ++ .../bluez4/org.bluez.obex.ObjectPush.xml | 21 ++ .../bluez4/org.bluez.obex.Transfer.xml | 30 ++ src/interfaces/interfaces.pri | 58 +++ src/macros.h | 12 + src/manager.cpp | 36 ++ src/manager_p.cpp | 341 ++++++++++++++++++ src/manager_p.h | 44 +++ src/mediaplayer.cpp | 42 +++ src/mediaplayer_p.cpp | 22 ++ src/mediaplayer_p.h | 14 + src/mediatransport.cpp | 15 + src/mediatransport_p.cpp | 22 ++ src/mediatransport_p.h | 15 + src/obexagentadaptor.cpp | 42 +++ src/obexagentadaptor.h | 14 + src/obexfiletransfer.cpp | 13 + src/obexmanager.cpp | 44 +++ src/obexmanager.h | 4 + src/obexmanager_p.cpp | 323 +++++++++++++++++ src/obexmanager_p.h | 70 ++++ src/obexobjectpush.cpp | 13 + src/obexsession.cpp | 20 + src/obexsession_p.h | 12 + src/obextransfer.cpp | 104 ++++++ src/obextransfer.h | 8 + src/obextransfer_p.h | 23 ++ src/pendingcall.cpp | 18 + src/request.cpp | 50 +++ src/request.h | 8 + src/src.pro | 61 +--- 53 files changed, 2166 insertions(+), 54 deletions(-) create mode 100644 src/interfaces/bluez4/bluez4.pri create mode 100644 src/interfaces/bluez4/org.bluez.Adapter.xml create mode 100644 src/interfaces/bluez4/org.bluez.Device.xml create mode 100644 src/interfaces/bluez4/org.bluez.Manager.xml create mode 100644 src/interfaces/bluez4/org.bluez.MediaPlayer.xml create mode 100644 src/interfaces/bluez4/org.bluez.MediaTransport.xml create mode 100644 src/interfaces/bluez4/org.bluez.obex.Client.xml create mode 100644 src/interfaces/bluez4/org.bluez.obex.FileTransfer.xml create mode 100644 src/interfaces/bluez4/org.bluez.obex.Manager.xml create mode 100644 src/interfaces/bluez4/org.bluez.obex.ObjectPush.xml create mode 100644 src/interfaces/bluez4/org.bluez.obex.Transfer.xml create mode 100644 src/interfaces/interfaces.pri diff --git a/src/adapter.cpp b/src/adapter.cpp index cc38928..4b2f5fd 100644 --- a/src/adapter.cpp +++ b/src/adapter.cpp @@ -57,13 +57,23 @@ QString Adapter::address() const QString Adapter::name() const { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return d->m_alias; +#else + return d->m_name; +#endif } PendingCall *Adapter::setName(const QString &name) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->setDBusProperty(QStringLiteral("Alias"), name), PendingCall::ReturnVoid, this); +#else + // "Alias" property is not present in BlueZ 4 + return new PendingCall(d->setDBusProperty(QStringLiteral("Name"), name), + PendingCall::ReturnVoid, this); +#endif } QString Adapter::systemName() const diff --git a/src/adapter.h b/src/adapter.h index 2c09218..0f9dc7d 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -363,6 +363,9 @@ private: friend class AdapterPrivate; friend class ManagerPrivate; friend class InitAdaptersJobPrivate; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + friend class DevicePrivate; +#endif }; } // namespace BluezQt diff --git a/src/adapter_p.cpp b/src/adapter_p.cpp index 786fa7d..2ef9718 100644 --- a/src/adapter_p.cpp +++ b/src/adapter_p.cpp @@ -25,12 +25,20 @@ #include "utils.h" #include "macros.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "agent.h" +#endif + namespace BluezQt { AdapterPrivate::AdapterPrivate(const QString &path, const QVariantMap &properties) : QObject() +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusProperties(nullptr) +#else + , m_pairingAgent(nullptr) +#endif , m_adapterClass(0) , m_powered(0) , m_discoverable(false) @@ -45,6 +53,7 @@ AdapterPrivate::AdapterPrivate(const QString &path, const QVariantMap &propertie void AdapterPrivate::init(const QVariantMap &properties) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_dbusProperties = new DBusProperties(Strings::orgBluez(), m_bluezAdapter->path(), DBusConnection::orgBluez(), this); @@ -55,6 +64,10 @@ void AdapterPrivate::init(const QVariantMap &properties) // powered off when the PropertiesChanged signal is emitted ... connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &AdapterPrivate::propertiesChanged, Qt::QueuedConnection); +#else + connect(m_bluezAdapter, &BluezAdapter::PropertyChanged, + this, &AdapterPrivate::adapterPropertyChanged); +#endif // Init properties m_address = properties.value(QStringLiteral("Address")).toString(); @@ -90,20 +103,40 @@ void AdapterPrivate::removeDevice(const DevicePtr &device) QDBusPendingReply<> AdapterPrivate::setDBusProperty(const QString &name, const QVariant &value) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return m_dbusProperties->Set(Strings::orgBluezAdapter1(), name, QDBusVariant(value)); +#else + return m_bluezAdapter->SetProperty(name, QDBusVariant(value)); +#endif } void AdapterPrivate::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (interface != Strings::orgBluezAdapter1()) { return; } +#else + Q_UNUSED(interface) +#endif QVariantMap::const_iterator i; for (i = changed.constBegin(); i != changed.constEnd(); ++i) { const QVariant &value = i.value(); const QString &property = i.key(); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + if (property == QLatin1String("Name")) { + // In BlueZ 4 there is only 'Name', no 'Alias' + if (m_name != value.toString()) { + m_name = value.toString(); + Q_EMIT q.data()->nameChanged(m_name); + Q_EMIT q.data()->systemNameChanged(m_name); + } + continue; + } +#endif + if (property == QLatin1String("Name")) { PROPERTY_CHANGED(m_name, toString, systemNameChanged); } else if (property == QLatin1String("Alias")) { @@ -138,4 +171,41 @@ void AdapterPrivate::propertiesChanged(const QString &interface, const QVariantM Q_EMIT q.data()->adapterChanged(q.toStrongRef()); } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +QDBusPendingReply<QDBusObjectPath> AdapterPrivate::createPairedDevice(const QString &address) +{ + if (!m_pairingAgent) { + return QDBusMessage::createError(QStringLiteral("org.bluez.Error.Failed"), + QStringLiteral("No pairing agent set!")); + } + + // Create a single-use agent that is a proxy of the default agent. + ProxyAgent *proxyAgent = createProxyForAgent(m_pairingAgent, "/bluez4_pairing_request_agent_proxy"); + connect(proxyAgent, &ProxyAgent::agentReleased, proxyAgent, &ProxyAgent::deleteLater); + + return m_bluezAdapter->CreatePairedDevice(address, proxyAgent->objectPath(), + ProxyAgent::capabilityToString(proxyAgent->capability())); +} + +QDBusPendingReply<void> AdapterPrivate::cancelDeviceCreation(const QString &address) +{ + return m_bluezAdapter->CancelDeviceCreation(address); +} + +ProxyAgent *AdapterPrivate::createProxyForAgent(Agent *agent, const QString &proxyAgentPath) +{ + Q_ASSERT(agent); + + ProxyAgent *proxyAgent = new ProxyAgent(agent, proxyAgentPath, q.data()); + emit agentCreated(proxyAgent); + + return proxyAgent; +} + +void AdapterPrivate::adapterPropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(QStringLiteral("org.bluez.Adapter"), this, property, value.variant()); +} +#endif + } // namespace BluezQt diff --git a/src/adapter_p.h b/src/adapter_p.h index 734364d..f0aa69d 100644 --- a/src/adapter_p.h +++ b/src/adapter_p.h @@ -27,14 +27,22 @@ #include <QStringList> #include "types.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "bluezadapter1.h" #include "dbusproperties.h" +#else +#include "bluezadapter.h" +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::Adapter1 BluezAdapter; typedef org::freedesktop::DBus::Properties DBusProperties; +#else +class ProxyAgent; +#endif class AdapterPrivate : public QObject { @@ -51,9 +59,20 @@ public: QDBusPendingReply<> setDBusProperty(const QString &name, const QVariant &value); void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + QDBusPendingReply<QDBusObjectPath> createPairedDevice(const QString &address); + QDBusPendingReply<void> cancelDeviceCreation(const QString &address); + ProxyAgent *createProxyForAgent(Agent *agent, const QString &proxyAgentPath); + void adapterPropertyChanged(const QString &property, const QDBusVariant &value); +#endif + QWeakPointer<Adapter> q; BluezAdapter *m_bluezAdapter; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusProperties *m_dbusProperties; +#else + Agent *m_pairingAgent; +#endif QString m_address; QString m_name; @@ -68,6 +87,11 @@ public: QStringList m_uuids; QList<DevicePtr> m_devices; QString m_modalias; + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +Q_SIGNALS: + void agentCreated(Agent *agent); +#endif }; } // namespace BluezQt diff --git a/src/agent.cpp b/src/agent.cpp index 42d3db4..324f070 100644 --- a/src/agent.cpp +++ b/src/agent.cpp @@ -22,6 +22,10 @@ #include "agent.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include <QDBusObjectPath> +#endif + namespace BluezQt { @@ -93,4 +97,141 @@ void Agent::release() { } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +ProxyAgent::ProxyAgent(Agent *agent, const QString &pathSuffix, QObject *parent) + : Agent(parent) + , m_agent(agent) + , m_pathSuffix(pathSuffix) +{ +} + +ProxyAgent::~ProxyAgent() +{ +} + +QString ProxyAgent::capabilityToString(Agent::Capability capability) +{ + QString capabilityString; + + switch (capability) { + case Agent::DisplayOnly: + capabilityString = QStringLiteral("DisplayOnly"); + break; + case Agent::DisplayYesNo: + capabilityString = QStringLiteral("DisplayYesNo"); + break; + case Agent::KeyboardOnly: + capabilityString = QStringLiteral("KeyboardOnly"); + break; + case Agent::NoInputNoOutput: + capabilityString = QStringLiteral("NoInputNoOutput"); + break; + default: + capabilityString = QStringLiteral("DisplayYesNo"); + break; + } + + return capabilityString; +} + +Agent *ProxyAgent::agent() const +{ + return m_agent; +} + +QDBusObjectPath ProxyAgent::objectPath() const +{ + if (!m_agent) { + return QDBusObjectPath(); + } + return QDBusObjectPath(m_agent->objectPath().path() + m_pathSuffix); +} + +BluezQt::Agent::Capability ProxyAgent::capability() const +{ + if (!m_agent) { + return BluezQt::Agent::DisplayOnly; + } + return m_agent->capability(); +} + +void ProxyAgent::requestPinCode(BluezQt::DevicePtr device, const BluezQt::Request<QString> &request) +{ + if (!m_agent) { + request.reject(); + return; + } + m_agent->requestPinCode(device, request); +} + +void ProxyAgent::displayPinCode(BluezQt::DevicePtr device, const QString &pinCode) +{ + if (!m_agent) { + return; + } + m_agent->displayPinCode(device, pinCode); +} + +void ProxyAgent::requestPasskey(BluezQt::DevicePtr device, const BluezQt::Request<quint32> &request) +{ + if (!m_agent) { + request.reject(); + return; + } + m_agent->requestPasskey(device, request); +} + +void ProxyAgent::displayPasskey(BluezQt::DevicePtr device, const QString &passkey, const QString &entered) +{ + if (!m_agent) { + return; + } + m_agent->displayPasskey(device, passkey, entered); +} + +void ProxyAgent::requestConfirmation(BluezQt::DevicePtr device, const QString &passkey, const BluezQt::Request<> &request) +{ + if (!m_agent) { + request.reject(); + return; + } + m_agent->requestConfirmation(device, passkey, request); +} + +void ProxyAgent::requestAuthorization(BluezQt::DevicePtr device, const BluezQt::Request<> &request) +{ + if (!m_agent) { + request.reject(); + return; + } + m_agent->requestAuthorization(device, request); +} + +void ProxyAgent::authorizeService(BluezQt::DevicePtr device, const QString &uuid, const BluezQt::Request<> &request) +{ + if (!m_agent) { + request.reject(); + return; + } + m_agent->authorizeService(device, uuid, request); +} + +void ProxyAgent::cancel() +{ + if (!m_agent) { + return; + } + m_agent->cancel(); +} + +void ProxyAgent::release() +{ + if (m_agent) { + m_agent->release(); + } + + emit agentReleased(); +} +#endif + } // namespace BluezQt diff --git a/src/agent.h b/src/agent.h index 5b0d832..737243d 100644 --- a/src/agent.h +++ b/src/agent.h @@ -206,6 +206,41 @@ public: virtual void release(); }; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +class ProxyAgent : public Agent +{ + Q_OBJECT + +public: + ProxyAgent(Agent *agent, const QString &pathSuffix, QObject *parent = Q_NULLPTR); + ~ProxyAgent(); + + Agent *agent() const; + + QDBusObjectPath objectPath() const; + Capability capability() const; + + void requestPinCode(BluezQt::DevicePtr device, const BluezQt::Request<QString> &request); + void displayPinCode(BluezQt::DevicePtr device, const QString &pinCode); + void requestPasskey(BluezQt::DevicePtr device, const BluezQt::Request<quint32> &request); + void displayPasskey(BluezQt::DevicePtr device, const QString &passkey, const QString &entered); + void requestConfirmation(BluezQt::DevicePtr device, const QString &passkey, const BluezQt::Request<> &request); + void requestAuthorization(BluezQt::DevicePtr device, const BluezQt::Request<> &request); + void authorizeService(BluezQt::DevicePtr device, const QString &uuid, const BluezQt::Request<> &request); + void cancel(); + void release(); + + static QString capabilityToString(Agent::Capability capability); + +Q_SIGNALS: + void agentReleased(); + +private: + Agent *m_agent; + QString m_pathSuffix; +}; +#endif + } // namespace BluezQt #endif // BLUEZQT_AGENT_H diff --git a/src/agentadaptor.cpp b/src/agentadaptor.cpp index 47478e3..05d9533 100644 --- a/src/agentadaptor.cpp +++ b/src/agentadaptor.cpp @@ -132,6 +132,14 @@ void AgentAdaptor::AuthorizeService(const QDBusObjectPath &device, const QString m_agent->authorizeService(dev, uuid.toUpper(), req); } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void AgentAdaptor::Authorize(const QDBusObjectPath &device, const QString &uuid, const QDBusMessage &msg) +{ + AuthorizeService(device, uuid, msg); +} + +#endif + void AgentAdaptor::Cancel() { m_agent->cancel(); diff --git a/src/agentadaptor.h b/src/agentadaptor.h index 2ce588d..7473a1e 100644 --- a/src/agentadaptor.h +++ b/src/agentadaptor.h @@ -39,7 +39,11 @@ class Agent; class AgentAdaptor : public QDBusAbstractAdaptor { Q_OBJECT +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent1") +#else + Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent") +#endif public: explicit AgentAdaptor(Agent *parent, Manager *manager); @@ -53,6 +57,10 @@ public Q_SLOTS: void RequestAuthorization(const QDBusObjectPath &device, const QDBusMessage &msg); void AuthorizeService(const QDBusObjectPath &device, const QString &uuid, const QDBusMessage &msg); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void Authorize(const QDBusObjectPath &device, const QString &uuid, const QDBusMessage &msg); +#endif + Q_NOREPLY void Cancel(); Q_NOREPLY void Release(); diff --git a/src/bluezqt_dbustypes.h b/src/bluezqt_dbustypes.h index 2dbf6fd..cb07da8 100644 --- a/src/bluezqt_dbustypes.h +++ b/src/bluezqt_dbustypes.h @@ -36,4 +36,12 @@ Q_DECLARE_METATYPE(QVariantMapMap) typedef QMap<QDBusObjectPath, QVariantMapMap> DBusManagerStruct; Q_DECLARE_METATYPE(DBusManagerStruct) +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +typedef QMap<quint32, QString> DeviceServiceMap; +Q_DECLARE_METATYPE(DeviceServiceMap) + +typedef QPair<QDBusObjectPath, QVariantMap> ObexTransferInfo; +Q_DECLARE_METATYPE(ObexTransferInfo) +#endif + #endif // BLUEZQT_DBUSTYPES_H diff --git a/src/device.cpp b/src/device.cpp index 92567ca..33b749f 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -272,7 +272,25 @@ Device::Type Device::stringToType(const QString &typeString) PendingCall *Device::connectToDevice() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezDevice->Connect(), PendingCall::ReturnVoid, this); +#else + // In BlueZ 4 there is no generic Connect(), so try connecting to the Input or Audio services. + Type deviceType = type(); + if (deviceType >= Keyboard && deviceType <= Peripheral) { + if (!d->m_inputInterface) { + d->m_inputInterface = new QDBusInterface(Strings::orgBluez(), ubi(), + QStringLiteral("org.bluez.Input"), DBusConnection::orgBluez(), this); + } + return new PendingCall(d->m_inputInterface->asyncCall(QStringLiteral("Connect")), PendingCall::ReturnVoid, this); + } else { + if (!d->m_audioInterface) { + d->m_audioInterface = new QDBusInterface(Strings::orgBluez(), ubi(), + QStringLiteral("org.bluez.Audio"), DBusConnection::orgBluez(), this); + } + return new PendingCall(d->m_audioInterface->asyncCall(QStringLiteral("Connect")), PendingCall::ReturnVoid, this); + } +#endif } PendingCall *Device::disconnectFromDevice() @@ -282,22 +300,46 @@ PendingCall *Device::disconnectFromDevice() PendingCall *Device::connectProfile(const QString &uuid) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezDevice->ConnectProfile(uuid), PendingCall::ReturnVoid, this); +#else + Q_UNUSED(uuid) + return new PendingCall(PendingCall::NotSupported, QStringLiteral("Device::connectProfile() not supported for BlueZ 4")); +#endif } PendingCall *Device::disconnectProfile(const QString &uuid) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezDevice->DisconnectProfile(uuid), PendingCall::ReturnVoid, this); +#else + Q_UNUSED(uuid) + return new PendingCall(PendingCall::NotSupported, QStringLiteral("Device::disconnectProfile() not supported for BlueZ 4")); +#endif } PendingCall *Device::pair() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezDevice->Pair(), PendingCall::ReturnVoid, this); +#else + if (d->m_adapter.isNull()) { + return new PendingCall(PendingCall::InternalError, QStringLiteral("Invalid adapter"), this); + } + return new PendingCall(d->pair(d->m_adapter), PendingCall::ReturnObjectPath, this); +#endif } PendingCall *Device::cancelPairing() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezDevice->CancelPairing(), PendingCall::ReturnVoid, this); +#else + if (d->m_adapter.isNull()) { + return new PendingCall(PendingCall::InternalError, QStringLiteral("Invalid adapter"), this); + } + return new PendingCall(d->cancelPairing(d->m_adapter), PendingCall::ReturnVoid, this); +#endif } } // namespace BluezQt diff --git a/src/device_p.cpp b/src/device_p.cpp index 9ba34c4..cb34315 100644 --- a/src/device_p.cpp +++ b/src/device_p.cpp @@ -32,14 +32,23 @@ #include "utils.h" #include "macros.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "adapter_p.h" +#endif + namespace BluezQt { static const qint16 INVALID_RSSI = -32768; // qint16 minimum DevicePrivate::DevicePrivate(const QString &path, const QVariantMap &properties, const AdapterPtr &adapter) - : QObject() + : QObject() +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusProperties(nullptr) +#else + , m_inputInterface(nullptr) + , m_audioInterface(nullptr) +#endif , m_deviceClass(0) , m_appearance(0) , m_paired(false) @@ -57,12 +66,17 @@ DevicePrivate::DevicePrivate(const QString &path, const QVariantMap &properties, void DevicePrivate::init(const QVariantMap &properties) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_dbusProperties = new DBusProperties(Strings::orgBluez(), m_bluezDevice->path(), DBusConnection::orgBluez(), this); // QueuedConnection is important here - see AdapterPrivate::initProperties connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &DevicePrivate::propertiesChanged, Qt::QueuedConnection); +#else + connect(m_bluezDevice, &BluezDevice::PropertyChanged, + this, &DevicePrivate::devicePropertyChanged); +#endif // Init properties m_address = properties.value(QStringLiteral("Address")).toString(); @@ -85,6 +99,7 @@ void DevicePrivate::init(const QVariantMap &properties) } } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void DevicePrivate::interfacesAdded(const QString &path, const QVariantMapMap &interfaces) { bool changed = false; @@ -113,7 +128,9 @@ void DevicePrivate::interfacesAdded(const QString &path, const QVariantMapMap &i Q_EMIT q.data()->deviceChanged(q.toStrongRef()); } } +#endif +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void DevicePrivate::interfacesRemoved(const QString &path, const QStringList &interfaces) { Q_UNUSED(path) @@ -139,17 +156,26 @@ void DevicePrivate::interfacesRemoved(const QString &path, const QStringList &in Q_EMIT q.data()->deviceChanged(q.toStrongRef()); } } +#endif QDBusPendingReply<> DevicePrivate::setDBusProperty(const QString &name, const QVariant &value) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return m_dbusProperties->Set(Strings::orgBluezDevice1(), name, QDBusVariant(value)); +#else + return m_bluezDevice->SetProperty(name, QDBusVariant(value)); +#endif } void DevicePrivate::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (interface != Strings::orgBluezDevice1()) { return; } +#else + Q_UNUSED(interface) +#endif QVariantMap::const_iterator i; for (i = changed.constBegin(); i != changed.constEnd(); ++i) { @@ -233,4 +259,23 @@ void DevicePrivate::classPropertyChanged(quint32 value) } } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +QDBusPendingReply<QDBusObjectPath> DevicePrivate::pair(AdapterPtr adapter) +{ + Q_ASSERT(adapter); + return adapter->d->createPairedDevice(m_address); +} + +QDBusPendingReply<void> DevicePrivate::cancelPairing(AdapterPtr adapter) +{ + Q_ASSERT(adapter); + return adapter->d->cancelDeviceCreation(m_address); +} + +void DevicePrivate::devicePropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(QStringLiteral("org.bluez.Device"), this, property, value.variant()); +} +#endif + } // namespace BluezQt diff --git a/src/device_p.h b/src/device_p.h index 1590181..24ca5c5 100644 --- a/src/device_p.h +++ b/src/device_p.h @@ -27,15 +27,23 @@ #include <QStringList> #include "types.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "bluezdevice1.h" #include "dbusproperties.h" +#else +#include "bluezdevice.h" +#endif #include "bluezqt_dbustypes.h" namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::Device1 BluezDevice; typedef org::freedesktop::DBus::Properties DBusProperties; +#else +typedef org::bluez::Device BluezDevice; +#endif class DevicePrivate : public QObject { @@ -46,8 +54,10 @@ public: void init(const QVariantMap &properties); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void interfacesAdded(const QString &path, const QVariantMapMap &interfaces); void interfacesRemoved(const QString &path, const QStringList &interfaces); +#endif QDBusPendingReply<> setDBusProperty(const QString &name, const QVariant &value); void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated); @@ -55,9 +65,20 @@ public: void aliasPropertyChanged(const QString &value); void classPropertyChanged(quint32 value); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + QDBusPendingReply<QDBusObjectPath> pair(AdapterPtr adapter); + QDBusPendingReply<void> cancelPairing(AdapterPtr adapter); + void devicePropertyChanged(const QString &property, const QDBusVariant &value); +#endif + QWeakPointer<Device> q; BluezDevice *m_bluezDevice; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusProperties *m_dbusProperties; +#else + QDBusInterface *m_inputInterface; + QDBusInterface *m_audioInterface; +#endif QString m_address; QString m_name; diff --git a/src/input.cpp b/src/input.cpp index 4cf4f03..3789b71 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -28,7 +28,9 @@ namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::freedesktop::DBus::Properties DBusProperties; +#endif static Input::ReconnectMode stringToReconnectMode(const QString &mode) { @@ -45,11 +47,13 @@ static Input::ReconnectMode stringToReconnectMode(const QString &mode) InputPrivate::InputPrivate(const QString &path, const QVariantMap &properties) : QObject() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_dbusProperties = new DBusProperties(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &InputPrivate::propertiesChanged, Qt::QueuedConnection); +#endif // Init properties m_reconnectMode = stringToReconnectMode(properties.value(QStringLiteral("ReconnectMode")).toString()); @@ -59,9 +63,13 @@ void InputPrivate::propertiesChanged(const QString &interface, const QVariantMap { Q_UNUSED(invalidated) +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (interface != Strings::orgBluezInput1()) { return; } +#else + Q_UNUSED(interface) +#endif QVariantMap::const_iterator i; for (i = changed.constBegin(); i != changed.constEnd(); ++i) { diff --git a/src/input_p.h b/src/input_p.h index 424179a..c3c6857 100644 --- a/src/input_p.h +++ b/src/input_p.h @@ -26,12 +26,16 @@ #include <QObject> #include "input.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "dbusproperties.h" +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::freedesktop::DBus::Properties DBusProperties; +#endif class InputPrivate : public QObject { @@ -43,7 +47,9 @@ public: void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated); QWeakPointer<Input> q; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusProperties *m_dbusProperties; +#endif Input::ReconnectMode m_reconnectMode; }; diff --git a/src/interfaces/bluez4/bluez4.pri b/src/interfaces/bluez4/bluez4.pri new file mode 100644 index 0000000..a2977f1 --- /dev/null +++ b/src/interfaces/bluez4/bluez4.pri @@ -0,0 +1,47 @@ +SRC_DIR=$$PWD/../.. + +system(qdbusxml2cpp -c BluezAdapter -p $$SRC_DIR/bluezadapter.h:$$SRC_DIR/bluezadapter.cpp $$PWD/org.bluez.Adapter.xml) +system(qdbusxml2cpp -c BluezDevice -p $$SRC_DIR/bluezdevice.h:$$SRC_DIR/bluezdevice.cpp $$PWD/org.bluez.Device.xml -i $$SRC_DIR/bluezqt_dbustypes.h) +system(qdbusxml2cpp -c BluezManager -p $$SRC_DIR/bluezmanager.h:$$SRC_DIR/bluezmanager.cpp $$PWD/org.bluez.Manager.xml) +system(qdbusxml2cpp -c BluezMediaPlayer -p $$SRC_DIR/bluezmediaplayer.h:$$SRC_DIR/bluezmediaplayer.cpp $$PWD/org.bluez.MediaPlayer.xml) +system(qdbusxml2cpp -c BluezMediaTransport -p $$SRC_DIR/bluezmediatransport.h:$$SRC_DIR/bluezmediatransport.cpp $$PWD/org.bluez.MediaTransport.xml -i $$SRC_DIR/bluezqt_dbustypes.h) + +system(qdbusxml2cpp -c BluezObexManager -p $$SRC_DIR/bluezobexmanager.h:$$SRC_DIR/bluezobexmanager.cpp $$PWD/org.bluez.obex.Manager.xml) +system(qdbusxml2cpp -c BluezObexClient -p $$SRC_DIR/bluezobexclient.h:$$SRC_DIR/bluezobexclient.cpp $$PWD/org.bluez.obex.Client.xml) +system(qdbusxml2cpp -c BluezObexFileTransfer -p $$SRC_DIR/bluezobexfiletransfer.h:$$SRC_DIR/bluezobexfiletransfer.cpp $$PWD/org.bluez.obex.FileTransfer.xml -i $$SRC_DIR/bluezqt_dbustypes.h) +system(qdbusxml2cpp -c BluezObexTransfer -p $$SRC_DIR/bluezobextransfer.h:$$SRC_DIR/bluezobextransfer.cpp $$PWD/org.bluez.obex.Transfer.xml) +system(qdbusxml2cpp -c BluezObexObjectPush -p $$SRC_DIR/bluezobexobjectpush.h:$$SRC_DIR/bluezobexobjectpush.cpp $$PWD/org.bluez.obex.ObjectPush.xml -i $$SRC_DIR/bluezqt_dbustypes.h) + +DBUS_SOURCES += \ + $$SRC_DIR/bluezadapter.cpp \ + $$SRC_DIR/bluezdevice.cpp \ + $$SRC_DIR/bluezmanager.cpp \ + $$SRC_DIR/bluezmediaplayer.cpp \ + $$SRC_DIR/bluezmediatransport.cpp \ + $$SRC_DIR/bluezobexmanager.cpp \ + $$SRC_DIR/bluezobexclient.cpp \ + $$SRC_DIR/bluezobexfiletransfer.cpp \ + $$SRC_DIR/bluezobextransfer.cpp \ + $$SRC_DIR/bluezobexobjectpush.cpp + +DBUS_HEADERS += \ + $$SRC_DIR/bluezadapter.h \ + $$SRC_DIR/bluezdevice.h \ + $$SRC_DIR/bluezmanager.h \ + $$SRC_DIR/bluezmediaplayer.h \ + $$SRC_DIR/bluezmediatransport.h \ + $$SRC_DIR/bluezobexmanager.h \ + $$SRC_DIR/bluezobexclient.h \ + $$SRC_DIR/bluezobexfiletransfer.h \ + $$SRC_DIR/bluezobextransfer.h \ + $$SRC_DIR/bluezobexobjectpush.h + +SOURCES += \ + $$DBUS_SOURCES + +HEADERS += \ + $$DBUS_HEADERS + +OTHER_FILES += \ + $$PWD/*.xml + diff --git a/src/interfaces/bluez4/org.bluez.Adapter.xml b/src/interfaces/bluez4/org.bluez.Adapter.xml new file mode 100644 index 0000000..6c91c52 --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.Adapter.xml @@ -0,0 +1,65 @@ +<!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.Adapter"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <method name="RequestSession"/> + <method name="ReleaseSession"/> + <method name="StartDiscovery"/> + <method name="StopDiscovery"/> + <method name="ListDevices"> + <arg type="ao" direction="out"/> + </method> + <method name="CreateDevice"> + <arg type="s" direction="in"/> + <arg type="o" direction="out"/> + </method> + <method name="CreatePairedDevice"> + <arg type="s" direction="in"/> + <arg type="o" direction="in"/> + <arg type="s" direction="in"/> + <arg type="o" direction="out"/> + </method> + <method name="CancelDeviceCreation"> + <arg type="s" direction="in"/> + </method> + <method name="RemoveDevice"> + <arg type="o" direction="in"/> + </method> + <method name="FindDevice"> + <arg type="s" direction="in"/> + <arg type="o" direction="out"/> + </method> + <method name="RegisterAgent"> + <arg type="o" direction="in"/> + <arg type="s" direction="in"/> + </method> + <method name="UnregisterAgent"> + <arg type="o" direction="in"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <signal name="DeviceCreated"> + <arg type="o"/> + </signal> + <signal name="DeviceRemoved"> + <arg type="o"/> + </signal> + <signal name="DeviceFound"> + <arg type="s"/> + <arg type="a{sv}"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> + </signal> + <signal name="DeviceDisappeared"> + <arg type="s"/> + </signal> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.Device.xml b/src/interfaces/bluez4/org.bluez.Device.xml new file mode 100644 index 0000000..9bbda0e --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.Device.xml @@ -0,0 +1,25 @@ +<!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.Device"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <method name="DiscoverServices"> + <arg type="s" direction="in"/> + <arg type="a{us}" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="DeviceServiceMap"/> + </method> + <method name="CancelDiscovery"/> + <method name="Disconnect"/> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <signal name="DisconnectRequested"/> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.Manager.xml b/src/interfaces/bluez4/org.bluez.Manager.xml new file mode 100644 index 0000000..70ce617 --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.Manager.xml @@ -0,0 +1,32 @@ +<!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.Manager"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="DefaultAdapter"> + <arg type="o" direction="out"/> + </method> + <method name="FindAdapter"> + <arg type="s" direction="in"/> + <arg type="o" direction="out"/> + </method> + <method name="ListAdapters"> + <arg type="ao" direction="out"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <signal name="AdapterAdded"> + <arg type="o"/> + </signal> + <signal name="AdapterRemoved"> + <arg type="o"/> + </signal> + <signal name="DefaultAdapterChanged"> + <arg type="o"/> + </signal> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.MediaPlayer.xml b/src/interfaces/bluez4/org.bluez.MediaPlayer.xml new file mode 100644 index 0000000..415a077 --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.MediaPlayer.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!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.MediaPlayer"> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <method name="Release"/> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.MediaTransport.xml b/src/interfaces/bluez4/org.bluez.MediaTransport.xml new file mode 100644 index 0000000..c56857a --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.MediaTransport.xml @@ -0,0 +1,27 @@ +<?xml version="1.0"?> +<!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.MediaTransport"> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <method name="SetProperty"> + <arg type="s" direction="in"/> + <arg type="v" direction="in"/> + </method> + <method name="Acquire"> + <arg name="accesstype" type="s" direction="in"/> + <arg name="fd" type="h" direction="out"/> + <arg name="read_mtu" type="q" direction="out"/> + <arg name="write_mtu" type="q" direction="out"/> + </method> + <method name="Release"> + <arg name="accesstype" type="s" direction="in"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.obex.Client.xml b/src/interfaces/bluez4/org.bluez.obex.Client.xml new file mode 100644 index 0000000..c54c2c1 --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.obex.Client.xml @@ -0,0 +1,14 @@ +<!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.obex.Client"> + <method name="CreateSession"> + <arg type="s" direction="in"/> + <arg type="a{sv}" direction="in"/> + <arg type="o" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> + </method> + <method name="RemoveSession"> + <arg type="o" direction="in"/> + </method> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.obex.FileTransfer.xml b/src/interfaces/bluez4/org.bluez.obex.FileTransfer.xml new file mode 100644 index 0000000..fbf1037 --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.obex.FileTransfer.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!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.obex.FileTransfer"> + <method name="ChangeFolder"> + <arg name="folder" type="s" direction="in" /> + </method> + <method name="CreateFolder"> + <arg name="folder" type="s" direction="in" /> + </method> + <method name="ListFolder"> + <arg name="folderinfo" type="aa{sv}" direction="out" /> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMapList"/> + </method> + <method name="GetFile"> + <arg name="targetfile" type="s" direction="in" /> + <arg name="sourcefile" type="s" direction="in" /> + <arg name="transfer" type="o" direction="out" /> + <arg name="properties" type="a{sv}" direction="out" /> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/> + </method> + <method name="PutFile"> + <arg name="sourcefile" type="s" direction="in" /> + <arg name="targetfile" type="s" direction="in" /> + <arg name="transfer" type="o" direction="out" /> + <arg name="properties" type="a{sv}" direction="out" /> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/> + </method> + <method name="CopyFile"> + <arg name="sourcefile" type="s" direction="in" /> + <arg name="targetfile" type="s" direction="in" /> + </method> + <method name="MoveFile"> + <arg name="sourcefile" type="s" direction="in" /> + <arg name="targetfile" type="s" direction="in" /> + </method> + <method name="Delete"> + <arg name="file" type="s" direction="in" /> + </method> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.obex.Manager.xml b/src/interfaces/bluez4/org.bluez.obex.Manager.xml new file mode 100644 index 0000000..8666ff7 --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.obex.Manager.xml @@ -0,0 +1,24 @@ +<!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.obex.Manager"> + <method name="RegisterAgent"> + <arg type="o" direction="in"/> + </method> + <method name="UnregisterAgent"> + <arg type="o" direction="in"/> + </method> + <signal name="SessionCreated"> + <arg type="o"/> + </signal> + <signal name="SessionRemoved"> + <arg type="o"/> + </signal> + <signal name="TransferStarted"> + <arg type="o"/> + </signal> + <signal name="TransferCompleted"> + <arg type="o"/> + <arg type="b"/> + </signal> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.obex.ObjectPush.xml b/src/interfaces/bluez4/org.bluez.obex.ObjectPush.xml new file mode 100644 index 0000000..1dd0fed --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.obex.ObjectPush.xml @@ -0,0 +1,21 @@ +<!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.obex.ObjectPush"> + <method name="SendFile"> + <arg type="s" direction="in"/> + <arg type="(oa{sv})" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ObexTransferInfo"/> + </method> + <method name="PullBusinessCard"> + <arg type="s" direction="in"/> + <arg type="(oa{sv})" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ObexTransferInfo"/> + </method> + <method name="ExchangeBusinessCards"> + <arg type="s" direction="in"/> + <arg type="s" direction="in"/> + <arg type="(oa{sv})" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ObexTransferInfo"/> + </method> + </interface> +</node> diff --git a/src/interfaces/bluez4/org.bluez.obex.Transfer.xml b/src/interfaces/bluez4/org.bluez.obex.Transfer.xml new file mode 100644 index 0000000..82df51a --- /dev/null +++ b/src/interfaces/bluez4/org.bluez.obex.Transfer.xml @@ -0,0 +1,30 @@ +<!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.obex.Transfer"> + + <!-- both services --> + <method name="Cancel"/> + + <!-- org.bluez.obex.client service only --> + <method name="GetProperties"> + <arg type="a{sv}" direction="out"/> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> + </method> + <signal name="PropertyChanged"> + <arg type="s"/> + <arg type="v"/> + </signal> + <signal name="Complete"/> + <signal name="Error"> + <arg type="s"/> + <arg type="s"/> + </signal> + + <!-- org.bluez.obex service only --> + <signal name="Progress"> + <arg type="i"/> + <arg type="i"/> + </signal> + + </interface> +</node> diff --git a/src/interfaces/interfaces.pri b/src/interfaces/interfaces.pri new file mode 100644 index 0000000..82f9672 --- /dev/null +++ b/src/interfaces/interfaces.pri @@ -0,0 +1,58 @@ +SRC_DIR=$$PWD/.. + +system(qdbusxml2cpp -c ObjectManager -p $$SRC_DIR/dbusobjectmanager.h:$$SRC_DIR/dbusobjectmanager.cpp $$PWD/org.freedesktop.DBus.ObjectManager.xml -i $$SRC_DIR/bluezqt_dbustypes.h) +system(qdbusxml2cpp -c ObexFileTransfer -p $$SRC_DIR/obexfiletransfer1.h:$$SRC_DIR/obexfiletransfer1.cpp $$PWD/org.bluez.obex.FileTransfer1.xml -i $$SRC_DIR/bluezqt_dbustypes.h) +system(qdbusxml2cpp -c Properties -p $$SRC_DIR/dbusproperties.h:$$SRC_DIR/dbusproperties.cpp $$PWD/org.freedesktop.DBus.Properties.xml) +system(qdbusxml2cpp -c BluezAdapter -p $$SRC_DIR/bluezadapter1.h:$$SRC_DIR/bluezadapter1.cpp $$PWD/org.bluez.Adapter1.xml) +system(qdbusxml2cpp -c BluezAgentManager -p $$SRC_DIR/bluezagentmanager1.h:$$SRC_DIR/bluezagentmanager1.cpp $$PWD/org.bluez.AgentManager1.xml) +system(qdbusxml2cpp -c BluezProfileManager -p $$SRC_DIR/bluezprofilemanager1.h:$$SRC_DIR/bluezprofilemanager1.cpp $$PWD/org.bluez.ProfileManager1.xml) +system(qdbusxml2cpp -c BluezDevice -p $$SRC_DIR/bluezdevice1.h:$$SRC_DIR/bluezdevice1.cpp $$PWD/org.bluez.Device1.xml) +system(qdbusxml2cpp -c BluezMediaPlayer -p $$SRC_DIR/bluezmediaplayer1.h:$$SRC_DIR/bluezmediaplayer1.cpp $$PWD/org.bluez.MediaPlayer1.xml) +system(qdbusxml2cpp -c BluezMediaTransport -p $$SRC_DIR/bluezmediatransport1.h:$$SRC_DIR/bluezmediatransport1.cpp $$PWD/org.bluez.MediaTransport1.xml) +system(qdbusxml2cpp -c ObexAgentManager -p $$SRC_DIR/obexagentmanager1.h:$$SRC_DIR/obexagentmanager1.cpp $$PWD/org.bluez.obex.AgentManager1.xml) +system(qdbusxml2cpp -c ObexClient -p $$SRC_DIR/obexclient1.h:$$SRC_DIR/obexclient1.cpp $$PWD/org.bluez.obex.Client1.xml) +system(qdbusxml2cpp -c ObexTransfer -p $$SRC_DIR/obextransfer1.h:$$SRC_DIR/obextransfer1.cpp $$PWD/org.bluez.obex.Transfer1.xml) +system(qdbusxml2cpp -c ObexSession -p $$SRC_DIR/obexsession1.h:$$SRC_DIR/obexsession1.cpp $$PWD/org.bluez.obex.Session1.xml) +system(qdbusxml2cpp -c ObexObjectPush -p $$SRC_DIR/obexobjectpush1.h:$$SRC_DIR/obexobjectpush1.cpp $$PWD/org.bluez.obex.ObjectPush1.xml) + +DBUS_SOURCES += \ + $$SRC_DIR/dbusobjectmanager.cpp \ + $$SRC_DIR/obexfiletransfer1.cpp \ + $$SRC_DIR/dbusproperties.cpp \ + $$SRC_DIR/bluezadapter1.cpp \ + $$SRC_DIR/bluezagentmanager1.cpp \ + $$SRC_DIR/bluezprofilemanager1.cpp \ + $$SRC_DIR/bluezdevice1.cpp \ + $$SRC_DIR/bluezmediaplayer1.cpp \ + $$SRC_DIR/bluezmediatransport1.cpp \ + $$SRC_DIR/obexagentmanager1.cpp \ + $$SRC_DIR/obexclient1.cpp \ + $$SRC_DIR/obextransfer1.cpp \ + $$SRC_DIR/obexsession1.cpp \ + $$SRC_DIR/obexobjectpush1.cpp + +DBUS_HEADERS += \ + $$SRC_DIR/dbusobjectmanager.h \ + $$SRC_DIR/obexfiletransfer1.h \ + $$SRC_DIR/dbusproperties.h \ + $$SRC_DIR/bluezadapter1.h \ + $$SRC_DIR/bluezagentmanager1.h \ + $$SRC_DIR/bluezprofilemanager1.h \ + $$SRC_DIR/bluezdevice1.h \ + $$SRC_DIR/bluezmediaplayer1.h \ + $$SRC_DIR/bluezmediatransport1.h \ + $$SRC_DIR/obexagentmanager1.h \ + $$SRC_DIR/obexclient1.h \ + $$SRC_DIR/obextransfer1.h \ + $$SRC_DIR/obexsession1.h \ + $$SRC_DIR/obexobjectpush1.h + +SOURCES += \ + $$DBUS_SOURCES + +HEADERS += \ + $$DBUS_HEADERS + +OTHER_FILES += \ + $$PWD/*.xml + diff --git a/src/macros.h b/src/macros.h index 9b6c6f3..fbcc524 100644 --- a/src/macros.h +++ b/src/macros.h @@ -44,4 +44,16 @@ Q_EMIT q.data()->signal(var); \ } +// Calls propertiesChanged() for a single property value change +#define INVOKE_PROPERTIES_CHANGED(interface, obj, property, value) {\ + QVariantMap changed; \ + QStringList invalidated; \ + if (value.isValid()) { \ + changed[property] = value; \ + } else { \ + invalidated << property; \ + } \ + obj->propertiesChanged(interface, changed, invalidated); \ +} + #endif // BLUEZQT_MACROS_H diff --git a/src/manager.cpp b/src/manager.cpp index 4bd0068..7606b03 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -154,9 +154,11 @@ PendingCall *Manager::registerAgent(Agent *agent) { Q_ASSERT(agent); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_bluezAgentManager) { return new PendingCall(PendingCall::InternalError, QStringLiteral("Manager not operational!")); } +#endif QString capability; @@ -178,6 +180,7 @@ PendingCall *Manager::registerAgent(Agent *agent) break; } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 new AgentAdaptor(agent, this); if (!DBusConnection::orgBluez().registerObject(agent->objectPath().path(), agent)) { @@ -186,12 +189,18 @@ PendingCall *Manager::registerAgent(Agent *agent) return new PendingCall(d->m_bluezAgentManager->RegisterAgent(agent->objectPath(), capability), PendingCall::ReturnVoid, this); +#else + // registerAgent() in BlueZ 5 registers an application agent, which is different from the + // behavior of registerAgent() in BlueZ 5, so this is a no-op here. + return new PendingCall(PendingCall::NoError, QString(), this); +#endif } PendingCall *Manager::unregisterAgent(Agent *agent) { Q_ASSERT(agent); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_bluezAgentManager) { return new PendingCall(PendingCall::InternalError, QStringLiteral("Manager not operational!")); } @@ -200,24 +209,44 @@ PendingCall *Manager::unregisterAgent(Agent *agent) return new PendingCall(d->m_bluezAgentManager->UnregisterAgent(agent->objectPath()), PendingCall::ReturnVoid, this); +#else + // registerAgent() is a no-op for non-default-agents in BlueZ 4, so unregistration is only + // necessary if the agent was set as a default agent. + AdapterPtr adapter = d->findAdapterForDefaultAgent(agent); + if (!adapter) { + return new PendingCall(PendingCall::NoError, QString(), this); + } + + return new PendingCall(d->unregisterDefaultAgent(adapter), PendingCall::ReturnVoid, this); +#endif } PendingCall *Manager::requestDefaultAgent(Agent *agent) { Q_ASSERT(agent); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_bluezAgentManager) { return new PendingCall(PendingCall::InternalError, QStringLiteral("Manager not operational!")); } return new PendingCall(d->m_bluezAgentManager->RequestDefaultAgent(agent->objectPath()), PendingCall::ReturnVoid, this); +#else + if (d->m_adapters.isEmpty()) { + return new PendingCall(PendingCall::InternalError, QStringLiteral("No adapters available!"), this); + } + + AdapterPtr adapter = d->m_usableAdapter ? d->m_usableAdapter : d->m_adapters.values().first(); + return new PendingCall(d->requestDefaultAgent(adapter, agent), PendingCall::ReturnVoid, this); +#endif } PendingCall *Manager::registerProfile(Profile *profile) { Q_ASSERT(profile); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_bluezProfileManager) { return new PendingCall(PendingCall::InternalError, QStringLiteral("Manager not operational!")); } @@ -230,12 +259,16 @@ PendingCall *Manager::registerProfile(Profile *profile) return new PendingCall(d->m_bluezProfileManager->RegisterProfile(profile->objectPath(), profile->uuid(), profile->d->options), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("Manager::registerProfile() not supported for BlueZ 4")); +#endif } PendingCall *Manager::unregisterProfile(Profile *profile) { Q_ASSERT(profile); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_bluezProfileManager) { return new PendingCall(PendingCall::InternalError, QStringLiteral("Manager not operational!")); } @@ -244,6 +277,9 @@ PendingCall *Manager::unregisterProfile(Profile *profile) return new PendingCall(d->m_bluezProfileManager->UnregisterProfile(profile->objectPath()), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("Manager::unregisterProfile() not supported for BlueZ 4")); +#endif } } // namespace BluezQt diff --git a/src/manager_p.cpp b/src/manager_p.cpp index aaec901..bad24b1 100644 --- a/src/manager_p.cpp +++ b/src/manager_p.cpp @@ -33,15 +33,24 @@ #include <QDBusConnection> #include <QDBusServiceWatcher> +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluezadapter.h" +#include "agentadaptor.h" +#endif + namespace BluezQt { ManagerPrivate::ManagerPrivate(Manager *parent) : QObject(parent) , q(parent) +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusObjectManager(nullptr) , m_bluezAgentManager(nullptr) , m_bluezProfileManager(nullptr) +#else + , m_bluezManager(nullptr) +#endif , m_usableAdapter(0) , m_initialized(false) , m_bluezRunning(false) @@ -118,13 +127,22 @@ void ManagerPrivate::load() this, SLOT(dummy())); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_dbusObjectManager = new DBusObjectManager(Strings::orgBluez(), QStringLiteral("/"), DBusConnection::orgBluez(), this); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(m_dbusObjectManager->GetManagedObjects(), this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerPrivate::getManagedObjectsFinished); +#else + m_bluezManager = new BluezManager(Strings::orgBluez(), QStringLiteral("/"), DBusConnection::orgBluez(), this); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(m_bluezManager->DefaultAdapter(), this); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerPrivate::managerDefaultAdapterFinished); + +#endif } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watcher) { const QDBusPendingReply<DBusManagerStruct> &reply = *watcher; @@ -178,6 +196,7 @@ void ManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watcher) Q_EMIT initFinished(); } +#endif void ManagerPrivate::clear() { @@ -204,6 +223,7 @@ void ManagerPrivate::clear() // Delete all other objects m_usableAdapter.clear(); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (m_dbusObjectManager) { m_dbusObjectManager->deleteLater(); m_dbusObjectManager = nullptr; @@ -213,6 +233,7 @@ void ManagerPrivate::clear() m_bluezAgentManager->deleteLater(); m_bluezAgentManager = nullptr; } +#endif } AdapterPtr ManagerPrivate::findUsableAdapter() const @@ -248,6 +269,7 @@ void ManagerPrivate::serviceUnregistered() Q_EMIT q->operationalChanged(false); } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ManagerPrivate::interfacesAdded(const QDBusObjectPath &objectPath, const QVariantMapMap &interfaces) { const QString &path = objectPath.path(); @@ -268,7 +290,9 @@ void ManagerPrivate::interfacesAdded(const QDBusObjectPath &objectPath, const QV } } } +#endif +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ManagerPrivate::interfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces) { const QString &path = objectPath.path(); @@ -288,9 +312,14 @@ void ManagerPrivate::interfacesRemoved(const QDBusObjectPath &objectPath, const } } } +#endif void ManagerPrivate::adapterRemoved(const AdapterPtr &adapter) { +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + m_defaultAgents.remove(adapter->ubi()); +#endif + disconnect(adapter.data(), &Adapter::poweredChanged, this, &ManagerPrivate::adapterPoweredChanged); // Current usable adapter was removed @@ -348,6 +377,19 @@ void ManagerPrivate::addAdapter(const QString &adapterPath, const QVariantMap &p connect(adapter.data(), &Adapter::adapterRemoved, q, &Manager::adapterRemoved); connect(adapter.data(), &Adapter::adapterChanged, q, &Manager::adapterChanged); connect(adapter.data(), &Adapter::poweredChanged, this, &ManagerPrivate::adapterPoweredChanged); + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + connect(adapter->d->m_bluezAdapter, &BluezAdapter::DeviceFound, + this, &ManagerPrivate::deviceFound); + connect(adapter->d->m_bluezAdapter, &BluezAdapter::DeviceCreated, + this, &ManagerPrivate::addDeviceByPath); + connect(adapter->d->m_bluezAdapter, &BluezAdapter::DeviceRemoved, + this, &ManagerPrivate::deviceRemoved); + connect(adapter->d->m_bluezAdapter, &BluezAdapter::PropertyChanged, + this, &ManagerPrivate::adapterPropertyChanged); + connect(adapter.data()->d, &AdapterPrivate::agentCreated, + this, &ManagerPrivate::agentCreated); +#endif } void ManagerPrivate::addDevice(const QString &devicePath, const QVariantMap &properties) @@ -428,4 +470,303 @@ void ManagerPrivate::dummy() { } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void ManagerPrivate::managerInitialized() +{ + if (!m_initialized) { + // Set up initial state as per getManagedObjectsFinished() + m_loaded = true; + m_initialized = true; + + Q_EMIT q->operationalChanged(true); + + if (q->isBluetoothOperational()) { + Q_EMIT q->bluetoothOperationalChanged(true); + } + + Q_EMIT initFinished(); + } +} + +void ManagerPrivate::managerDefaultAdapterFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<QDBusObjectPath> &reply = *watcher; + watcher->deleteLater(); + + if (reply.isError()) { + Q_EMIT initError(reply.error().message()); + return; + } + + const QDBusObjectPath &objectPath = reply.value(); + managerAdapterAdded(objectPath); + + connect(m_bluezManager, &BluezManager::AdapterAdded, + this, &ManagerPrivate::managerAdapterAdded); + connect(m_bluezManager, &BluezManager::AdapterRemoved, + this, &ManagerPrivate::managerAdapterRemoved); +} + +void ManagerPrivate::managerAdapterAdded(const QDBusObjectPath &objectPath) +{ + QDBusInterface *bluezAdapter = new QDBusInterface(Strings::orgBluez(), objectPath.path(), + QStringLiteral("org.bluez.Adapter"), DBusConnection::orgBluez(), this); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(bluezAdapter->asyncCall(QStringLiteral("GetProperties")), this); + watcher->setProperty("bluezAdapter", QVariant::fromValue(bluezAdapter)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerPrivate::adapterGetPropertiesFinished); +} + +void ManagerPrivate::managerAdapterRemoved(const QDBusObjectPath &objectPath) +{ + removeAdapter(objectPath.path()); +} + +void ManagerPrivate::adapterGetPropertiesFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<QVariantMap> &reply = *watcher; + const QVariantMap &properties = reply.value(); + watcher->deleteLater(); + + QDBusInterface *bluezAdapter = watcher->property("bluezAdapter").value<QDBusInterface *>(); + bluezAdapter->deleteLater(); + + if (reply.isError()) { + if (!m_initialized) { + Q_EMIT initError(reply.error().message()); + } + return; + } + + addAdapter(bluezAdapter->path(), properties); + + QVariant deviceList = properties.value(QStringLiteral("Devices")); + if (deviceList.isValid()) { + updateDeviceList(bluezAdapter->path(), deviceList); + } + + if (m_pendingInitializationWatchers.isEmpty()) { + managerInitialized(); + } +} + +void ManagerPrivate::adapterPropertyChanged(const QString &property, const QDBusVariant &value) +{ + BluezAdapter *adapter = qobject_cast<BluezAdapter *>(sender()); + + if (adapter && property == QStringLiteral("Devices")) { + updateDeviceList(adapter->path(), value.variant()); + } +} + +void ManagerPrivate::updateDeviceList(const QString &adapterPath, const QVariant &deviceList) +{ + QStringList devicePaths; + const QDBusArgument &dbusArgument = deviceList.value<QDBusArgument>(); + dbusArgument.beginArray(); + while (!dbusArgument.atEnd()) { + QDBusObjectPath path; + dbusArgument >> path; + devicePaths << path.path(); + } + dbusArgument.endArray(); + + QHash<QString, DevicePtr>::const_iterator it; + QStringList pathsToRemove; + + for (it = m_devices.constBegin(); it != m_devices.constEnd(); ++it) { + const QString &path = it.key(); + const DevicePtr &device = it.value(); + + if (device->adapter()->ubi() == adapterPath && !devicePaths.contains(path)) { + pathsToRemove.append(path); + } + } + + Q_FOREACH (const QString &devicePath, devicePaths) { + if (!m_devices.contains(devicePath)) { + QDBusPendingCallWatcher *watcher = addDeviceByPath(QDBusObjectPath(devicePath)); + if (!m_initialized && watcher) { + m_pendingInitializationWatchers.insert(watcher); + } + } + } + + Q_FOREACH (const QString &devicePath, pathsToRemove) { + removeDevice(devicePath); + } +} + +QDBusPendingCallWatcher *ManagerPrivate::addDeviceByPath(const QDBusObjectPath &objectPath) +{ + if (!m_devices.contains(objectPath.path())) { + QDBusInterface *bluezDevice = new QDBusInterface(Strings::orgBluez(), objectPath.path(), + QStringLiteral("org.bluez.Device"), DBusConnection::orgBluez(), this); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher( + bluezDevice->asyncCall(QStringLiteral("GetProperties")), this); + watcher->setProperty("bluezDevice", QVariant::fromValue(bluezDevice)); + connect(watcher, &QDBusPendingCallWatcher::finished, + this, &ManagerPrivate::deviceGetPropertiesFinished); + return watcher; + } + return 0; +} + +void ManagerPrivate::deviceGetPropertiesFinished(QDBusPendingCallWatcher *watcher) +{ + m_pendingInitializationWatchers.remove(watcher); + + const QDBusPendingReply<QVariantMap> &reply = *watcher; + watcher->deleteLater(); + + QDBusInterface *bluezDevice = watcher->property("bluezDevice").value<QDBusInterface *>(); + bluezDevice->deleteLater(); + + if (!reply.isError()) { + DevicePtr device = m_devices.value(bluezDevice->path()); + if (device.isNull()) { + addDevice(bluezDevice->path(), reply.value()); + } else { + device->d->propertiesChanged(Strings::orgBluezDevice1(), reply.value(), QStringList()); + } + } + + if (!m_initialized && m_pendingInitializationWatchers.isEmpty()) { + managerInitialized(); + } +} + +void ManagerPrivate::deviceFound(const QString &address, const QVariantMap &values) +{ + BluezAdapter *bluezAdapter = qobject_cast<BluezAdapter *>(sender()); + if (!bluezAdapter) { + return; + } + + QHash<QString, DevicePtr>::iterator it; + + for (it = m_devices.begin(); it != m_devices.end(); ++it) { + const DevicePtr &device = it.value(); + + if (device->address() == address) { + device->d->propertiesChanged(Strings::orgBluezDevice1(), values, QStringList()); + return; + } + } + + // 'Adapter' is not included in the property map provided by DeviceFound(), but addDevice() + // expects this property so it must be present. + QString addressCopy = address; + QString devicePath = QString("%1/dev_%2").arg(bluezAdapter->path()).arg(addressCopy.replace(':', '_')); + QVariantMap properties = values; + properties.insert(QStringLiteral("Adapter"), QVariant::fromValue(QDBusObjectPath(bluezAdapter->path()))); + + addDevice(devicePath, properties); +} + +void ManagerPrivate::deviceRemoved(const QDBusObjectPath &objectPath) +{ + removeDevice(objectPath.path()); +} + +QDBusPendingReply<void> ManagerPrivate::requestDefaultAgent(AdapterPtr adapter, Agent *agent) +{ + Q_ASSERT(adapter); + Q_ASSERT(agent); + + // Register a proxy for this agent instead of registering it directly. This allows the same + // agent to be used as the default agent as well as the agent for initiated pairing requests, + // which is not supported behavior in BlueZ 4. + ProxyAgent *proxyAgent = adapter->d->createProxyForAgent(agent, "/bluez4_system_agent_proxy"); + QDBusPendingReply<void> reply = adapter->d->m_bluezAdapter->RegisterAgent(proxyAgent->objectPath(), ProxyAgent::capabilityToString(proxyAgent->capability())); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + watcher->setProperty("proxyAgent", QVariant::fromValue(proxyAgent)); + watcher->setProperty("adapterAddress", adapter->address()); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerPrivate::requestDefaultAgentFinished); + + return reply; +} + +void ManagerPrivate::requestDefaultAgentFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<void> &reply = *watcher; + ProxyAgent *proxyAgent = watcher->property("proxyAgent").value<ProxyAgent *>(); + QString adapterAddress = watcher->property("adapterAddress").toString(); + watcher->deleteLater(); + + if (reply.isError()) { + return; + } + + AdapterPtr adapter = q->adapterForAddress(adapterAddress); + if (adapter) { + m_defaultAgents.insert(adapter->ubi(), proxyAgent); + + // Set the adapter to reuse the proxied agent when initiating pairings. + adapter->d->m_pairingAgent = proxyAgent->agent(); + } +} + +QDBusPendingReply<void> ManagerPrivate::unregisterDefaultAgent(AdapterPtr adapter) +{ + Q_ASSERT(adapter); + + if (!m_defaultAgents.contains(adapter->ubi())) { + return QDBusPendingReply<void>(QDBusMessage::createError(QDBusError::InternalError, + QStringLiteral("Agent has not been registered with this adapter"))); + } + + ProxyAgent *proxyAgent = m_defaultAgents.value(adapter->ubi()); + QDBusPendingReply<void> reply = adapter->d->m_bluezAdapter->UnregisterAgent(proxyAgent->objectPath()); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + watcher->setProperty("adapterPath", adapter->ubi()); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerPrivate::unregisterAgentFinished); + + return reply; +} + +void ManagerPrivate::unregisterAgentFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<void> &reply = *watcher; + QString adapterPath = watcher->property("adapterPath").toString(); + watcher->deleteLater(); + + if (reply.isError()) { + return; + } + + m_defaultAgents.remove(adapterPath); +} + +AdapterPtr ManagerPrivate::findAdapterForDefaultAgent(Agent *agent) +{ + QHash<QString, ProxyAgent *>::const_iterator i; + + for (i = m_defaultAgents.constBegin(); i != m_defaultAgents.constEnd(); ++i) { + const QString &adapterPath = i.key(); + ProxyAgent *proxyAgent = i.value(); + + if (proxyAgent == agent) { + return q->adapterForUbi(adapterPath); + } + } + + return AdapterPtr(); +} + +void ManagerPrivate::agentCreated(Agent *agent) +{ + // Initialize the agent as per Manager::registerAgent() + + new AgentAdaptor(agent, q); + + if (!DBusConnection::orgBluez().registerObject(agent->objectPath().path(), agent)) { + qCWarning(BLUEZQT) << "Cannot register object" << agent->objectPath().path(); + } +} +#endif + } // namespace BluezQt diff --git a/src/manager_p.h b/src/manager_p.h index 0b26d1b..3b0cf0b 100644 --- a/src/manager_p.h +++ b/src/manager_p.h @@ -28,16 +28,26 @@ #include "types.h" #include "rfkill.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "dbusobjectmanager.h" #include "bluezagentmanager1.h" #include "bluezprofilemanager1.h" +#else +#include "bluezmanager.h" +#include "agent.h" +#include <QSet> +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::freedesktop::DBus::ObjectManager DBusObjectManager; typedef org::bluez::AgentManager1 BluezAgentManager; typedef org::bluez::ProfileManager1 BluezProfileManager; +#else +typedef org::bluez::Manager BluezManager; +#endif class Manager; class Adapter; @@ -54,15 +64,20 @@ public: void init(); void nameHasOwnerFinished(QDBusPendingCallWatcher *watcher); void load(); + +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void getManagedObjectsFinished(QDBusPendingCallWatcher *watcher); +#endif void clear(); AdapterPtr findUsableAdapter() const; void serviceRegistered(); void serviceUnregistered(); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void interfacesAdded(const QDBusObjectPath &objectPath, const QVariantMapMap &interfaces); void interfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces); +#endif void adapterRemoved(const AdapterPtr &adapter); void adapterPoweredChanged(bool powered); void rfkillStateChanged(Rfkill::State state); @@ -75,11 +90,40 @@ public: bool rfkillBlocked() const; void setUsableAdapter(const AdapterPtr &adapter); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void managerInitialized(); + void managerDefaultAdapterFinished(QDBusPendingCallWatcher *watcher); + void managerAdapterAdded(const QDBusObjectPath &objectPath); + void managerAdapterRemoved(const QDBusObjectPath &objectPath); + + void adapterGetPropertiesFinished(QDBusPendingCallWatcher *watcher); + void adapterPropertyChanged(const QString &property, const QDBusVariant &value); + + void updateDeviceList(const QString &adapterPath, const QVariant &deviceList); + QDBusPendingCallWatcher *addDeviceByPath(const QDBusObjectPath &objectPath); + void deviceGetPropertiesFinished(QDBusPendingCallWatcher *watcher); + void deviceFound(const QString &address, const QVariantMap &values); + void deviceRemoved(const QDBusObjectPath &objectPath); + + QDBusPendingReply<void> requestDefaultAgent(AdapterPtr adapter, Agent *agent); + void requestDefaultAgentFinished(QDBusPendingCallWatcher *watcher); + QDBusPendingReply<void> unregisterDefaultAgent(AdapterPtr adapter); + void unregisterAgentFinished(QDBusPendingCallWatcher *watcher); + AdapterPtr findAdapterForDefaultAgent(Agent *agent); + void agentCreated(Agent *agent); +#endif + Manager *q; Rfkill *m_rfkill; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusObjectManager *m_dbusObjectManager; BluezAgentManager *m_bluezAgentManager; BluezProfileManager *m_bluezProfileManager; +#else + BluezManager *m_bluezManager; + QSet<QDBusPendingCallWatcher *> m_pendingInitializationWatchers; + QHash<QString, ProxyAgent *> m_defaultAgents; +#endif QHash<QString, AdapterPtr> m_adapters; QHash<QString, DevicePtr> m_devices; diff --git a/src/mediaplayer.cpp b/src/mediaplayer.cpp index 8d2c90a..623e31c 100644 --- a/src/mediaplayer.cpp +++ b/src/mediaplayer.cpp @@ -24,6 +24,10 @@ #include "mediaplayer_p.h" #include "pendingcall.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "debug.h" +#endif + namespace BluezQt { @@ -81,7 +85,12 @@ MediaPlayerPtr MediaPlayer::toSharedPtr() const QString MediaPlayer::name() const { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return d->m_name; +#else + qCWarning(BLUEZQT) << "MediaPlayer::name() not available in BlueZ 4!"; + return QString(); +#endif } MediaPlayer::Equalizer MediaPlayer::equalizer() const @@ -124,7 +133,12 @@ MediaPlayer::Status MediaPlayer::status() const MediaPlayerTrack MediaPlayer::track() const { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return d->m_track; +#else + qCWarning(BLUEZQT) << "MediaPlayer::track() not available in BlueZ 4!"; + return MediaPlayerTrack(); +#endif } quint32 MediaPlayer::position() const @@ -134,37 +148,65 @@ quint32 MediaPlayer::position() const PendingCall *MediaPlayer::play() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaPlayer->Play(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("MediaPlayer::play() not available in BlueZ 4!"), this); +#endif } PendingCall *MediaPlayer::pause() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaPlayer->Pause(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("MediaPlayer::pause() not available in BlueZ 4!"), this); +#endif } PendingCall *MediaPlayer::stop() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaPlayer->Stop(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("MediaPlayer::stop() not available in BlueZ 4!"), this); +#endif } PendingCall *MediaPlayer::next() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaPlayer->Next(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("MediaPlayer::next() not available in BlueZ 4!"), this); +#endif } PendingCall *MediaPlayer::previous() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaPlayer->Previous(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("MediaPlayer::previous() not available in BlueZ 4!"), this); +#endif } PendingCall *MediaPlayer::fastForward() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaPlayer->FastForward(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("MediaPlayer::fastForward() not available in BlueZ 4!"), this); +#endif } PendingCall *MediaPlayer::rewind() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaPlayer->Rewind(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("MediaPlayer::rewind() not available in BlueZ 4!"), this); +#endif } } // namespace BluezQt diff --git a/src/mediaplayer_p.cpp b/src/mediaplayer_p.cpp index 3c4e57e..38dcc8d 100644 --- a/src/mediaplayer_p.cpp +++ b/src/mediaplayer_p.cpp @@ -75,7 +75,9 @@ static MediaPlayer::Status stringToStatus(const QString &status) MediaPlayerPrivate::MediaPlayerPrivate(const QString &path, const QVariantMap &properties) : QObject() +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusProperties(nullptr) +#endif , m_equalizer(MediaPlayer::EqualizerOff) , m_repeat(MediaPlayer::RepeatOff) , m_shuffle(MediaPlayer::ShuffleOff) @@ -89,11 +91,16 @@ MediaPlayerPrivate::MediaPlayerPrivate(const QString &path, const QVariantMap &p void MediaPlayerPrivate::init(const QVariantMap &properties) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_dbusProperties = new DBusProperties(Strings::orgBluez(), m_bluezMediaPlayer->path(), DBusConnection::orgBluez(), this); connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &MediaPlayerPrivate::propertiesChanged, Qt::QueuedConnection); +#else + connect(m_bluezMediaPlayer, &BluezMediaPlayer::PropertyChanged, + this, &MediaPlayerPrivate::mediaPlayerPropertyChanged); +#endif // Init properties m_name = properties.value(QStringLiteral("Name")).toString(); @@ -107,14 +114,22 @@ void MediaPlayerPrivate::init(const QVariantMap &properties) QDBusPendingReply<> MediaPlayerPrivate::setDBusProperty(const QString &name, const QVariant &value) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return m_dbusProperties->Set(Strings::orgBluezMediaPlayer1(), name, QDBusVariant(value)); +#else + return m_bluezMediaPlayer->SetProperty(name, QDBusVariant(value)); +#endif } void MediaPlayerPrivate::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (interface != Strings::orgBluezMediaPlayer1()) { return; } +#else + Q_UNUSED(interface) +#endif QVariantMap::const_iterator i; for (i = changed.constBegin(); i != changed.constEnd(); ++i) { @@ -165,4 +180,11 @@ MediaPlayerTrack MediaPlayerPrivate::variantToTrack(const QVariant &variant) con return MediaPlayerTrack(properties); } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void MediaPlayerPrivate::mediaPlayerPropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(QStringLiteral("org.bluez.MediaTransport"), this, property, value.variant()); +} +#endif + } // namespace BluezQt diff --git a/src/mediaplayer_p.h b/src/mediaplayer_p.h index a7fa364..acf617c 100644 --- a/src/mediaplayer_p.h +++ b/src/mediaplayer_p.h @@ -26,14 +26,22 @@ #include <QObject> #include "mediaplayer.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "bluezmediaplayer1.h" #include "dbusproperties.h" +#else +#include "bluezmediaplayer.h" +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::MediaPlayer1 BluezMediaPlayer; typedef org::freedesktop::DBus::Properties DBusProperties; +#else +typedef org::bluez::MediaPlayer BluezMediaPlayer; +#endif class MediaPlayerPrivate : public QObject { @@ -49,9 +57,15 @@ public: MediaPlayerTrack variantToTrack(const QVariant &variant) const; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void mediaPlayerPropertyChanged(const QString &property, const QDBusVariant &value); +#endif + QWeakPointer<MediaPlayer> q; BluezMediaPlayer *m_bluezMediaPlayer; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusProperties *m_dbusProperties; +#endif QString m_name; MediaPlayer::Equalizer m_equalizer; diff --git a/src/mediatransport.cpp b/src/mediatransport.cpp index 375a8a9..3895df9 100644 --- a/src/mediatransport.cpp +++ b/src/mediatransport.cpp @@ -87,20 +87,35 @@ PendingCall *MediaTransport::setVolume(quint16 volume) PendingCall *MediaTransport::acquire() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaTransport->Acquire(), PendingCall::ReturnMediaTransportSocketInfo, this); +#else + return new PendingCall(d->m_bluezMediaTransport->Acquire(QStringLiteral("rw")), + PendingCall::ReturnMediaTransportSocketInfo, this); +#endif } PendingCall *MediaTransport::tryAcquire() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaTransport->TryAcquire(), PendingCall::ReturnMediaTransportSocketInfo, this); +#else + return new PendingCall(PendingCall::NotSupported, + QStringLiteral("MediaTransport::tryAcquire() not available in BlueZ 4!"), this); +#endif } PendingCall *MediaTransport::release() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezMediaTransport->Release(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(d->m_bluezMediaTransport->Release(QStringLiteral("rw")), + PendingCall::ReturnVoid, this); +#endif } } // namespace BluezQt diff --git a/src/mediatransport_p.cpp b/src/mediatransport_p.cpp index a08b0f7..73775ca 100644 --- a/src/mediatransport_p.cpp +++ b/src/mediatransport_p.cpp @@ -39,7 +39,9 @@ static MediaTransport::State stringToState(const QString &state) MediaTransportPrivate::MediaTransportPrivate(const QString &path, const QVariantMap &properties) : QObject() +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusProperties(0) +#endif , m_codec(0) , m_state(MediaTransport::StreamIdle) , m_delay(0) @@ -52,11 +54,16 @@ MediaTransportPrivate::MediaTransportPrivate(const QString &path, const QVariant void MediaTransportPrivate::init(const QVariantMap &properties) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_dbusProperties = new DBusProperties(Strings::orgBluez(), m_bluezMediaTransport->path(), DBusConnection::orgBluez(), this); connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &MediaTransportPrivate::propertiesChanged, Qt::QueuedConnection); +#else + connect(m_bluezMediaTransport, &BluezMediaTransport::PropertyChanged, + this, &MediaTransportPrivate::mediaTransportPropertyChanged); +#endif // Init properties m_uuid = properties.value(QStringLiteral("UUID")).toString(); @@ -69,14 +76,22 @@ void MediaTransportPrivate::init(const QVariantMap &properties) QDBusPendingReply<> MediaTransportPrivate::setDBusProperty(const QString &name, const QVariant &value) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return m_dbusProperties->Set(Strings::orgBluezMediaTransport1(), name, QDBusVariant(value)); +#else + return m_bluezMediaTransport->SetProperty(name, QDBusVariant(value)); +#endif } void MediaTransportPrivate::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated) { +#if KF5BLUEZQT_BLUEZ_VERSION < 5 if (interface != Strings::orgBluezMediaTransport1()) { return; } +#else + Q_UNUSED(interface) +#endif QVariantMap::const_iterator i; for (i = changed.constBegin(); i != changed.constEnd(); ++i) { @@ -115,4 +130,11 @@ void MediaTransportPrivate::propertiesChanged(const QString &interface, const QV } } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void MediaTransportPrivate::mediaTransportPropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(QStringLiteral("org.bluez.MediaTransport"), this, property, value.variant()); +} +#endif + } // namespace BluezQt diff --git a/src/mediatransport_p.h b/src/mediatransport_p.h index 51785e0..4ef1b46 100644 --- a/src/mediatransport_p.h +++ b/src/mediatransport_p.h @@ -26,14 +26,23 @@ #include <QObject> #include "mediatransport.h" + +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "bluezmediatransport1.h" #include "dbusproperties.h" +#else +#include "bluezmediatransport.h" +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::MediaTransport1 BluezMediaTransport; typedef org::freedesktop::DBus::Properties DBusProperties; +#else +typedef org::bluez::MediaTransport BluezMediaTransport; +#endif class MediaTransportPrivate : public QObject { @@ -47,9 +56,15 @@ public: QDBusPendingReply<> setDBusProperty(const QString &name, const QVariant &value); void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void mediaTransportPropertyChanged(const QString &property, const QDBusVariant &value); +#endif + QWeakPointer<MediaTransport> q; BluezMediaTransport *m_bluezMediaTransport; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusProperties *m_dbusProperties; +#endif QString m_uuid; quint8 m_codec; diff --git a/src/obexagentadaptor.cpp b/src/obexagentadaptor.cpp index 238c59d..4d908bd 100644 --- a/src/obexagentadaptor.cpp +++ b/src/obexagentadaptor.cpp @@ -25,7 +25,11 @@ #include "obexmanager.h" #include "obextransfer.h" #include "obextransfer_p.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "dbusproperties.h" +#else +#include "obexmanager_p.h" +#endif #include "utils.h" #include <QDBusObjectPath> @@ -33,7 +37,9 @@ namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::freedesktop::DBus::Properties DBusProperties; +#endif ObexAgentAdaptor::ObexAgentAdaptor(ObexAgent *parent, ObexManager *manager) : QDBusAbstractAdaptor(parent) @@ -42,17 +48,48 @@ ObexAgentAdaptor::ObexAgentAdaptor(ObexAgent *parent, ObexManager *manager) { } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 QString ObexAgentAdaptor::AuthorizePush(const QDBusObjectPath &transfer, const QDBusMessage &msg) +#else +QString ObexAgentAdaptor::Authorize(const QDBusObjectPath &transfer, const QString &bt_address, + const QString &name, const QString &type, qint32 length, + qint32 time, const QDBusMessage &msg) +#endif { msg.setDelayedReply(true); m_transferRequest = Request<QString>(OrgBluezObexAgent, msg); m_transferPath = transfer.path(); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusProperties dbusProperties(Strings::orgBluezObex(), m_transferPath, DBusConnection::orgBluezObex(), this); const QDBusPendingReply<QVariantMap> &call = dbusProperties.GetAll(Strings::orgBluezObexTransfer1()); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &ObexAgentAdaptor::getPropertiesFinished); +#else + m_transferRequest.setObjectPushTransferPath(transfer.path()); + + // Assemble the map of property values. In BlueZ 4, transfer objects provided by the org.bluez.obex + // service for OBEX agents (as opposed to those provided by the org.bluez.obex.client service + // for OBEX clients) don't have persistent properties provided by a GetProperties() function; + // instead, all values are provided by the AuthorizePush() arguments, so initialize them here. + // Note 'Filename' is not added here as it not available in BlueZ 4 and is optional in BlueZ 5. + QVariantMap properties; + properties.insert(QStringLiteral("Status"), QStringLiteral("queued")); + properties.insert(QStringLiteral("Name"), name); + properties.insert(QStringLiteral("Type"), type); + if (time > 0) { + properties.insert(QStringLiteral("Time"), static_cast<quint64>(time)); + } + if (length > 0) { + properties.insert(QStringLiteral("Size"), static_cast<quint64>(length)); + } + properties.insert(QStringLiteral("Transferred"), 0); + + // For BlueZ 4 there is only FTP session support, so manually add per-transfer OPP sessions. + ObexTransferPtr transferPtr = m_manager->d->newObjectPushTransfer(transfer, properties, bt_address); + getPropertiesFinished(transferPtr); +#endif return QString(); } @@ -67,6 +104,7 @@ void ObexAgentAdaptor::Release() m_agent->release(); } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ObexAgentAdaptor::getPropertiesFinished(QDBusPendingCallWatcher *watcher) { const QDBusPendingReply<QVariantMap> &reply = *watcher; @@ -79,6 +117,10 @@ void ObexAgentAdaptor::getPropertiesFinished(QDBusPendingCallWatcher *watcher) ObexTransferPtr transfer = ObexTransferPtr(new ObexTransfer(m_transferPath, reply.value())); transfer->d->q = transfer.toWeakRef(); +#else +void ObexAgentAdaptor::getPropertiesFinished(ObexTransferPtr transfer) +{ +#endif ObexSessionPtr session = m_manager->sessionForPath(transfer->objectPath()); Q_ASSERT(session); diff --git a/src/obexagentadaptor.h b/src/obexagentadaptor.h index 3de3b2b..ff3ca03 100644 --- a/src/obexagentadaptor.h +++ b/src/obexagentadaptor.h @@ -40,19 +40,33 @@ class ObexManager; class ObexAgentAdaptor : public QDBusAbstractAdaptor { Q_OBJECT +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 Q_CLASSINFO("D-Bus Interface", "org.bluez.obex.Agent1") +#else + Q_CLASSINFO("D-Bus Interface", "org.bluez.obex.Agent") +#endif public: explicit ObexAgentAdaptor(ObexAgent *parent, ObexManager *manager); public Q_SLOTS: +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 QString AuthorizePush(const QDBusObjectPath &transfer, const QDBusMessage &msg); +#else + QString Authorize(const QDBusObjectPath &transfer, const QString &bt_address, + const QString &name, const QString &type, qint32 length, + qint32 time, const QDBusMessage &msg); +#endif Q_NOREPLY void Cancel(); Q_NOREPLY void Release(); private Q_SLOTS: +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void getPropertiesFinished(QDBusPendingCallWatcher *watcher); +#else + void getPropertiesFinished(ObexTransferPtr transfer); +#endif private: ObexAgent *m_agent; diff --git a/src/obexfiletransfer.cpp b/src/obexfiletransfer.cpp index 1dec08e..9694056 100644 --- a/src/obexfiletransfer.cpp +++ b/src/obexfiletransfer.cpp @@ -24,12 +24,20 @@ #include "pendingcall.h" #include "utils.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "obexfiletransfer1.h" +#else +#include "bluezobexfiletransfer.h" +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::obex::FileTransfer1 BluezFileTransfer; +#else +typedef org::bluez::obex::FileTransfer BluezFileTransfer; +#endif class ObexFileTransferPrivate { @@ -42,8 +50,13 @@ ObexFileTransfer::ObexFileTransfer(const QDBusObjectPath &path, QObject *parent) : QObject(parent) , d(new ObexFileTransferPrivate) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 d->m_bluezFileTransfer = new BluezFileTransfer(Strings::orgBluezObex(), path.path(), DBusConnection::orgBluezObex(), this); +#else + d->m_bluezFileTransfer = new BluezFileTransfer(QStringLiteral("org.bluez.obex.client"), path.path(), + DBusConnection::orgBluezObex(), this); +#endif } ObexFileTransfer::~ObexFileTransfer() diff --git a/src/obexmanager.cpp b/src/obexmanager.cpp index 3b1baab..d7fbc74 100644 --- a/src/obexmanager.cpp +++ b/src/obexmanager.cpp @@ -74,6 +74,19 @@ ObexSessionPtr ObexManager::sessionForPath(const QDBusObjectPath &path) const return session; } } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + // In BlueZ 5, sessionForPath() can be used to find a session for a transfer, as transfer paths + // start with the associated session path. This is not the case in BlueZ 4, so mimic this + // feature by searching transfer paths here. + QString sessionPath = d->sessionForObjectPushTransfer(path); + if (!sessionPath.isEmpty()) { + if (!d->m_sessions.contains(sessionPath)) { + qCWarning(BLUEZQT) << "Cannot find matching session" << sessionPath << "for transfer" << path.path(); + return ObexSessionPtr(); + } + return d->m_sessions.value(sessionPath); + } +#endif return ObexSessionPtr(); } @@ -98,6 +111,16 @@ PendingCall *ObexManager::registerAgent(ObexAgent *agent) return new PendingCall(PendingCall::InternalError, QStringLiteral("ObexManager not operational!")); } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + if (!d->m_managerNotifier) { + d->m_managerNotifier = new ObexManagerNotifier(d); + if (ObexManagerNotifier::connection().registerObject(ObexManagerNotifier::objectPath(), d) + && ObexManagerNotifier::connection().registerService(ObexManagerNotifier::service())) { + qCDebug(BLUEZQT) << "Registered system OBEX manager notifier"; + } + } +#endif + new ObexAgentAdaptor(agent, this); if (!DBusConnection::orgBluezObex().registerObject(agent->objectPath().path(), agent)) { @@ -128,8 +151,19 @@ PendingCall *ObexManager::createSession(const QString &destination, const QVaria return new PendingCall(PendingCall::InternalError, QStringLiteral("ObexManager not operational!")); } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_obexClient->CreateSession(destination, args), PendingCall::ReturnObjectPath, this); +#else + // Manually add/remove sessions as DBusObjectManager is not available in BlueZ 4 to detect when + // they are created/removed. + PendingCall *call = new PendingCall(d->m_obexClient->CreateSession(destination, args), + PendingCall::ReturnObjectPath, this); + call->setProperty("destination", destination); + call->setProperty("args", args); + connect(call, &PendingCall::finished, d, &ObexManagerPrivate::createSessionFinished); + return call; +#endif } PendingCall *ObexManager::removeSession(const QDBusObjectPath &session) @@ -138,8 +172,18 @@ PendingCall *ObexManager::removeSession(const QDBusObjectPath &session) return new PendingCall(PendingCall::InternalError, QStringLiteral("ObexManager not operational!")); } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_obexClient->RemoveSession(session), PendingCall::ReturnVoid, this); +#else + // Manually add/remove sessions as DBusObjectManager is not available in BlueZ 4 to detect when + // they are created/removed. + PendingCall *call = new PendingCall(d->m_obexClient->RemoveSession(session), + PendingCall::ReturnVoid, this); + call->setProperty("session", session.path()); + connect(call, &PendingCall::finished, d, &ObexManagerPrivate::removeSessionFinished); + return call; +#endif } } // namespace BluezQt diff --git a/src/obexmanager.h b/src/obexmanager.h index 851978f..ab613a0 100644 --- a/src/obexmanager.h +++ b/src/obexmanager.h @@ -205,6 +205,10 @@ private: friend class ObexManagerPrivate; friend class InitObexManagerJobPrivate; + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + friend class ObexAgentAdaptor; +#endif }; } // namespace BluezQt diff --git a/src/obexmanager_p.cpp b/src/obexmanager_p.cpp index 2535b62..34e14e3 100644 --- a/src/obexmanager_p.cpp +++ b/src/obexmanager_p.cpp @@ -27,21 +27,60 @@ #include "debug.h" #include "utils.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "dbusobjectmanager.h" +#else +#include "obextransfer_p.h" +#include "pendingcall.h" +#include "bluezqt_dbustypes.h" +#include <QDBusMessage> +#endif + #include <QDBusServiceWatcher> namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::freedesktop::DBus::ObjectManager DBusObjectManager; +#else +ObexManagerNotifier::ObexManagerNotifier(ObexManagerPrivate *parent) + : QDBusAbstractAdaptor(parent) + , m_manager(parent) +{ + qDBusRegisterMetaType<QVariantMapMap>(); +} + +QMap<QString, QVariantMap> ObexManagerNotifier::getSessions() +{ + return m_manager->sessionProperties(); +} + +QMap<QString, QVariantMap> ObexManagerNotifier::getTransfers() +{ + return m_manager->transferProperties(); +} + +void ObexManagerNotifier::setTransferAborted(const QString &transferPath) +{ + m_manager->setTransferAborted(transferPath); +} + +#endif ObexManagerPrivate::ObexManagerPrivate(ObexManager *q) : QObject(q) , q(q) , m_obexClient(nullptr) , m_obexAgentManager(nullptr) +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusObjectManager(nullptr) +#else + , m_managerNotifier(nullptr) + , m_initializedSessions(false) + , m_initializedTransfers(false) +#endif , m_initialized(false) , m_obexRunning(false) , m_loaded(false) @@ -113,6 +152,7 @@ void ObexManagerPrivate::load() this, SLOT(dummy())); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_dbusObjectManager = new DBusObjectManager(Strings::orgBluezObex(), QStringLiteral("/"), DBusConnection::orgBluezObex(), this); @@ -123,8 +163,38 @@ void ObexManagerPrivate::load() QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(m_dbusObjectManager->GetManagedObjects(), this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &ObexManagerPrivate::getManagedObjectsFinished); +#else + m_obexClient = new ObexClient(QStringLiteral("org.bluez.obex.client"), "/", DBusConnection::orgBluezObex(), this); + m_obexAgentManager = new ObexAgentManager(Strings::orgBluezObex(), "/", DBusConnection::orgBluezObex(), this); + + connect(m_obexAgentManager, &ObexAgentManager::TransferStarted, + this, &ObexManagerPrivate::transferStarted); + connect(m_obexAgentManager, &ObexAgentManager::TransferCompleted, + this, &ObexManagerPrivate::transferCompleted); + + // Fetch known sessions from the "system" ObexManager + QDBusMessage getSessionsCall = QDBusMessage::createMethodCall(ObexManagerNotifier::service(), + ObexManagerNotifier::objectPath(), + ObexManagerNotifier::interface(), + QStringLiteral("getSessions")); + + QDBusPendingCallWatcher *getSessionsWatcher = new QDBusPendingCallWatcher(ObexManagerNotifier::connection().asyncCall(getSessionsCall)); + connect(getSessionsWatcher, &QDBusPendingCallWatcher::finished, this, &ObexManagerPrivate::getSessionsFinished); + + // Fetch known transfers from the "system" ObexManager, including those that are pending + // Authorize() and therefore cannot normally be fetched as BlueZ 4 would not have emitted + // transferStarted() for them yet. + QDBusMessage getTransfersCall = QDBusMessage::createMethodCall(ObexManagerNotifier::service(), + ObexManagerNotifier::objectPath(), + ObexManagerNotifier::interface(), + QStringLiteral("getTransfers")); + + QDBusPendingCallWatcher *getTransfersWatcher = new QDBusPendingCallWatcher(ObexManagerNotifier::connection().asyncCall(getTransfersCall)); + connect(getTransfersWatcher, &QDBusPendingCallWatcher::finished, this, &ObexManagerPrivate::getTransfersFinished); +#endif } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ObexManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watcher) { const QDBusPendingReply<DBusManagerStruct> &reply = *watcher; @@ -166,6 +236,7 @@ void ObexManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watc Q_EMIT q->operationalChanged(true); Q_EMIT initFinished(); } +#endif void ObexManagerPrivate::clear() { @@ -189,10 +260,12 @@ void ObexManagerPrivate::clear() m_obexAgentManager = nullptr; } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (m_dbusObjectManager) { m_dbusObjectManager->deleteLater(); m_dbusObjectManager = nullptr; } +#endif } void ObexManagerPrivate::serviceRegistered() @@ -215,6 +288,7 @@ void ObexManagerPrivate::serviceUnregistered() Q_EMIT q->operationalChanged(false); } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ObexManagerPrivate::interfacesAdded(const QDBusObjectPath &objectPath, const QVariantMapMap &interfaces) { const QString &path = objectPath.path(); @@ -226,7 +300,9 @@ void ObexManagerPrivate::interfacesAdded(const QDBusObjectPath &objectPath, cons } } } +#endif +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ObexManagerPrivate::interfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces) { const QString &path = objectPath.path(); @@ -237,6 +313,7 @@ void ObexManagerPrivate::interfacesRemoved(const QDBusObjectPath &objectPath, co } } } +#endif void ObexManagerPrivate::addSession(const QString &sessionPath, const QVariantMap &properties) { @@ -261,4 +338,250 @@ void ObexManagerPrivate::dummy() { } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void ObexManagerPrivate::getSessionsFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<QVariantMapMap> &reply = *watcher; + watcher->deleteLater(); + + m_initializedSessions = true; + + if (!reply.isError()) { + QVariantMapMap::const_iterator it; + const QVariantMapMap &sessions = reply.value(); + + for (it = sessions.constBegin(); it != sessions.constEnd(); ++it) { + const QString &path = it.key(); + const QVariantMap &properties = it.value(); + + addSession(path, properties); + } + } else if (reply.error().name() != QStringLiteral("org.freedesktop.DBus.Error.ServiceUnknown")) { + // Error can be ignored as it occurs if registerAgent() has not yet been called on any + // managers, which means this is probably the manager that will be used to register agents. + qCWarning(BLUEZQT) << "Failed to find existing sessions:" << reply.error().message(); + } + + if (m_initializedSessions && m_initializedTransfers) { + completeInit(); + } +} + +void ObexManagerPrivate::getTransfersFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<QVariantMapMap> &reply = *watcher; + watcher->deleteLater(); + + m_initializedTransfers = true; + + if (!reply.isError()) { + QVariantMapMap::const_iterator it; + const QVariantMapMap &transfers = reply.value(); + + for (it = transfers.constBegin(); it != transfers.constEnd(); ++it) { + const QString &path = it.key(); + const QVariantMap &properties = it.value(); + + if (!m_oppTransfers.contains(path)) { + ObexTransferPtr transfer = ObexTransferPtr(new ObexTransfer(path, properties)); + transfer->d->q = transfer.toWeakRef(); + m_oppTransfers.insert(path, transfer); + } + } + } else if (reply.error().name() != QStringLiteral("org.freedesktop.DBus.Error.ServiceUnknown")) { + // Error can be ignored as it occurs if registerAgent() has not yet been called on any + // managers, which means this is probably the manager that will be used to register agents. + qCWarning(BLUEZQT) << "Failed to find existing transfers:" << reply.error().message(); + } + + if (m_initializedSessions && m_initializedTransfers) { + completeInit(); + } +} + +void ObexManagerPrivate::completeInit() +{ + if (!ObexManagerNotifier::connection().connect(QString(), QString(), ObexManagerNotifier::interface(), + QStringLiteral("objectPushTransferCreated"), + this, SLOT(objectPushTransferCreated(QString,QVariantMap,QString,QVariantMap)))) { + qCWarning(BLUEZQT) << "Failed to connect to objectPushTransferCreated() signal"; + } + if (!ObexManagerNotifier::connection().connect(QString(), QString(), ObexManagerNotifier::interface(), + QStringLiteral("objectPushTransferFinished"), + this, SLOT(objectPushTransferFinished(QString,QString,bool)))) { + qCWarning(BLUEZQT) << "Failed to connect to objectPushTransferFinished() signal"; + } + + // Complete initialization as per getManagedObjectsFinished() + m_loaded = true; + m_initialized = true; + + Q_EMIT q->operationalChanged(true); + Q_EMIT initFinished(); +} + +ObexTransferPtr ObexManagerPrivate::newObjectPushTransfer(const QDBusObjectPath &transferPath, const QVariantMap &transferProperties, const QString &destinationAddress) +{ + ObexTransferPtr transfer = ObexTransferPtr(new ObexTransfer(transferPath.path(), transferProperties)); + transfer->d->q = transfer.toWeakRef(); + m_oppTransfers.insert(transferPath.path(), transfer); + + // Source, Channel and Target properties not added; not supportable in BlueZ 4. + QVariantMap sessionProperties; + sessionProperties.insert(QStringLiteral("Destination"), destinationAddress); + sessionProperties.insert(QStringLiteral("Root"), QDir::home().absolutePath()); + sessionProperties.insert(QStringLiteral("org.kde.bluezqt.ObjectPushTransfer"), transferPath.path()); + + QString sessionPath = QStringLiteral("/org/bluez/obex/server/session") + QString::number(m_sessions.count()); + addSession(sessionPath, sessionProperties); + + notifyObexManagers(QStringLiteral("objectPushTransferCreated"), + QVariantList() << transferPath.path() << transferProperties + << sessionPath << sessionProperties); + return transfer; +} + +void ObexManagerPrivate::objectPushTransferCreated(const QString &transferPath, const QVariantMap &transferProperties, + const QString &sessionPath, const QVariantMap &sessionProperties) +{ + if (!m_oppTransfers.contains(transferPath)) { + ObexTransferPtr transfer = ObexTransferPtr(new ObexTransfer(transferPath, transferProperties)); + transfer->d->q = transfer.toWeakRef(); + m_oppTransfers.insert(transferPath, transfer); + } + + if (!m_sessions.contains(sessionPath)) { + addSession(sessionPath, sessionProperties); + } +} + +void ObexManagerPrivate::objectPushTransferFinished(const QString &transferPath, const QString &sessionPath, bool success) +{ + Q_UNUSED(sessionPath); + + transferCompleted(QDBusObjectPath(transferPath), success); +} + +void ObexManagerPrivate::transferStarted(const QDBusObjectPath &objectPath) +{ + ObexTransferPtr transfer = m_oppTransfers.value(objectPath.path()); + if (!transfer.isNull()) { + transfer->setTransferProperty(QStringLiteral("Status"), QStringLiteral("active")); + } +} + +void ObexManagerPrivate::transferCompleted(const QDBusObjectPath &objectPath, bool success) +{ + ObexTransferPtr transfer = m_oppTransfers.value(objectPath.path()); + + if (!transfer.isNull()) { + transfer->setTransferProperty(QStringLiteral("Status"), + success ? QStringLiteral("complete") : QStringLiteral("error")); + m_oppTransfers.remove(objectPath.path()); + } + + QString sessionPath = sessionForObjectPushTransfer(objectPath); + if (!sessionPath.isEmpty()) { + removeSession(sessionPath); + } +} + +void ObexManagerPrivate::createSessionFinished(PendingCall *call) +{ + if (call->error()) { + return; + } + + QString destination = call->property("destination").toString(); + QVariantMap args = call->property("args").toMap(); + if (destination.isEmpty()) { + qCWarning(BLUEZQT) << "No destination provided for created session"; + return; + } + if (args.isEmpty()) { + qCWarning(BLUEZQT) << "No args provided for created session"; + return; + } + + addSession(destination, args); +} + +void ObexManagerPrivate::removeSessionFinished(PendingCall *call) +{ + if (call->error()) { + return; + } + + QString session = call->property("session").toString(); + if (session.isEmpty()) { + qCWarning(BLUEZQT) << "No session path provided for removed session"; + return; + } + + removeSession(session); +} + +void ObexManagerPrivate::setTransferAborted(const QString &transferPath) +{ + // For BlueZ 4 OPP sessions are manually manged, and there is no way to detect when a transfer + // is rejected by Authorize() and thus the session and transfer should be removed, so the + // manager depends on this method being called in those cases. + + Q_FOREACH (ObexSessionPtr session, m_sessions) { + if (session->d->m_oppTransferPath == transferPath) { + notifyObexManagers(QStringLiteral("objectPushTransferFinished"), + QVariantList() << transferPath << session->d->m_sessionPath << false); + break; + } + } +} + +void ObexManagerPrivate::notifyObexManagers(const QString &signalName, const QVariantList &args) +{ + QDBusMessage message = QDBusMessage::createSignal("/", ObexManagerNotifier::interface(), signalName); + message.setArguments(args); + + if (!ObexManagerNotifier::connection().send(message)) { + qCWarning(BLUEZQT) << "Failed to notify OBEX managers of signal" << signalName + << "with args" << args; + } +} + +QVariantMapMap ObexManagerPrivate::sessionProperties() const +{ + QVariantMapMap properties; + + Q_FOREACH (ObexSessionPtr session, m_sessions) { + properties.insert(session->d->m_sessionPath, session->d->m_properties); + } + + return properties; +} + +QVariantMapMap ObexManagerPrivate::transferProperties() const +{ + QVariantMapMap properties; + QHash<QString, ObexTransferPtr>::const_iterator it; + + for (it = m_oppTransfers.constBegin(); it != m_oppTransfers.constEnd(); ++it) { + const QString &path = it.key(); + const ObexTransferPtr &transfer = it.value(); + + properties.insert(path, transfer->d->m_properties); + } + + return properties; +} + +QString ObexManagerPrivate::sessionForObjectPushTransfer(const QDBusObjectPath &transferPath) +{ + Q_FOREACH (ObexSessionPtr session, m_sessions) { + if (session->d->m_oppTransferPath == transferPath.path()) { + return session->d->m_sessionPath; + } + } + return QString(); +} +#endif + } // namespace BluezQt diff --git a/src/obexmanager_p.h b/src/obexmanager_p.h index 437d663..58e6d75 100644 --- a/src/obexmanager_p.h +++ b/src/obexmanager_p.h @@ -27,16 +27,54 @@ #include <QTimer> #include "types.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "dbusobjectmanager.h" #include "obexclient1.h" #include "obexagentmanager1.h" +#else +#include "bluezqt_dbustypes.h" +#include "bluezobexclient.h" +#include "bluezobexmanager.h" +#include <QDBusAbstractAdaptor> +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::obex::Client1 ObexClient; typedef org::bluez::obex::AgentManager1 ObexAgentManager; typedef org::freedesktop::DBus::ObjectManager DBusObjectManager; +#else +typedef org::bluez::obex::Client ObexClient; +typedef org::bluez::obex::Manager ObexAgentManager; +#endif + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +class ObexManagerPrivate; + +class ObexManagerNotifier : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.bluezqt.obex.ObexManager") +public: + ObexManagerNotifier(ObexManagerPrivate *parent); + + inline static QDBusConnection connection() { return QDBusConnection::sessionBus(); } + inline static QString service() { return QStringLiteral("org.kde.bluezqt.obex"); } + inline static QString objectPath() { return QStringLiteral("/org/kde/bluezqt/obex/ObexManager"); } + inline static QString interface() { return QStringLiteral("org.kde.bluezqt.obex.ObexManager"); } + +public Q_SLOTS: + QMap<QString, QVariantMap> getSessions(); + QMap<QString, QVariantMap> getTransfers(); + void setTransferAborted(const QString &transferPath); + +private: + friend class ObexManagerPrivate; + ObexManagerPrivate *m_manager; +}; +#endif class ObexManager; @@ -55,16 +93,43 @@ public: void serviceRegistered(); void serviceUnregistered(); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void interfacesAdded(const QDBusObjectPath &objectPath, const QVariantMapMap &interfaces); void interfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces); +#endif void addSession(const QString &sessionPath, const QVariantMap &properties); void removeSession(const QString &sessionPath); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void getSessionsFinished(QDBusPendingCallWatcher *watcher); + void getTransfersFinished(QDBusPendingCallWatcher *watcher); + void completeInit(); + + ObexTransferPtr newObjectPushTransfer(const QDBusObjectPath &transferPath, const QVariantMap &transferProperties, const QString &destinationAddress); + void transferStarted(const QDBusObjectPath &objectPath); + void transferCompleted(const QDBusObjectPath &objectPath, bool success); + void createSessionFinished(PendingCall *call); + void removeSessionFinished(PendingCall *call); + + void setTransferAborted(const QString &transferPath); + void notifyObexManagers(const QString &signalName, const QVariantList &args); + QVariantMapMap sessionProperties() const; + QVariantMapMap transferProperties() const; + QString sessionForObjectPushTransfer(const QDBusObjectPath &transferPath); +#endif + ObexManager *q; ObexClient *m_obexClient; ObexAgentManager *m_obexAgentManager; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusObjectManager *m_dbusObjectManager; +#else + QHash<QString, ObexTransferPtr> m_oppTransfers; + ObexManagerNotifier *m_managerNotifier; + bool m_initializedSessions; + bool m_initializedTransfers; +#endif QTimer m_timer; QHash<QString, ObexSessionPtr> m_sessions; @@ -79,6 +144,11 @@ Q_SIGNALS: private Q_SLOTS: void dummy(); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void objectPushTransferCreated(const QString &transferPath, const QVariantMap &transferProperties, + const QString &sessionPath, const QVariantMap &sessionProperties); + void objectPushTransferFinished(const QString &transferPath, const QString &sessionPath, bool success); +#endif }; } // namespace BluezQt diff --git a/src/obexobjectpush.cpp b/src/obexobjectpush.cpp index 07c4549..3a6e03e 100644 --- a/src/obexobjectpush.cpp +++ b/src/obexobjectpush.cpp @@ -24,12 +24,20 @@ #include "pendingcall.h" #include "utils.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "obexobjectpush1.h" +#else +#include "bluezobexobjectpush.h" +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::obex::ObjectPush1 BluezObjectPush; +#else +typedef org::bluez::obex::ObjectPush BluezObjectPush; +#endif class ObexObjectPushPrivate { @@ -42,8 +50,13 @@ ObexObjectPush::ObexObjectPush(const QDBusObjectPath &path, QObject *parent) : QObject(parent) , d(new ObexObjectPushPrivate) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 d->m_bluezObjectPush = new BluezObjectPush(Strings::orgBluezObex(), path.path(), DBusConnection::orgBluezObex(), this); +#else + d->m_bluezObjectPush = new BluezObjectPush(QStringLiteral("org.bluez.obex.client"), + path.path(), DBusConnection::orgBluezObex(), this); +#endif } ObexObjectPush::~ObexObjectPush() diff --git a/src/obexsession.cpp b/src/obexsession.cpp index e9f7dfe..7df17e3 100644 --- a/src/obexsession.cpp +++ b/src/obexsession.cpp @@ -25,14 +25,22 @@ #include "pendingcall.h" #include "utils.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include <QDBusObjectPath> +#endif + namespace BluezQt { ObexSessionPrivate::ObexSessionPrivate(const QString &path, const QVariantMap &properties) : QObject() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_bluezSession = new BluezSession(Strings::orgBluezObex(), path, DBusConnection::orgBluezObex(), this); +#else + m_sessionPath = path; +#endif init(properties); } @@ -44,6 +52,10 @@ void ObexSessionPrivate::init(const QVariantMap &properties) m_channel = properties.value(QStringLiteral("Channel")).toUInt(); m_target = properties.value(QStringLiteral("Target")).toString().toUpper(); m_root = properties.value(QStringLiteral("Root")).toString(); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + m_oppTransferPath = properties.value(QStringLiteral("org.kde.bluezqt.ObjectPushTransfer")).toString(); + m_properties = properties; +#endif } ObexSession::ObexSession(const QString &path, const QVariantMap &properties) @@ -64,7 +76,11 @@ ObexSessionPtr ObexSession::toSharedPtr() const QDBusObjectPath ObexSession::objectPath() const { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return QDBusObjectPath(d->m_bluezSession->path()); +#else + return QDBusObjectPath(d->m_sessionPath); +#endif } QString ObexSession::source() const @@ -94,7 +110,11 @@ QString ObexSession::root() const PendingCall *ObexSession::getCapabilities() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezSession->GetCapabilities(), PendingCall::ReturnString, this); +#else + return new PendingCall(PendingCall::NotSupported, QString("ObexSession::getCapabilities() not available in BlueZ 4!"), this); +#endif } } // namespace BluezQt diff --git a/src/obexsession_p.h b/src/obexsession_p.h index f772b51..b8cc6f4 100644 --- a/src/obexsession_p.h +++ b/src/obexsession_p.h @@ -23,14 +23,20 @@ #ifndef BLUEZQT_OBEXSESSION_P_H #define BLUEZQT_OBEXSESSION_P_H +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "obexsession1.h" +#else +#include "obexsession.h" +#endif namespace BluezQt { class ObexSession; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::obex::Session1 BluezSession; +#endif class ObexSessionPrivate : public QObject { @@ -42,7 +48,13 @@ public: void init(const QVariantMap &properties); QWeakPointer<ObexSession> q; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 BluezSession *m_bluezSession; +#else + QString m_sessionPath; + QString m_oppTransferPath; + QVariantMap m_properties; +#endif QString m_source; QString m_destination; diff --git a/src/obextransfer.cpp b/src/obextransfer.cpp index dc642cc..faef66a 100644 --- a/src/obextransfer.cpp +++ b/src/obextransfer.cpp @@ -28,6 +28,10 @@ #include "utils.h" #include "macros.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include <QMimeDatabase> +#endif + namespace BluezQt { @@ -49,29 +53,72 @@ static ObexTransfer::Status stringToStatus(const QString &status) ObexTransferPrivate::ObexTransferPrivate(const QString &path, const QVariantMap &properties) : QObject() +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusProperties(nullptr) +#else + , m_clientOrigin(path.contains(QStringLiteral("session"))) +#endif , m_status(ObexTransfer::Error) , m_time(0) , m_size(0) , m_transferred(0) , m_suspendable(false) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_bluezTransfer = new BluezTransfer(Strings::orgBluezObex(), path, DBusConnection::orgBluezObex(), this); +#else + const QString &service = m_clientOrigin ? QStringLiteral("org.bluez.obex.client") : Strings::orgBluezObex(); + m_bluezTransfer = new BluezTransfer(service, path, DBusConnection::orgBluezObex(), this); +#endif if (Instance::obexManager()) { connect(Instance::obexManager(), &ObexManager::sessionRemoved, this, &ObexTransferPrivate::sessionRemoved); } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 init(properties); +#else + // Ensure the properties contain the non-optional Status and Type properties, which are not + // specified for transfers provided by the org.bluez.obex.client service in BlueZ 4. Also, + // 'Progress' has been renamed to 'Transferred'. + // This doesn't need to be done for transfers provided by the org.bluez.obex service (i.e. from + // OBEX agents) as ObexAgentAdaptor already adds these in the AuthorizePush() handler. + QVariantMap modifiedProperties = properties; + if (m_clientOrigin) { + static const QMimeDatabase mimeDatabase; + const QString &name = properties.value(QStringLiteral("name")).toString(); + const QString &type = mimeDatabase.mimeTypeForFile(name).name(); + + modifiedProperties.insert(QStringLiteral("Status"), QStringLiteral("queued")); + modifiedProperties.insert(QStringLiteral("Type"), type); + modifiedProperties.insert(QStringLiteral("Transferred"), properties.value(QStringLiteral("Progress")).toUInt()); + } + init(modifiedProperties); + m_properties = properties; +#endif } void ObexTransferPrivate::init(const QVariantMap &properties) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_dbusProperties = new DBusProperties(Strings::orgBluezObex(), m_bluezTransfer->path(), DBusConnection::orgBluezObex(), this); connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &ObexTransferPrivate::propertiesChanged, Qt::QueuedConnection); +#else + if (m_clientOrigin) { + connect(m_bluezTransfer, &BluezTransfer::PropertyChanged, + this, &ObexTransferPrivate::orgBluezObexClientTransferPropertyChanged, Qt::QueuedConnection); + connect(m_bluezTransfer, &BluezTransfer::Complete, + this, &ObexTransferPrivate::orgBluezObexClientTransferComplete, Qt::QueuedConnection); + connect(m_bluezTransfer, &BluezTransfer::Error, + this, &ObexTransferPrivate::orgBluezObexClientTransferError, Qt::QueuedConnection); + } else { + connect(m_bluezTransfer, &BluezTransfer::Progress, + this, &ObexTransferPrivate::orgBluezObexTransferProgress, Qt::QueuedConnection); + } +#endif // Init properties m_status = stringToStatus(properties.value(QStringLiteral("Status")).toString()); @@ -87,9 +134,13 @@ void ObexTransferPrivate::propertiesChanged(const QString &interface, const QVar { Q_UNUSED(invalidated) +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (interface != Strings::orgBluezObexTransfer1()) { return; } +#else + Q_UNUSED(interface) +#endif QVariantMap::const_iterator i; for (i = changed.constBegin(); i != changed.constEnd(); ++i) { @@ -103,6 +154,13 @@ void ObexTransferPrivate::propertiesChanged(const QString &interface, const QVar } else if (property == QLatin1String("Filename")) { PROPERTY_CHANGED(m_fileName, toString, fileNameChanged); } + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + // 'Transferred' was 'Progress' in BlueZ 4 + if (property == QLatin1String("Progress")) { + PROPERTY_CHANGED(m_transferred, toUInt, transferredChanged); + } +#endif } } @@ -119,6 +177,33 @@ void ObexTransferPrivate::sessionRemoved(const ObexSessionPtr &session) } } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void ObexTransferPrivate::orgBluezObexTransferProgress(qint32 total, qint32 transferred) +{ + Q_UNUSED(total) + + QVariant value = static_cast<quint64>(transferred); + INVOKE_PROPERTIES_CHANGED(QStringLiteral("org.bluez.Transfer"), this, QStringLiteral("Progress"), value); +} + +void ObexTransferPrivate::orgBluezObexClientTransferComplete() +{ + QVariant value = QStringLiteral("complete"); + PROPERTY_CHANGED2(m_status, stringToStatus(value.toString()), statusChanged); +} + +void ObexTransferPrivate::orgBluezObexClientTransferError(const QString &code, const QString &message) +{ + QVariant value = QStringLiteral("error"); + PROPERTY_CHANGED2(m_status, stringToStatus(value.toString()), statusChanged); +} + +void ObexTransferPrivate::orgBluezObexClientTransferPropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(QStringLiteral("org.bluez.obex.Transfer"), this, property, value.variant()); +} +#endif + ObexTransfer::ObexTransfer(const QString &path, const QVariantMap &properties) : QObject() , d(new ObexTransferPrivate(path, properties)) @@ -177,7 +262,11 @@ QString ObexTransfer::fileName() const bool ObexTransfer::isSuspendable() const { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return d->m_suspendable; +#else + return false; +#endif } PendingCall *ObexTransfer::cancel() @@ -187,12 +276,27 @@ PendingCall *ObexTransfer::cancel() PendingCall *ObexTransfer::suspend() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezTransfer->Suspend(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("ObexTransfer::suspend() not available in BlueZ 4!"), this); +#endif } PendingCall *ObexTransfer::resume() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezTransfer->Resume(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(PendingCall::NotSupported, QStringLiteral("ObexTransfer::resume() not available in BlueZ 4!"), this); +#endif +} + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void ObexTransfer::setTransferProperty(const QString &property, const QVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(QStringLiteral("org.bluez.Transfer"), d, property, value); } +#endif } // namespace BluezQt diff --git a/src/obextransfer.h b/src/obextransfer.h index 72cbce7..0840fb6 100644 --- a/src/obextransfer.h +++ b/src/obextransfer.h @@ -180,6 +180,10 @@ public: */ PendingCall *resume(); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void setTransferProperty(const QString &property, const QVariant &value); +#endif + Q_SIGNALS: /** * Indicates that the status of transfer have changed. @@ -204,6 +208,10 @@ private: friend class ObexTransferPrivate; friend class ObexAgentAdaptor; friend class PendingCallPrivate; + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + friend class ObexManagerPrivate; +#endif }; } // namespace BluezQt diff --git a/src/obextransfer_p.h b/src/obextransfer_p.h index 4dd8078..ae30150 100644 --- a/src/obextransfer_p.h +++ b/src/obextransfer_p.h @@ -25,14 +25,22 @@ #include "obextransfer.h" +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "obextransfer1.h" #include "dbusproperties.h" +#else +#include "bluezobextransfer.h" +#endif namespace BluezQt { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 typedef org::bluez::obex::Transfer1 BluezTransfer; typedef org::freedesktop::DBus::Properties DBusProperties; +#else +typedef org::bluez::obex::Transfer BluezTransfer; +#endif class ObexTransferPrivate : public QObject { @@ -46,9 +54,24 @@ public: void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated); void sessionRemoved(const ObexSessionPtr &session); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + // from org.bluez.obex service + void orgBluezObexTransferProgress(qint32 total, qint32 transferred); + + // from org.bluez.obex.client service + void orgBluezObexClientTransferPropertyChanged(const QString &property, const QDBusVariant &value); + void orgBluezObexClientTransferComplete(); + void orgBluezObexClientTransferError(const QString &code, const QString &message); +#endif + QWeakPointer<ObexTransfer> q; BluezTransfer *m_bluezTransfer; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 DBusProperties *m_dbusProperties; +#else + bool m_clientOrigin; + QVariantMap m_properties; +#endif ObexTransfer::Status m_status; QString m_name; diff --git a/src/pendingcall.cpp b/src/pendingcall.cpp index 8b19c4e..ee42f6d 100644 --- a/src/pendingcall.cpp +++ b/src/pendingcall.cpp @@ -85,7 +85,11 @@ public: void processStringReply(const QDBusPendingReply<QString> &reply); void processObjectPathReply(const QDBusPendingReply<QDBusObjectPath> &reply); void processFileTransferListReply(const QDBusPendingReply<QVariantMapList> &reply); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void processTransferWithPropertiesReply(const QDBusPendingReply<QDBusObjectPath, QVariantMap> &reply); +#else + void processTransferWithPropertiesReply(const QDBusPendingReply<ObexTransferInfo> &reply); +#endif void processMediaTransportSocketInfoReply(const QDBusPendingReply<QDBusUnixFileDescriptor, quint16, quint16> &reply); void processError(const QDBusError &m_error); @@ -190,14 +194,23 @@ void PendingCallPrivate::processFileTransferListReply(const QDBusPendingReply<QV } } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void PendingCallPrivate::processTransferWithPropertiesReply(const QDBusPendingReply<QDBusObjectPath, QVariantMap> &reply) +#else +void PendingCallPrivate::processTransferWithPropertiesReply(const QDBusPendingReply<ObexTransferInfo> &reply) +#endif { processError(reply.error()); if (reply.isError()) { return; } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 ObexTransferPtr transfer = ObexTransferPtr(new ObexTransfer(reply.argumentAt<0>().path(), reply.argumentAt<1>())); +#else + const ObexTransferInfo &info = reply.argumentAt<0>(); + ObexTransferPtr transfer = ObexTransferPtr(new ObexTransfer(info.first.path(), info.second)); +#endif transfer->d->q = transfer.toWeakRef(); transfer->d->m_suspendable = true; m_value.append(QVariant::fromValue(transfer)); @@ -259,6 +272,11 @@ PendingCall::PendingCall(const QDBusPendingCall &call, ReturnType type, QObject { qDBusRegisterMetaType<QVariantMapList>(); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + qDBusRegisterMetaType<DeviceServiceMap>(); + qDBusRegisterMetaType<ObexTransferInfo>(); +#endif + d->m_type = type; d->m_watcher = new QDBusPendingCallWatcher(call, this); diff --git a/src/request.cpp b/src/request.cpp index 0a36cf1..da6cbee 100644 --- a/src/request.cpp +++ b/src/request.cpp @@ -24,6 +24,10 @@ #include "debug.h" #include "utils.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "obexmanager_p.h" +#endif + #include <QStringBuilder> #include <QDBusMessage> #include <QDBusConnection> @@ -43,6 +47,11 @@ public: void acceptRequest(const QVariant &val); void rejectRequest(); void cancelRequest(); + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + QString m_oppTransferPath; + void notifyTransferAborted(); +#endif }; bool RequestPrivate::sendMessage(const QDBusMessage &msg) @@ -94,6 +103,10 @@ void RequestPrivate::rejectRequest() if (!sendMessage(reply)) { qCWarning(BLUEZQT) << "Request: Failed to put reply on DBus queue"; } + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + notifyTransferAborted(); +#endif } void RequestPrivate::cancelRequest() @@ -103,8 +116,30 @@ void RequestPrivate::cancelRequest() if (!sendMessage(reply)) { qCWarning(BLUEZQT) << "Request: Failed to put reply on DBus queue"; } + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + notifyTransferAborted(); +#endif } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void RequestPrivate::notifyTransferAborted() +{ + if (m_type == OrgBluezObexAgent && !m_oppTransferPath.isEmpty()) { + QDBusMessage call = QDBusMessage::createMethodCall(ObexManagerNotifier::service(), + ObexManagerNotifier::objectPath(), + ObexManagerNotifier::interface(), + QStringLiteral("setTransferAborted")); + + call << m_oppTransferPath; + + if (!ObexManagerNotifier::connection().send(call)) { + qCWarning(BLUEZQT) << "Request: Failed to notify manager of aborted transfer"; + } + } +} +#endif + // T template<typename T> Request<T>::Request() @@ -158,6 +193,14 @@ void Request<T>::cancel() const d->cancelRequest(); } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +template<typename T> +void Request<T>::setObjectPushTransferPath(const QString &transferPath) +{ + d->m_oppTransferPath = transferPath; +} +#endif + // void Request<void>::Request() : d(new RequestPrivate) @@ -203,6 +246,13 @@ void Request<void>::cancel() const d->cancelRequest(); } +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void Request<void>::setObjectPushTransferPath(const QString &transferPath) +{ + d->m_oppTransferPath = transferPath; +} +#endif + // Generate classes template class Request<void>; template class Request<quint32>; diff --git a/src/request.h b/src/request.h index d8d1257..88a66e4 100644 --- a/src/request.h +++ b/src/request.h @@ -103,6 +103,10 @@ public: */ void cancel() const; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void setObjectPushTransferPath(const QString &transferPath); +#endif + private: explicit Request(RequestOriginatingType type, const QDBusMessage &message); @@ -128,6 +132,10 @@ public: void reject() const; void cancel() const; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void setObjectPushTransferPath(const QString &transferPath); +#endif + private: explicit Request(RequestOriginatingType type, const QDBusMessage &message); diff --git a/src/src.pro b/src/src.pro index 5d3eca8..9a5d0de 100644 --- a/src/src.pro +++ b/src/src.pro @@ -14,56 +14,15 @@ isEmpty(PREFIX) { include(../bluezqt_version.pri) -XML_DIR = $$PWD/interfaces -system(qdbusxml2cpp -c ObjectManager -p dbusobjectmanager.h:dbusobjectmanager.cpp $$XML_DIR/org.freedesktop.DBus.ObjectManager.xml -i $$PWD/bluezqt_dbustypes.h) -system(qdbusxml2cpp -c ObexFileTransfer -p obexfiletransfer1.h:obexfiletransfer1.cpp $$XML_DIR/org.bluez.obex.FileTransfer1.xml -i $$PWD/bluezqt_dbustypes.h) -system(qdbusxml2cpp -c Properties -p dbusproperties.h:dbusproperties.cpp $$XML_DIR/org.freedesktop.DBus.Properties.xml) -system(qdbusxml2cpp -c BluezAdapter -p bluezadapter1.h:bluezadapter1.cpp $$XML_DIR/org.bluez.Adapter1.xml) -system(qdbusxml2cpp -c BluezAgentManager -p bluezagentmanager1.h:bluezagentmanager1.cpp $$XML_DIR/org.bluez.AgentManager1.xml) -system(qdbusxml2cpp -c BluezProfileManager -p bluezprofilemanager1.h:bluezprofilemanager1.cpp $$XML_DIR/org.bluez.ProfileManager1.xml) -system(qdbusxml2cpp -c BluezDevice -p bluezdevice1.h:bluezdevice1.cpp $$XML_DIR/org.bluez.Device1.xml) -system(qdbusxml2cpp -c BluezMediaPlayer -p bluezmediaplayer1.h:bluezmediaplayer1.cpp $$XML_DIR/org.bluez.MediaPlayer1.xml) -system(qdbusxml2cpp -c BluezMediaTransport -p bluezmediatransport1.h:bluezmediatransport1.cpp $$XML_DIR/org.bluez.MediaTransport1.xml) -system(qdbusxml2cpp -c ObexAgentManager -p obexagentmanager1.h:obexagentmanager1.cpp $$XML_DIR/org.bluez.obex.AgentManager1.xml) -system(qdbusxml2cpp -c ObexClient -p obexclient1.h:obexclient1.cpp $$XML_DIR/org.bluez.obex.Client1.xml) -system(qdbusxml2cpp -c ObexTransfer -p obextransfer1.h:obextransfer1.cpp $$XML_DIR/org.bluez.obex.Transfer1.xml) -system(qdbusxml2cpp -c ObexSession -p obexsession1.h:obexsession1.cpp $$XML_DIR/org.bluez.obex.Session1.xml) -system(qdbusxml2cpp -c ObexObjectPush -p obexobjectpush1.h:obexobjectpush1.cpp $$XML_DIR/org.bluez.obex.ObjectPush1.xml) - -DBUS_SOURCES += \ - dbusobjectmanager.cpp \ - obexfiletransfer1.cpp \ - dbusproperties.cpp \ - bluezadapter1.cpp \ - bluezagentmanager1.cpp \ - bluezprofilemanager1.cpp \ - bluezdevice1.cpp \ - bluezmediaplayer1.cpp \ - bluezmediatransport1.cpp \ - obexagentmanager1.cpp \ - obexclient1.cpp \ - obextransfer1.cpp \ - obexsession1.cpp \ - obexobjectpush1.cpp - -DBUS_HEADERS += \ - dbusobjectmanager.h \ - obexfiletransfer1.h \ - dbusproperties.h \ - bluezadapter1.h \ - bluezagentmanager1.h \ - bluezprofilemanager1.h \ - bluezdevice1.h \ - bluezmediaplayer1.h \ - bluezmediatransport1.h \ - obexagentmanager1.h \ - obexclient1.h \ - obextransfer1.h \ - obexsession1.h \ - obexobjectpush1.h +equals(KF5BLUEZQT_BLUEZ_VERSION, 5) { + DEFINES += "KF5BLUEZQT_BLUEZ_VERSION=5" + include(interfaces/interfaces.pri) +} else { + DEFINES += "KF5BLUEZQT_BLUEZ_VERSION=4" + include(interfaces/bluez4/bluez4.pri) +} SOURCES += \ - $$DBUS_SOURCES \ debug.cpp \ manager.cpp \ manager_p.cpp \ @@ -129,7 +88,6 @@ PUBLIC_HEADERS += \ HEADERS += \ $$PUBLIC_HEADERS \ - $$DBUS_HEADERS \ agentadaptor.h \ obexagentadaptor.h \ profileadaptor.h \ @@ -148,9 +106,6 @@ HEADERS += \ utils.h \ rfkill.h -OTHER_FILES += \ - $$XML_DIR/*.xml - target.path = $$[QT_INSTALL_LIBS] headers.files = $$PUBLIC_HEADERS @@ -162,7 +117,7 @@ pkgconfig.path = $$[QT_INSTALL_LIBS]/pkgconfig QMAKE_PKGCONFIG_NAME = $$TARGET QMAKE_PKGCONFIG_DESTDIR = pkgconfig QMAKE_PKGCONFIG_INCDIR = $$headers.path -QMAKE_PKGCONFIG_DESCRIPTION = Qt bindings for BlueZ 5 +QMAKE_PKGCONFIG_DESCRIPTION = Qt bindings for BlueZ 5 (with partial support for BlueZ 4 backends) QMAKE_PKGCONFIG_PREFIX = $$PREFIX QMAKE_PKGCONFIG_VERSION = $$VERSION -- 2.33.1