Search
SailfishOS Open Build Service
>
Projects
>
nemo
:
testing:hw
:
lge
:
hammerhead
>
kf5bluezqt
> _service:tar_git:0005-Provide-binary-compatibility-between-BlueZ-variant-p.patch
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File _service:tar_git:0005-Provide-binary-compatibility-between-BlueZ-variant-p.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:11:08 +0200 Subject: [PATCH] Provide binary compatibility between BlueZ variant packages. Fixes JB#36929 Don't change the public headers between the -bluez4 and -bluez5 variants. Specifically, the deviations in agent.h, obextransfer.h, pendingcall.h and request.h have been removed. This provides binary compatibility when switching between -bluez4 and -bluez5 packages. Also, move the majority of the BlueZ 4 handling into src/bluez4 to make it easier to clearly see and separate this handling. --- .gitignore | 19 ++ src/adapter.cpp | 33 +- src/adapter.h | 6 +- src/adapter_p.cpp | 66 +--- src/adapter_p.h | 21 +- src/agent.cpp | 141 -------- src/agent.h | 35 -- src/agentadaptor.cpp | 8 - src/agentadaptor.h | 8 - src/bluez4/adapter_bluez4.cpp | 103 ++++++ src/bluez4/adapter_bluez4_p.h | 65 ++++ src/bluez4/agentadaptor_bluez4.cpp | 152 +++++++++ src/bluez4/agentadaptor_bluez4_p.h | 74 +++++ src/bluez4/bluez4.pri | 27 ++ src/bluez4/bluezqt_dbustypes_bluez4_p.h | 34 ++ src/bluez4/device_bluez4.cpp | 88 +++++ src/bluez4/device_bluez4_p.h | 61 ++++ src/bluez4/macros_bluez4_p.h | 37 +++ src/bluez4/manager_bluez4.cpp | 397 ++++++++++++++++++++++ src/bluez4/manager_bluez4_p.h | 91 +++++ src/bluez4/mediaplayer_bluez4.cpp | 47 +++ src/bluez4/mediaplayer_bluez4_p.h | 52 +++ src/bluez4/mediatransport_bluez4.cpp | 47 +++ src/bluez4/mediatransport_bluez4_p.h | 52 +++ src/bluez4/obexagentadaptor_bluez4.cpp | 106 ++++++ src/bluez4/obexagentadaptor_bluez4_p.h | 68 ++++ src/bluez4/obexmanager_bluez4.cpp | 419 ++++++++++++++++++++++++ src/bluez4/obexmanager_bluez4_p.h | 143 ++++++++ src/bluez4/obexsession_bluez4.cpp | 47 +++ src/bluez4/obexsession_bluez4_p.h | 48 +++ src/bluez4/obextransfer_bluez4.cpp | 113 +++++++ src/bluez4/obextransfer_bluez4_p.h | 60 ++++ src/bluez4/proxyagent.cpp | 164 ++++++++++ src/bluez4/proxyagent_p.h | 67 ++++ src/bluezqt_dbustypes.h | 8 - src/device.cpp | 29 +- src/device.h | 2 + src/device_p.cpp | 43 +-- src/device_p.h | 24 +- src/input.cpp | 13 +- src/interfaces/bluez4/bluez4.pri | 74 ++--- src/interfaces/interfaces.pri | 22 +- src/macros.h | 12 - src/manager.cpp | 20 +- src/manager_p.cpp | 370 +++------------------ src/manager_p.h | 50 +-- src/mediaplayer.cpp | 13 +- src/mediaplayer_p.cpp | 24 +- src/mediaplayer_p.h | 17 +- src/mediatransport.cpp | 8 +- src/mediatransport_p.cpp | 24 +- src/mediatransport_p.h | 18 +- src/obexagentadaptor.cpp | 38 +-- src/obexagentadaptor.h | 14 - src/obexfiletransfer.cpp | 2 +- src/obexmanager.cpp | 72 ++-- src/obexmanager.h | 4 +- src/obexmanager_p.cpp | 340 ++----------------- src/obexmanager_p.h | 72 +--- src/obexobjectpush.cpp | 2 +- src/obexsession.cpp | 12 +- src/obexsession.h | 2 + src/obexsession_p.h | 9 +- src/obextransfer.cpp | 98 +----- src/obextransfer.h | 8 +- src/obextransfer_p.h | 23 +- src/pendingcall.cpp | 5 + src/pendingcall.h | 2 + src/profile.cpp | 3 + src/request.cpp | 39 +-- src/request.h | 18 +- src/src.pro | 6 +- 72 files changed, 2960 insertions(+), 1479 deletions(-) create mode 100644 src/bluez4/adapter_bluez4.cpp create mode 100644 src/bluez4/adapter_bluez4_p.h create mode 100644 src/bluez4/agentadaptor_bluez4.cpp create mode 100644 src/bluez4/agentadaptor_bluez4_p.h create mode 100644 src/bluez4/bluez4.pri create mode 100644 src/bluez4/bluezqt_dbustypes_bluez4_p.h create mode 100644 src/bluez4/device_bluez4.cpp create mode 100644 src/bluez4/device_bluez4_p.h create mode 100644 src/bluez4/macros_bluez4_p.h create mode 100644 src/bluez4/manager_bluez4.cpp create mode 100644 src/bluez4/manager_bluez4_p.h create mode 100644 src/bluez4/mediaplayer_bluez4.cpp create mode 100644 src/bluez4/mediaplayer_bluez4_p.h create mode 100644 src/bluez4/mediatransport_bluez4.cpp create mode 100644 src/bluez4/mediatransport_bluez4_p.h create mode 100644 src/bluez4/obexagentadaptor_bluez4.cpp create mode 100644 src/bluez4/obexagentadaptor_bluez4_p.h create mode 100644 src/bluez4/obexmanager_bluez4.cpp create mode 100644 src/bluez4/obexmanager_bluez4_p.h create mode 100644 src/bluez4/obexsession_bluez4.cpp create mode 100644 src/bluez4/obexsession_bluez4_p.h create mode 100644 src/bluez4/obextransfer_bluez4.cpp create mode 100644 src/bluez4/obextransfer_bluez4_p.h create mode 100644 src/bluez4/proxyagent.cpp create mode 100644 src/bluez4/proxyagent_p.h diff --git a/.gitignore b/.gitignore index 7d7c2e3..e5c852f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,22 @@ build apidocs CMakeLists.txt.user +*.o +*.so* +moc_* +Makefile +bluez*1* +obex*1* +libKF5BluezQt* +bluez*adapter.* +bluez*device.* +bluez*manager.* +bluez*mediaplayer.* +bluez*mediatransport.* +bluez*obexclient.* +bluez*obexfiletransfer.* +bluez*obexmanager.* +bluez*obexobjectpush.* +bluez*obextransfer.* +dbusobjectmanager.* +dbusproperties.* diff --git a/src/adapter.cpp b/src/adapter.cpp index 4b2f5fd..27da474 100644 --- a/src/adapter.cpp +++ b/src/adapter.cpp @@ -26,6 +26,10 @@ #include "device_p.h" #include "pendingcall.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/adapter_bluez4_p.h" +#endif + namespace BluezQt { @@ -47,7 +51,11 @@ AdapterPtr Adapter::toSharedPtr() const QString Adapter::ubi() const { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return d->m_bluezAdapter->path(); +#else + return d->m_bluez4->m_bluez4Adapter->path(); +#endif } QString Adapter::address() const @@ -57,23 +65,13 @@ 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 @@ -173,20 +171,35 @@ DevicePtr Adapter::deviceForAddress(const QString &address) const PendingCall *Adapter::startDiscovery() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezAdapter->StartDiscovery(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(d->m_bluez4->m_bluez4Adapter->StartDiscovery(), + PendingCall::ReturnVoid, this); +#endif } PendingCall *Adapter::stopDiscovery() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezAdapter->StopDiscovery(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(d->m_bluez4->m_bluez4Adapter->StopDiscovery(), + PendingCall::ReturnVoid, this); +#endif } PendingCall *Adapter::removeDevice(DevicePtr device) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezAdapter->RemoveDevice(QDBusObjectPath(device->ubi())), PendingCall::ReturnVoid, this); +#else + return new PendingCall(d->m_bluez4->m_bluez4Adapter->RemoveDevice(QDBusObjectPath(device->ubi())), + PendingCall::ReturnVoid, this); +#endif } } // namespace BluezQt diff --git a/src/adapter.h b/src/adapter.h index 0f9dc7d..a68551e 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -363,9 +363,9 @@ private: friend class AdapterPrivate; friend class ManagerPrivate; friend class InitAdaptersJobPrivate; -#if KF5BLUEZQT_BLUEZ_VERSION < 5 - friend class DevicePrivate; -#endif + + friend class ManagerBluez4; + friend class DeviceBluez4; }; } // namespace BluezQt diff --git a/src/adapter_p.cpp b/src/adapter_p.cpp index 2ef9718..e4280f3 100644 --- a/src/adapter_p.cpp +++ b/src/adapter_p.cpp @@ -26,7 +26,7 @@ #include "macros.h" #if KF5BLUEZQT_BLUEZ_VERSION < 5 -#include "agent.h" +#include "bluez4/adapter_bluez4_p.h" #endif namespace BluezQt @@ -36,8 +36,6 @@ AdapterPrivate::AdapterPrivate(const QString &path, const QVariantMap &propertie : QObject() #if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusProperties(nullptr) -#else - , m_pairingAgent(nullptr) #endif , m_adapterClass(0) , m_powered(0) @@ -46,9 +44,13 @@ AdapterPrivate::AdapterPrivate(const QString &path, const QVariantMap &propertie , m_pairable(false) , m_pairableTimeout(0) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_bluezAdapter = new BluezAdapter(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); init(properties); +#else + m_bluez4 = new AdapterBluez4(this, path, properties); +#endif } void AdapterPrivate::init(const QVariantMap &properties) @@ -64,9 +66,6 @@ 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 @@ -106,37 +105,21 @@ QDBusPendingReply<> AdapterPrivate::setDBusProperty(const QString &name, const Q #if KF5BLUEZQT_BLUEZ_VERSION >= 5 return m_dbusProperties->Set(Strings::orgBluezAdapter1(), name, QDBusVariant(value)); #else - return m_bluezAdapter->SetProperty(name, QDBusVariant(value)); + return m_bluez4->setDBusProperty(name, 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")) { @@ -171,41 +154,4 @@ 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 f0aa69d..10be3af 100644 --- a/src/adapter_p.h +++ b/src/adapter_p.h @@ -25,13 +25,14 @@ #include <QObject> #include <QStringList> +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include <QDBusPendingReply> +#endif #include "types.h" #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "bluezadapter1.h" #include "dbusproperties.h" -#else -#include "bluezadapter.h" #endif namespace BluezQt @@ -41,7 +42,7 @@ namespace BluezQt typedef org::bluez::Adapter1 BluezAdapter; typedef org::freedesktop::DBus::Properties DBusProperties; #else -class ProxyAgent; +class AdapterBluez4; #endif class AdapterPrivate : public QObject @@ -59,19 +60,10 @@ 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 + BluezAdapter *m_bluezAdapter; DBusProperties *m_dbusProperties; -#else - Agent *m_pairingAgent; #endif QString m_address; @@ -89,8 +81,7 @@ public: QString m_modalias; #if KF5BLUEZQT_BLUEZ_VERSION < 5 -Q_SIGNALS: - void agentCreated(Agent *agent); + AdapterBluez4 *m_bluez4; #endif }; diff --git a/src/agent.cpp b/src/agent.cpp index 324f070..42d3db4 100644 --- a/src/agent.cpp +++ b/src/agent.cpp @@ -22,10 +22,6 @@ #include "agent.h" -#if KF5BLUEZQT_BLUEZ_VERSION < 5 -#include <QDBusObjectPath> -#endif - namespace BluezQt { @@ -97,141 +93,4 @@ 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 737243d..5b0d832 100644 --- a/src/agent.h +++ b/src/agent.h @@ -206,41 +206,6 @@ 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 05d9533..47478e3 100644 --- a/src/agentadaptor.cpp +++ b/src/agentadaptor.cpp @@ -132,14 +132,6 @@ 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 7473a1e..2ce588d 100644 --- a/src/agentadaptor.h +++ b/src/agentadaptor.h @@ -39,11 +39,7 @@ 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); @@ -57,10 +53,6 @@ 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/bluez4/adapter_bluez4.cpp b/src/bluez4/adapter_bluez4.cpp new file mode 100644 index 0000000..710e7f8 --- /dev/null +++ b/src/bluez4/adapter_bluez4.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#include "adapter_bluez4_p.h" +#include "macros_bluez4_p.h" +#include "proxyagent_p.h" + +#include "adapter.h" +#include "adapter_p.h" +#include "utils.h" +#include "macros.h" + +namespace BluezQt +{ + +AdapterBluez4::AdapterBluez4(AdapterPrivate *adapterPrivate, const QString &path, const QVariantMap &properties) + : QObject(adapterPrivate) + , m_adapterPrivate(adapterPrivate) + , m_bluez4Adapter(0) + , m_pairingAgent(0) +{ + m_bluez4Adapter = new Bluez4Adapter(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); + connect(m_bluez4Adapter, &Bluez4Adapter::PropertyChanged, + this, &AdapterBluez4::adapterPropertyChanged); + + // In BlueZ 4 there is no "Alias" property, so set Adapter::alias() to return the "Name" value. + adapterPrivate->init(properties); + adapterPrivate->m_alias = properties.value(QStringLiteral("Name")).toString(); +} + +QDBusPendingReply<> AdapterBluez4::setDBusProperty(const QString &name, const QVariant &value) +{ + if (name == QStringLiteral("Alias")) { + return m_bluez4Adapter->SetProperty(QStringLiteral("Name"), QDBusVariant(value)); + } else { + return m_bluez4Adapter->SetProperty(name, QDBusVariant(value)); + } +} + +QDBusPendingReply<QDBusObjectPath> AdapterBluez4::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_bluez4Adapter->CreatePairedDevice(address, proxyAgent->objectPath(), + ProxyAgent::capabilityToString(proxyAgent->capability())); +} + +QDBusPendingReply<void> AdapterBluez4::cancelDeviceCreation(const QString &address) +{ + return m_bluez4Adapter->CancelDeviceCreation(address); +} + +ProxyAgent *AdapterBluez4::createProxyForAgent(Agent *agent, const QString &proxyAgentPath) +{ + Q_ASSERT(agent); + + ProxyAgent *proxyAgent = new ProxyAgent(agent, proxyAgentPath, m_adapterPrivate->q.data()); + emit agentCreated(proxyAgent); + + return proxyAgent; +} + +void AdapterBluez4::setPairingAgent(Agent *agent) +{ + m_pairingAgent = agent; +} + +void AdapterBluez4::adapterPropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezAdapter1(), m_adapterPrivate, property, value.variant()); + + // In BlueZ 4 there is no "Alias" property, so set Adapter::alias() to return the "Name" value. + if (property == QStringLiteral("Name")) { + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezAdapter1(), m_adapterPrivate, QStringLiteral("Alias"), value.variant()); + } +} + +} // namespace BluezQt diff --git a/src/bluez4/adapter_bluez4_p.h b/src/bluez4/adapter_bluez4_p.h new file mode 100644 index 0000000..d402ff0 --- /dev/null +++ b/src/bluez4/adapter_bluez4_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_ADAPTER_BLUEZ4_P_H +#define BLUEZQT_ADAPTER_BLUEZ4_P_H + +#include "types.h" +#include "bluez4adapter.h" + +namespace BluezQt +{ + +typedef org::bluez::Adapter Bluez4Adapter; + +class ProxyAgent; +class AdapterPrivate; + +class AdapterBluez4 : public QObject +{ + Q_OBJECT + +public: + explicit AdapterBluez4(AdapterPrivate *adapterPrivate, const QString &path, const QVariantMap &properties); + + QDBusPendingReply<> setDBusProperty(const QString &name, const QVariant &value); + + QDBusPendingReply<QDBusObjectPath> createPairedDevice(const QString &address); + QDBusPendingReply<void> cancelDeviceCreation(const QString &address); + + ProxyAgent *createProxyForAgent(Agent *agent, const QString &proxyAgentPath); + void setPairingAgent(Agent *agent); + + AdapterPrivate *m_adapterPrivate; + Bluez4Adapter *m_bluez4Adapter; + +Q_SIGNALS: + void agentCreated(Agent *agent); + +private: + void adapterPropertyChanged(const QString &property, const QDBusVariant &value); + + Agent *m_pairingAgent; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_ADAPTER_BLUEZ4_P_H diff --git a/src/bluez4/agentadaptor_bluez4.cpp b/src/bluez4/agentadaptor_bluez4.cpp new file mode 100644 index 0000000..cbcefa0 --- /dev/null +++ b/src/bluez4/agentadaptor_bluez4.cpp @@ -0,0 +1,152 @@ +/* + * BluezQt - Asynchronous Bluez wrapper library + * + * Copyright (C) 2014 David Rosca <nowrep@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "agentadaptor_bluez4_p.h" + +#include "agent.h" +#include "manager.h" +#include "adapter.h" +#include "device.h" +#include "request.h" + +#include <QDBusMessage> +#include <QDBusObjectPath> + +namespace BluezQt +{ + +AgentAdaptorBluez4::AgentAdaptorBluez4(Agent *parent, Manager *manager) + : QDBusAbstractAdaptor(parent) + , m_agent(parent) + , m_manager(manager) +{ +} + +QString AgentAdaptorBluez4::RequestPinCode(const QDBusObjectPath &device, const QDBusMessage &msg) +{ + msg.setDelayedReply(true); + Request<QString> req(OrgBluezAgent, msg); + + DevicePtr dev = m_manager->deviceForUbi(device.path()); + if (!dev) { + req.cancel(); + return QString(); + } + + m_agent->requestPinCode(dev, req); + return QString(); +} + +void AgentAdaptorBluez4::DisplayPinCode(const QDBusObjectPath &device, const QString &pincode) +{ + DevicePtr dev = m_manager->deviceForUbi(device.path()); + if (!dev) { + return; + } + + m_agent->displayPinCode(dev, pincode); +} + +quint32 AgentAdaptorBluez4::RequestPasskey(const QDBusObjectPath &device, const QDBusMessage &msg) +{ + msg.setDelayedReply(true); + Request<quint32> req(OrgBluezAgent, msg); + + DevicePtr dev = m_manager->deviceForUbi(device.path()); + if (!dev) { + req.cancel(); + return 0; + } + + m_agent->requestPasskey(dev, req); + return 0; +} + +void AgentAdaptorBluez4::DisplayPasskey(const QDBusObjectPath &device, quint32 passkey, quint16 entered) +{ + DevicePtr dev = m_manager->deviceForUbi(device.path()); + if (!dev) { + return; + } + + m_agent->displayPasskey(dev, passkeyToString(passkey), QString::number(entered)); +} + +void AgentAdaptorBluez4::RequestConfirmation(const QDBusObjectPath &device, quint32 passkey, const QDBusMessage &msg) +{ + msg.setDelayedReply(true); + Request<> req(OrgBluezAgent, msg); + + DevicePtr dev = m_manager->deviceForUbi(device.path()); + if (!dev) { + req.cancel(); + return; + } + + m_agent->requestConfirmation(dev, passkeyToString(passkey), req); +} + +void AgentAdaptorBluez4::RequestAuthorization(const QDBusObjectPath &device, const QDBusMessage &msg) +{ + msg.setDelayedReply(true); + Request<> req(OrgBluezAgent, msg); + + DevicePtr dev = m_manager->deviceForUbi(device.path()); + if (!dev) { + req.cancel(); + return; + } + + m_agent->requestAuthorization(dev, req); +} + +void AgentAdaptorBluez4::Authorize(const QDBusObjectPath &device, const QString &uuid, const QDBusMessage &msg) +{ + msg.setDelayedReply(true); + Request<> req(OrgBluezAgent, msg); + + DevicePtr dev = m_manager->deviceForUbi(device.path()); + if (!dev) { + req.cancel(); + return; + } + + m_agent->authorizeService(dev, uuid.toUpper(), req); +} + +void AgentAdaptorBluez4::Cancel() +{ + m_agent->cancel(); +} + +void AgentAdaptorBluez4::Release() +{ + m_agent->release(); +} + +QString AgentAdaptorBluez4::passkeyToString(quint32 passkey) const +{ + // Passkey will always be a 6-digit number, zero-pad it at the start + return QStringLiteral("%1").arg(passkey, 6, 10, QLatin1Char('0')); +} + +} // namespace BluezQt diff --git a/src/bluez4/agentadaptor_bluez4_p.h b/src/bluez4/agentadaptor_bluez4_p.h new file mode 100644 index 0000000..01e681f --- /dev/null +++ b/src/bluez4/agentadaptor_bluez4_p.h @@ -0,0 +1,74 @@ +/* + * BluezQt - Asynchronous Bluez wrapper library + * + * Copyright (C) 2014 David Rosca <nowrep@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BLUEZQT_AGENTADAPTOR_BLUEZ4_H +#define BLUEZQT_AGENTADAPTOR_BLUEZ4_H + +#include <QObject> +#include <QDBusAbstractAdaptor> + +class QDBusMessage; +class QDBusObjectPath; + +namespace BluezQt +{ + +class Device; +class Manager; +class Agent; + +// This is the same as agentadaptor.* but with: +// - the org.bluez.Agent D-Bus interface Q_CLASSINFO +// - Authorize() instead of AuthorizeService() + +class AgentAdaptorBluez4 : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent") + +public: + explicit AgentAdaptorBluez4(Agent *parent, Manager *manager); + +public Q_SLOTS: + QString RequestPinCode(const QDBusObjectPath &device, const QDBusMessage &msg); + Q_NOREPLY void DisplayPinCode(const QDBusObjectPath &device, const QString &pincode); + quint32 RequestPasskey(const QDBusObjectPath &device, const QDBusMessage &msg); + Q_NOREPLY void DisplayPasskey(const QDBusObjectPath &device, quint32 passkey, quint16 entered); + void RequestConfirmation(const QDBusObjectPath &device, quint32 passkey, const QDBusMessage &msg); + void RequestAuthorization(const QDBusObjectPath &device, const QDBusMessage &msg); + + // In BlueZ 4 it is Authorize() rather than AuthorizeService() + void Authorize(const QDBusObjectPath &device, const QString &uuid, const QDBusMessage &msg); + + Q_NOREPLY void Cancel(); + Q_NOREPLY void Release(); + +private: + QString passkeyToString(quint32 passkey) const; + + Agent *m_agent; + Manager *m_manager; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_AGENTADAPTOR_BLUEZ4_H diff --git a/src/bluez4/bluez4.pri b/src/bluez4/bluez4.pri new file mode 100644 index 0000000..dd25939 --- /dev/null +++ b/src/bluez4/bluez4.pri @@ -0,0 +1,27 @@ +HEADERS += \ + $$PWD/manager_bluez4_p.h \ + $$PWD/adapter_bluez4_p.h \ + $$PWD/device_bluez4_p.h \ + $$PWD/agentadaptor_bluez4_p.h \ + $$PWD/mediaplayer_bluez4_p.h \ + $$PWD/mediatransport_bluez4_p.h \ + $$PWD/obexmanager_bluez4_p.h \ + $$PWD/obexsession_bluez4_p.h \ + $$PWD/obextransfer_bluez4_p.h \ + $$PWD/obexagentadaptor_bluez4_p.h \ + $$PWD/proxyagent_p.h \ + $$PWD/macros_bluez4_p.h \ + $$PWD/bluezqt_dbustypes_bluez4_p.h + +SOURCES += \ + $$PWD/manager_bluez4.cpp \ + $$PWD/adapter_bluez4.cpp \ + $$PWD/device_bluez4.cpp \ + $$PWD/agentadaptor_bluez4.cpp \ + $$PWD/mediaplayer_bluez4.cpp \ + $$PWD/mediatransport_bluez4.cpp \ + $$PWD/obexmanager_bluez4.cpp \ + $$PWD/obexsession_bluez4.cpp \ + $$PWD/obextransfer_bluez4.cpp \ + $$PWD/obexagentadaptor_bluez4.cpp \ + $$PWD/proxyagent.cpp diff --git a/src/bluez4/bluezqt_dbustypes_bluez4_p.h b/src/bluez4/bluezqt_dbustypes_bluez4_p.h new file mode 100644 index 0000000..b2f7876 --- /dev/null +++ b/src/bluez4/bluezqt_dbustypes_bluez4_p.h @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_DBUSTYPES_BLUEZ4_H +#define BLUEZQT_DBUSTYPES_BLUEZ4_H + +#include <QVariantMap> +#include <QDBusObjectPath> + +typedef QMap<quint32, QString> DeviceServiceMap; +Q_DECLARE_METATYPE(DeviceServiceMap) + +typedef QPair<QDBusObjectPath, QVariantMap> ObexTransferInfo; +Q_DECLARE_METATYPE(ObexTransferInfo) + +#endif // BLUEZQT_DBUSTYPES_H diff --git a/src/bluez4/device_bluez4.cpp b/src/bluez4/device_bluez4.cpp new file mode 100644 index 0000000..70b57cf --- /dev/null +++ b/src/bluez4/device_bluez4.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#include "device_bluez4_p.h" +#include "adapter_bluez4_p.h" +#include "macros_bluez4_p.h" + +#include "device_p.h" +#include "adapter.h" +#include "adapter_p.h" +#include "utils.h" +#include "macros.h" + +namespace BluezQt +{ + +DeviceBluez4::DeviceBluez4(DevicePrivate *devicePrivate, const QString &path) + : QObject(devicePrivate) + , m_devicePrivate(devicePrivate) + , m_inputInterface(0) + , m_audioInterface(0) +{ + m_bluez4Device = new Bluez4Device(Strings::orgBluez(), path, + DBusConnection::orgBluez(), this); + connect(m_bluez4Device, &Bluez4Device::PropertyChanged, + this, &DeviceBluez4::devicePropertyChanged); +} + +QDBusInterface *DeviceBluez4::orgBluezInput() +{ + if (!m_inputInterface) { + m_inputInterface = new QDBusInterface(Strings::orgBluez(), m_devicePrivate->q.data()->ubi(), + QStringLiteral("org.bluez.Input"), DBusConnection::orgBluez(), this); + } + return m_inputInterface; +} + +QDBusInterface *DeviceBluez4::orgBluezAudio() +{ + if (!m_audioInterface) { + m_audioInterface = new QDBusInterface(Strings::orgBluez(), m_devicePrivate->q.data()->ubi(), + QStringLiteral("org.bluez.Audio"), DBusConnection::orgBluez(), this); + } + return m_audioInterface; +} + +QDBusPendingReply<QDBusObjectPath> DeviceBluez4::pair(AdapterPtr adapter) +{ + if (adapter.isNull() || !adapter->d->m_bluez4) { + return QDBusMessage::createError(QDBusError::InvalidArgs, "Invalid adapter"); + } + + return adapter->d->m_bluez4->createPairedDevice(m_devicePrivate->m_address); +} + +QDBusPendingReply<void> DeviceBluez4::cancelPairing(AdapterPtr adapter) +{ + if (adapter.isNull() || !adapter->d->m_bluez4) { + return QDBusMessage::createError(QDBusError::InvalidArgs, "Invalid adapter"); + } + + return adapter->d->m_bluez4->cancelDeviceCreation(m_devicePrivate->m_address); +} + +void DeviceBluez4::devicePropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezDevice1(), m_devicePrivate, property, value.variant()); +} + +} // namespace BluezQt diff --git a/src/bluez4/device_bluez4_p.h b/src/bluez4/device_bluez4_p.h new file mode 100644 index 0000000..8f70599 --- /dev/null +++ b/src/bluez4/device_bluez4_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_DEVICE_BLUEZ4_P_H +#define BLUEZQT_DEVICE_BLUEZ4_P_H + +#include "types.h" +#include "bluez4device.h" + +namespace BluezQt +{ + +typedef org::bluez::Device Bluez4Device; + +class DevicePrivate; +class AdapterPrivate; + +class DeviceBluez4 : public QObject +{ + Q_OBJECT + +public: + explicit DeviceBluez4(DevicePrivate *devicePrivate, const QString &path); + + QDBusInterface *orgBluezInput(); + QDBusInterface *orgBluezAudio(); + + QDBusPendingReply<QDBusObjectPath> pair(AdapterPtr adapter); + QDBusPendingReply<void> cancelPairing(AdapterPtr adapter); + + DevicePrivate *m_devicePrivate; + Bluez4Device *m_bluez4Device; + +private: + void devicePropertyChanged(const QString &property, const QDBusVariant &value); + + QDBusInterface *m_inputInterface; + QDBusInterface *m_audioInterface; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_DEVICE_BLUEZ4_P_H diff --git a/src/bluez4/macros_bluez4_p.h b/src/bluez4/macros_bluez4_p.h new file mode 100644 index 0000000..cb1808c --- /dev/null +++ b/src/bluez4/macros_bluez4_p.h @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_MACROS_BLUEZ4_H +#define BLUEZQT_MACROS_BLUEZ4_H + +// 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/bluez4/manager_bluez4.cpp b/src/bluez4/manager_bluez4.cpp new file mode 100644 index 0000000..7b7938c --- /dev/null +++ b/src/bluez4/manager_bluez4.cpp @@ -0,0 +1,397 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#include "manager_bluez4_p.h" +#include "adapter_bluez4_p.h" +#include "agentadaptor_bluez4_p.h" +#include "proxyagent_p.h" + +#include "manager.h" +#include "manager_p.h" +#include "device_p.h" +#include "adapter.h" +#include "adapter_p.h" +#include "utils.h" +#include "debug.h" + +namespace BluezQt +{ + +ManagerBluez4::ManagerBluez4(ManagerPrivate *parent) + : QObject(parent) + , m_managerPrivate(parent) + , m_bluez4Manager(0) + , m_loaded(false) +{ + m_bluez4Manager = new Bluez4Manager(Strings::orgBluez(), QStringLiteral("/"), DBusConnection::orgBluez(), this); +} + +void ManagerBluez4::load() +{ + if (m_loaded) { + return; + } + + connect(m_bluez4Manager, &Bluez4Manager::DefaultAdapterChanged, + this, &ManagerBluez4::managerDefaultAdapterChanged); + connect(m_bluez4Manager, &Bluez4Manager::AdapterAdded, + this, &ManagerBluez4::managerAdapterAdded); + connect(m_bluez4Manager, &Bluez4Manager::AdapterRemoved, + this, &ManagerBluez4::managerAdapterRemoved); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(m_bluez4Manager->DefaultAdapter(), this); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerBluez4::managerDefaultAdapterFinished); +} + +void ManagerBluez4::addAdapter(AdapterPrivate *adapterPrivate) +{ + if (adapterPrivate->m_bluez4) { + connect(adapterPrivate->m_bluez4->m_bluez4Adapter, &Bluez4Adapter::DeviceFound, + this, &ManagerBluez4::deviceFound); + connect(adapterPrivate->m_bluez4->m_bluez4Adapter, &Bluez4Adapter::DeviceCreated, + this, &ManagerBluez4::addDeviceByPath); + connect(adapterPrivate->m_bluez4->m_bluez4Adapter, &Bluez4Adapter::DeviceRemoved, + this, &ManagerBluez4::deviceRemoved); + connect(adapterPrivate->m_bluez4->m_bluez4Adapter, &Bluez4Adapter::PropertyChanged, + this, &ManagerBluez4::adapterPropertyChanged); + connect(adapterPrivate->m_bluez4, &AdapterBluez4::agentCreated, + this, &ManagerBluez4::agentCreated); + } +} + +void ManagerBluez4::adapterRemoved(const AdapterPrivate *adapterPrivate) +{ + m_defaultAgents.remove(adapterPrivate->q.data()->ubi()); +} + +QDBusPendingReply<void> ManagerBluez4::requestDefaultAgent(AdapterPtr adapter, Agent *agent) +{ + if (adapter.isNull() || !adapter->d->m_bluez4 || !agent) { + return QDBusMessage::createError(QDBusError::InvalidArgs, "Invalid adapter or 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->m_bluez4->createProxyForAgent(agent, "/bluez4_system_agent_proxy"); + QDBusPendingReply<void> reply = adapter->d->m_bluez4->m_bluez4Adapter->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, &ManagerBluez4::requestDefaultAgentFinished); + + return reply; +} + +void ManagerBluez4::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 = m_managerPrivate->q->adapterForAddress(adapterAddress); + if (adapter && adapter->d->m_bluez4) { + m_defaultAgents.insert(adapter->ubi(), proxyAgent); + + // Set the adapter to reuse the proxied agent when initiating pairings. + adapter->d->m_bluez4->setPairingAgent(proxyAgent->agent()); + } +} + +QDBusPendingReply<void> ManagerBluez4::unregisterDefaultAgent(AdapterPtr adapter) +{ + if (adapter.isNull() || !adapter->d->m_bluez4) { + return QDBusMessage::createError(QDBusError::InvalidArgs, "Invalid 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_bluez4->m_bluez4Adapter->UnregisterAgent(proxyAgent->objectPath()); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + watcher->setProperty("adapterPath", adapter->ubi()); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerBluez4::unregisterAgentFinished); + + return reply; +} + +void ManagerBluez4::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 ManagerBluez4::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 m_managerPrivate->q->adapterForUbi(adapterPath); + } + } + + return AdapterPtr(); +} + +QDBusPendingReply<QDBusObjectPath> ManagerBluez4::createPairedDevice(AdapterPtr adapter, const QString &address) +{ + if (adapter.isNull() || !adapter->d->m_bluez4) { + return QDBusMessage::createError(QDBusError::InvalidArgs, "Invalid adapter"); + } + + return adapter->d->m_bluez4->createPairedDevice(address); +} + +void ManagerBluez4::emitLoaded(bool success, const QString &errorMessage) +{ + if (!m_loaded) { + m_loaded = true; + Q_EMIT loaded(success, errorMessage); + } +} + +void ManagerBluez4::managerDefaultAdapterFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<QDBusObjectPath> &reply = *watcher; + watcher->deleteLater(); + + if (reply.isError()) { + if (reply.error().name() == QStringLiteral("org.bluez.Error.NoSuchAdapter")) { + // It's OK if the default adapter is not yet available when the manager is loaded. + emitLoaded(true, QString()); + } else { + emitLoaded(false, reply.error().message()); + } + return; + } + + const QDBusObjectPath &objectPath = reply.value(); + managerAdapterAdded(objectPath); +} + +void ManagerBluez4::managerDefaultAdapterChanged(const QDBusObjectPath &objectPath) +{ + QDBusInterface *bluez4Adapter = new QDBusInterface(Strings::orgBluez(), objectPath.path(), + QStringLiteral("org.bluez.Adapter"), DBusConnection::orgBluez(), this); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(bluez4Adapter->asyncCall(QStringLiteral("GetProperties")), this); + watcher->setProperty("bluez4Adapter", QVariant::fromValue(bluez4Adapter)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerBluez4::adapterGetPropertiesFinished); +} + +void ManagerBluez4::managerAdapterAdded(const QDBusObjectPath &objectPath) +{ + QDBusInterface *bluez4Adapter = new QDBusInterface(Strings::orgBluez(), objectPath.path(), + QStringLiteral("org.bluez.Adapter"), DBusConnection::orgBluez(), this); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(bluez4Adapter->asyncCall(QStringLiteral("GetProperties")), this); + watcher->setProperty("bluez4Adapter", QVariant::fromValue(bluez4Adapter)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerBluez4::adapterGetPropertiesFinished); +} + +void ManagerBluez4::managerAdapterRemoved(const QDBusObjectPath &objectPath) +{ + m_managerPrivate->removeAdapter(objectPath.path()); +} + +void ManagerBluez4::adapterGetPropertiesFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<QVariantMap> &reply = *watcher; + const QVariantMap &properties = reply.value(); + watcher->deleteLater(); + + QDBusInterface *bluez4Adapter = watcher->property("bluez4Adapter").value<QDBusInterface *>(); + bluez4Adapter->deleteLater(); + + if (reply.isError()) { + if (m_pendingInitializationWatchers.isEmpty()) { + emitLoaded(false, reply.error().message()); + } + return; + } + + m_managerPrivate->addAdapter(bluez4Adapter->path(), properties); + + QVariant deviceList = properties.value(QStringLiteral("Devices")); + if (deviceList.isValid()) { + updateDeviceList(bluez4Adapter->path(), deviceList); + } + + if (m_pendingInitializationWatchers.isEmpty()) { + emitLoaded(true); + } +} + +void ManagerBluez4::adapterPropertyChanged(const QString &property, const QDBusVariant &value) +{ + Bluez4Adapter *adapter = qobject_cast<Bluez4Adapter *>(sender()); + + if (adapter && property == QStringLiteral("Devices")) { + updateDeviceList(adapter->path(), value.variant()); + } +} + +void ManagerBluez4::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_managerPrivate->m_devices.constBegin(); it != m_managerPrivate->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_managerPrivate->m_devices.contains(devicePath)) { + QDBusPendingCallWatcher *watcher = addDeviceByPath(QDBusObjectPath(devicePath)); + if (!m_loaded && watcher) { + m_pendingInitializationWatchers.insert(watcher); + } + } + } + + Q_FOREACH (const QString &devicePath, pathsToRemove) { + m_managerPrivate->removeDevice(devicePath); + } +} + +QDBusPendingCallWatcher *ManagerBluez4::addDeviceByPath(const QDBusObjectPath &objectPath) +{ + if (!m_managerPrivate->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, &ManagerBluez4::deviceGetPropertiesFinished); + return watcher; + } + return 0; +} + +void ManagerBluez4::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_managerPrivate->m_devices.value(bluezDevice->path()); + if (device.isNull()) { + m_managerPrivate->addDevice(bluezDevice->path(), reply.value()); + } else { + device->d->propertiesChanged(Strings::orgBluezDevice1(), reply.value(), QStringList()); + } + } + + if (m_pendingInitializationWatchers.isEmpty()) { + emitLoaded(true); + } +} + +void ManagerBluez4::deviceFound(const QString &address, const QVariantMap &values) +{ + Bluez4Adapter *bluez4Adapter = qobject_cast<Bluez4Adapter *>(sender()); + if (!bluez4Adapter) { + return; + } + + QHash<QString, DevicePtr>::iterator it; + + for (it = m_managerPrivate->m_devices.begin(); it != m_managerPrivate->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(bluez4Adapter->path()).arg(addressCopy.replace(':', '_')); + QVariantMap properties = values; + properties.insert(QStringLiteral("Adapter"), QVariant::fromValue(QDBusObjectPath(bluez4Adapter->path()))); + + m_managerPrivate->addDevice(devicePath, properties); +} + +void ManagerBluez4::deviceRemoved(const QDBusObjectPath &objectPath) +{ + m_managerPrivate->removeDevice(objectPath.path()); +} + +void ManagerBluez4::agentCreated(Agent *agent) +{ + // Initialize the agent as per Manager::registerAgent() + + new AgentAdaptorBluez4(agent, m_managerPrivate->q); + + if (!DBusConnection::orgBluez().registerObject(agent->objectPath().path(), agent)) { + qCWarning(BLUEZQT) << "Cannot register object" << agent->objectPath().path(); + } +} + +} // namespace BluezQt diff --git a/src/bluez4/manager_bluez4_p.h b/src/bluez4/manager_bluez4_p.h new file mode 100644 index 0000000..89d5358 --- /dev/null +++ b/src/bluez4/manager_bluez4_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_MANAGER_BLUEZ4_P_H +#define BLUEZQT_MANAGER_BLUEZ4_P_H + +#include <QSet> + +#include "types.h" +#include "bluez4manager.h" + +namespace BluezQt +{ + +typedef org::bluez::Manager Bluez4Manager; + +class ManagerPrivate; +class AdapterPrivate; +class ProxyAgent; +class Agent; + +class ManagerBluez4 : public QObject +{ + Q_OBJECT + +public: + explicit ManagerBluez4(ManagerPrivate *parent); + + void load(); + + void addAdapter(AdapterPrivate *adapterPrivate); + void adapterRemoved(const AdapterPrivate *adapterPrivate); + + QDBusPendingReply<void> requestDefaultAgent(AdapterPtr adapter, Agent *agent); + QDBusPendingReply<void> unregisterDefaultAgent(AdapterPtr adapter); + AdapterPtr findAdapterForDefaultAgent(Agent *agent); + + QDBusPendingReply<QDBusObjectPath> createPairedDevice(AdapterPtr adapter, const QString &address); + + ManagerPrivate *m_managerPrivate; + Bluez4Manager *m_bluez4Manager; + +signals: + void loaded(bool success, const QString &errorMessage); + +private: + void emitLoaded(bool success, const QString &errorMessage = QString()); + void managerDefaultAdapterFinished(QDBusPendingCallWatcher *watcher); + void managerDefaultAdapterChanged(const QDBusObjectPath &objectPath); + 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); + + void requestDefaultAgentFinished(QDBusPendingCallWatcher *watcher); + void unregisterAgentFinished(QDBusPendingCallWatcher *watcher); + void agentCreated(Agent *agent); + + bool m_loaded; + QSet<QDBusPendingCallWatcher *> m_pendingInitializationWatchers; + QHash<QString, ProxyAgent *> m_defaultAgents; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_MANAGER_BLUEZ4_P_H diff --git a/src/bluez4/mediaplayer_bluez4.cpp b/src/bluez4/mediaplayer_bluez4.cpp new file mode 100644 index 0000000..2cfe940 --- /dev/null +++ b/src/bluez4/mediaplayer_bluez4.cpp @@ -0,0 +1,47 @@ +/* + * BluezQt - Asynchronous Bluez wrapper library + * + * Copyright (C) 2015 David Rosca <nowrep@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "mediaplayer_bluez4_p.h" +#include "macros_bluez4_p.h" + +#include "mediaplayer_p.h" +#include "utils.h" + +namespace BluezQt +{ + +MediaPlayerBluez4::MediaPlayerBluez4(MediaPlayerPrivate *mediaPlayerPrivate, const QString &path) + : QObject(mediaPlayerPrivate) + , m_mediaPlayerPrivate(mediaPlayerPrivate) +{ + m_bluez4MediaPlayer = new Bluez4MediaPlayer(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); + + connect(m_bluez4MediaPlayer, &Bluez4MediaPlayer::PropertyChanged, + this, &MediaPlayerBluez4::mediaPlayerPropertyChanged); +} + +void MediaPlayerBluez4::mediaPlayerPropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezMediaPlayer1(), m_mediaPlayerPrivate, property, value.variant()); +} + +} // namespace BluezQt diff --git a/src/bluez4/mediaplayer_bluez4_p.h b/src/bluez4/mediaplayer_bluez4_p.h new file mode 100644 index 0000000..bb41762 --- /dev/null +++ b/src/bluez4/mediaplayer_bluez4_p.h @@ -0,0 +1,52 @@ +/* + * BluezQt - Asynchronous Bluez wrapper library + * + * Copyright (C) 2015 David Rosca <nowrep@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BLUEZQT_MEDIAPLAYER_BLUEZ4_P_H +#define BLUEZQT_MEDIAPLAYER_BLUEZ4_P_H + +#include <QObject> + +#include "bluez4mediaplayer.h" + +namespace BluezQt +{ + +typedef org::bluez::MediaPlayer Bluez4MediaPlayer; + +class MediaPlayerPrivate; + +class MediaPlayerBluez4 : public QObject +{ + Q_OBJECT + +public: + explicit MediaPlayerBluez4(MediaPlayerPrivate *mediaPlayerPrivate, const QString &path); + + void mediaPlayerPropertyChanged(const QString &property, const QDBusVariant &value); + + MediaPlayerPrivate *m_mediaPlayerPrivate; + Bluez4MediaPlayer *m_bluez4MediaPlayer; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_MEDIAPLAYER_BLUEZ4_P_H diff --git a/src/bluez4/mediatransport_bluez4.cpp b/src/bluez4/mediatransport_bluez4.cpp new file mode 100644 index 0000000..8a0670f --- /dev/null +++ b/src/bluez4/mediatransport_bluez4.cpp @@ -0,0 +1,47 @@ +/* + * BluezQt - Asynchronous Bluez wrapper library + * + * Copyright (C) 2015 David Rosca <nowrep@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "mediatransport_bluez4_p.h" +#include "macros_bluez4_p.h" + +#include "utils.h" +#include "mediatransport_p.h" + +namespace BluezQt +{ + +MediaTransportBluez4::MediaTransportBluez4(MediaTransportPrivate *mediaTransportPrivate, const QString &path) + : QObject(mediaTransportPrivate) + , m_mediaTransportPrivate(mediaTransportPrivate) +{ + m_bluez4MediaTransport = new Bluez4MediaTransport(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); + + connect(m_bluez4MediaTransport, &Bluez4MediaTransport::PropertyChanged, + this, &MediaTransportBluez4::mediaTransportPropertyChanged); +} + +void MediaTransportBluez4::mediaTransportPropertyChanged(const QString &property, const QDBusVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezMediaTransport1(), m_mediaTransportPrivate, property, value.variant()); +} + +} // namespace BluezQt diff --git a/src/bluez4/mediatransport_bluez4_p.h b/src/bluez4/mediatransport_bluez4_p.h new file mode 100644 index 0000000..36aa33d --- /dev/null +++ b/src/bluez4/mediatransport_bluez4_p.h @@ -0,0 +1,52 @@ +/* + * BluezQt - Asynchronous Bluez wrapper library + * + * Copyright (C) 2015 David Rosca <nowrep@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BLUEZQT_MEDIATRANSPORT_BLUEZ4_P_H +#define BLUEZQT_MEDIATRANSPORT_BLUEZ4_P_H + +#include <QObject> + +#include "bluez4mediatransport.h" + +namespace BluezQt +{ + +typedef org::bluez::MediaTransport Bluez4MediaTransport; + +class MediaTransportPrivate; + +class MediaTransportBluez4 : public QObject +{ + Q_OBJECT + +public: + explicit MediaTransportBluez4(MediaTransportPrivate *mediaTransportPrivate, const QString &path); + + void mediaTransportPropertyChanged(const QString &property, const QDBusVariant &value); + + MediaTransportPrivate *m_mediaTransportPrivate; + Bluez4MediaTransport *m_bluez4MediaTransport; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_MEDIATRANSPORT_BLUEZ4_P_H diff --git a/src/bluez4/obexagentadaptor_bluez4.cpp b/src/bluez4/obexagentadaptor_bluez4.cpp new file mode 100644 index 0000000..135d2ac --- /dev/null +++ b/src/bluez4/obexagentadaptor_bluez4.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#include "obexagentadaptor_bluez4_p.h" +#include "obexmanager_bluez4_p.h" + +#include "obexmanager.h" +#include "obextransfer.h" +#include "obexagent.h" +#include "utils.h" + +#include <QDBusObjectPath> +#include <QDBusMessage> + +namespace BluezQt +{ + +ObexAgentAdaptorBluez4::ObexAgentAdaptorBluez4(ObexAgent *parent, ObexManagerBluez4 *manager) + : QDBusAbstractAdaptor(parent) + , m_agent(parent) + , m_manager(manager) +{ +} + +QString ObexAgentAdaptorBluez4::Authorize(const QDBusObjectPath &transfer, const QString &bt_address, + const QString &name, const QString &type, qint32 length, + qint32 time, const QDBusMessage &msg) +{ + // Set up the request as per ObexAgentAdaptor::AuthorizePush(). + msg.setDelayedReply(true); + m_transferRequest = Request<QString>(OrgBluezObexAgent, msg); + m_transferPath = transfer.path(); + + 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); + + QMetaObject::invokeMethod(this, "authorizeTransfer", Qt::QueuedConnection, + Q_ARG(QString, transfer.path()), + Q_ARG(QVariantMap, properties), + Q_ARG(QString, bt_address)); + + return QString(); +} + +void ObexAgentAdaptorBluez4::Cancel() +{ + m_agent->cancel(); +} + +void ObexAgentAdaptorBluez4::Release() +{ + m_agent->release(); +} + +void ObexAgentAdaptorBluez4::authorizeTransfer(const QString &transferPath, const QVariantMap &transferProperties, const QString &destinationAddress) +{ + // For BlueZ 4 there is only FTP session support, so manually add per-transfer OPP sessions. + ObexTransferPtr transfer = m_manager->newObjectPushTransfer(QDBusObjectPath(transferPath), transferProperties, destinationAddress); + + // Now pass the transfer to the agent, as per ObexAgentAdaptor::getPropertiesFinished(). + ObexSessionPtr session = m_manager->sessionForObjectPushTransfer(transfer->objectPath()); + Q_ASSERT(session); + + if (!session) { + m_transferRequest.cancel(); + return; + } + + m_agent->authorizePush(transfer, session, m_transferRequest); +} + +} // namespace BluezQt diff --git a/src/bluez4/obexagentadaptor_bluez4_p.h b/src/bluez4/obexagentadaptor_bluez4_p.h new file mode 100644 index 0000000..03595ff --- /dev/null +++ b/src/bluez4/obexagentadaptor_bluez4_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_OBEXAGENTADAPTOR_BLUEZ4_H +#define BLUEZQT_OBEXAGENTADAPTOR_BLUEZ4_H + +#include <QDBusAbstractAdaptor> + +#include "types.h" +#include "request.h" + +class QDBusObjectPath; + +namespace BluezQt +{ + +class ObexAgent; +class ObexManagerBluez4; + +class ObexAgentAdaptorBluez4 : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.bluez.obex.Agent") + +public: + explicit ObexAgentAdaptorBluez4(ObexAgent *parent, ObexManagerBluez4 *manager); + +public Q_SLOTS: + QString Authorize(const QDBusObjectPath &transfer, const QString &bt_address, + const QString &name, const QString &type, qint32 length, + qint32 time, const QDBusMessage &msg); + + Q_NOREPLY void Cancel(); + Q_NOREPLY void Release(); + +private Q_SLOTS: + void authorizeTransfer(const QString &transferPath, + const QVariantMap &transferProperties, + const QString &destinationAddress); + +private: + ObexAgent *m_agent; + ObexManagerBluez4 *m_manager; + QString m_transferPath; + Request<QString> m_transferRequest; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_OBEXAGENTADAPTOR_BLUEZ4_H diff --git a/src/bluez4/obexmanager_bluez4.cpp b/src/bluez4/obexmanager_bluez4.cpp new file mode 100644 index 0000000..c1784e8 --- /dev/null +++ b/src/bluez4/obexmanager_bluez4.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#include "obexmanager_bluez4_p.h" +#include "obextransfer_bluez4_p.h" +#include "obexsession_bluez4_p.h" + +#include "obexmanager_p.h" +#include "obexmanager.h" +#include "obexsession.h" +#include "obexsession_p.h" +#include "debug.h" +#include "utils.h" + +#include "obextransfer_p.h" +#include "pendingcall.h" +#include "bluezqt_dbustypes.h" + +#include <QDBusMessage> + +namespace BluezQt +{ + +ObexManagerNotifier::ObexManagerNotifier(ObexManagerBluez4 *parent) + : QDBusAbstractAdaptor(parent) + , m_managerBluez4(parent) +{ + qDBusRegisterMetaType<QVariantMapList>(); +} + +void ObexManagerNotifier::notifyTransferAborted(const QString &transferPath) +{ + if (!transferPath.isEmpty()) { + QDBusMessage call = QDBusMessage::createMethodCall(service(), objectPath(), interface(), QStringLiteral("setTransferAborted")); + call << transferPath; + + if (!ObexManagerNotifier::connection().send(call)) { + qCWarning(BLUEZQT) << "Request: Failed to notify manager of aborted transfer"; + } + } +} + +QVariantMapList ObexManagerNotifier::getSessions() +{ + return m_managerBluez4->sessionProperties(); +} + +QVariantMapList ObexManagerNotifier::getTransfers() +{ + return m_managerBluez4->transferProperties(); +} + +void ObexManagerNotifier::setTransferAborted(const QString &transferPath) +{ + m_managerBluez4->setTransferAborted(transferPath); +} + + +ObexManagerBluez4::ObexManagerBluez4(ObexManagerPrivate *obexManagerPrivate) + : QObject(obexManagerPrivate) + , m_obexManagerPrivate(obexManagerPrivate) + , m_managerNotifier(0) + , m_initializedSessions(false) + , m_initializedTransfers(false) +{ + m_bluez4ObexClient = new Bluez4ObexClient(QStringLiteral("org.bluez.obex.client"), "/", DBusConnection::orgBluezObex(), this); + m_bluez4ObexManager = new Bluez4ObexManager(Strings::orgBluezObex(), "/", DBusConnection::orgBluezObex(), this); + + qDBusRegisterMetaType<QVariantMapList>(); +} + +void ObexManagerBluez4::load() +{ + connect(m_bluez4ObexManager, &Bluez4ObexManager::TransferStarted, + this, &ObexManagerBluez4::transferStarted); + connect(m_bluez4ObexManager, &Bluez4ObexManager::TransferCompleted, + this, &ObexManagerBluez4::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), this); + connect(getSessionsWatcher, &QDBusPendingCallWatcher::finished, this, &ObexManagerBluez4::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), this); + connect(getTransfersWatcher, &QDBusPendingCallWatcher::finished, this, &ObexManagerBluez4::getTransfersFinished); +} + +void ObexManagerBluez4::getSessionsFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<QVariantMapList> &reply = *watcher; + watcher->deleteLater(); + + m_initializedSessions = true; + + if (!reply.isError()) { + QVariantMapList::const_iterator it; + const QVariantMapList &sessions = reply.value(); + + for (it = sessions.constBegin(); it != sessions.constEnd(); ++it) { + QVariantMap properties = *it; + const QString &path = properties.value(obexSessionPathKey()).toString(); + + m_obexManagerPrivate->addSession(path, properties); + } + } else if (reply.error().name() != QStringLiteral("org.freedesktop.DBus.Error.ServiceUnknown")) { + // ServiceUnknown 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) { + completeLoading(); + } +} + +void ObexManagerBluez4::getTransfersFinished(QDBusPendingCallWatcher *watcher) +{ + const QDBusPendingReply<QVariantMapList> &reply = *watcher; + watcher->deleteLater(); + + m_initializedTransfers = true; + + if (!reply.isError()) { + QVariantMapList::const_iterator it; + const QVariantMapList &transfers = reply.value(); + + for (it = transfers.constBegin(); it != transfers.constEnd(); ++it) { + QVariantMap properties = *it; + const QString &path = properties.value(obexTransferPathKey()).toString(); + + 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")) { + // ServiceUnknown 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) { + completeLoading(); + } +} + +void ObexManagerBluez4::completeLoading() +{ + 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"; + } + + Q_EMIT loaded(); +} + +QDBusPendingReply<void> ObexManagerBluez4::registerAgent(const QDBusObjectPath &agentPath) +{ + if (!m_managerNotifier) { + m_managerNotifier = new ObexManagerNotifier(this); + + // The first agent registered (assumed to be the system agent) will share the known + // sessions and transfers with other agents. + if (ObexManagerNotifier::connection().registerObject(ObexManagerNotifier::objectPath(), this) + && ObexManagerNotifier::connection().registerService(ObexManagerNotifier::service())) { + qCDebug(BLUEZQT) << "Registered system OBEX manager notifier for" << agentPath.path(); + } else { + qCWarning(BLUEZQT) << "Error registering system OBEX manager notifier for" << agentPath.path(); + } + } + + return m_bluez4ObexManager->RegisterAgent(agentPath); +} + +QDBusPendingReply<void> ObexManagerBluez4::unregisterAgent(const QDBusObjectPath &agentPath) +{ + return m_bluez4ObexManager->UnregisterAgent(agentPath); +} + +PendingCall *ObexManagerBluez4::createSession(const QString &destination, const QVariantMap &args) +{ + // Manually add/remove sessions as DBusObjectManager is not available in BlueZ 4 to detect when + // they are created/removed. + PendingCall *call = new PendingCall(m_bluez4ObexClient->CreateSession(destination, args), + PendingCall::ReturnObjectPath, this); + call->setProperty("destination", destination); + call->setProperty("args", args); + connect(call, &PendingCall::finished, this, &ObexManagerBluez4::createSessionFinished); + + return call; +} + +PendingCall *ObexManagerBluez4::removeSession(const QDBusObjectPath &session) +{ + // Manually add/remove sessions as DBusObjectManager is not available in BlueZ 4 to detect when + // they are created/removed. + PendingCall *call = new PendingCall(m_bluez4ObexClient->RemoveSession(session), + PendingCall::ReturnVoid, this); + call->setProperty("session", session.path()); + connect(call, &PendingCall::finished, this, &ObexManagerBluez4::removeSessionFinished); + + return call; +} + +void ObexManagerBluez4::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; + } + + m_obexManagerPrivate->addSession(destination, args); +} + +void ObexManagerBluez4::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; + } + + m_obexManagerPrivate->removeSession(session); +} + +ObexTransferPtr ObexManagerBluez4::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(ObexSessionBluez4::objectPushTransferPathKey(), transferPath.path()); + + QString sessionPath = QStringLiteral("/org/bluez/obex/server/session") + QString::number(m_obexManagerPrivate->m_sessions.count()); + m_obexManagerPrivate->addSession(sessionPath, sessionProperties); + + notifyObexManagers(QStringLiteral("objectPushTransferCreated"), + QVariantList() << transferPath.path() << transferProperties + << sessionPath << sessionProperties); + return transfer; +} + +void ObexManagerBluez4::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_obexManagerPrivate->m_sessions.contains(sessionPath)) { + m_obexManagerPrivate->addSession(sessionPath, sessionProperties); + } +} + +void ObexManagerBluez4::objectPushTransferFinished(const QString &transferPath, const QString &sessionPath, bool success) +{ + Q_UNUSED(sessionPath); + + transferCompleted(QDBusObjectPath(transferPath), success); +} + +void ObexManagerBluez4::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_obexManagerPrivate->m_sessions) { + if (session->d->m_bluez4.m_oppTransferPath == transferPath) { + notifyObexManagers(QStringLiteral("objectPushTransferFinished"), + QVariantList() << transferPath << session->objectPath().path() << false); + break; + } + } +} + +QVariantMapList ObexManagerBluez4::sessionProperties() const +{ + QVariantMapList result; + + Q_FOREACH (ObexSessionPtr session, m_obexManagerPrivate->m_sessions) { + QVariantMap properties = session->d->m_bluez4.m_properties; + properties.insert(obexSessionPathKey(), session->objectPath().path()); + result.append(properties); + } + + return result; +} + +QVariantMapList ObexManagerBluez4::transferProperties() const +{ + QVariantMapList result; + 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(); + + QVariantMap properties = transfer->d->m_bluez4->m_properties; + properties.insert(obexTransferPathKey(), path); + result.append(properties); + } + + return result; +} + +ObexSessionPtr ObexManagerBluez4::sessionForObjectPushTransfer(const QDBusObjectPath &transferPath) +{ + Q_FOREACH (ObexSessionPtr session, m_obexManagerPrivate->m_sessions) { + if (session->d->m_bluez4.m_oppTransferPath == transferPath.path()) { + return session; + } + } + return ObexSessionPtr(); +} + +void ObexManagerBluez4::transferStarted(const QDBusObjectPath &objectPath) +{ + ObexTransferPtr transfer = m_oppTransfers.value(objectPath.path()); + if (!transfer.isNull()) { + transfer->d->m_bluez4->setTransferProperty(QStringLiteral("Status"), QStringLiteral("active")); + } +} + +void ObexManagerBluez4::transferCompleted(const QDBusObjectPath &objectPath, bool success) +{ + ObexTransferPtr transfer = m_oppTransfers.value(objectPath.path()); + + if (!transfer.isNull()) { + transfer->d->m_bluez4->setTransferProperty(QStringLiteral("Status"), + success ? QStringLiteral("complete") : QStringLiteral("error")); + m_oppTransfers.remove(objectPath.path()); + } + + ObexSessionPtr session = sessionForObjectPushTransfer(objectPath); + if (session) { + removeSession(session->objectPath()); + } +} + +void ObexManagerBluez4::notifyObexManagers(const QString &signalName, const QVariantList &args) +{ + QDBusMessage message = QDBusMessage::createSignal(ObexManagerNotifier::objectPath(), ObexManagerNotifier::interface(), signalName); + message.setArguments(args); + + if (!ObexManagerNotifier::connection().send(message)) { + qCWarning(BLUEZQT) << "Failed to notify OBEX managers of signal" << signalName + << "with args" << args; + } +} + +QString ObexManagerBluez4::obexSessionPathKey() +{ + return QStringLiteral("org.kde.bluezqt.ObexSession.Path"); +} + +QString ObexManagerBluez4::obexTransferPathKey() +{ + return QStringLiteral("org.kde.bluezqt.ObexTransfer.Path"); +} + +} // namespace BluezQt diff --git a/src/bluez4/obexmanager_bluez4_p.h b/src/bluez4/obexmanager_bluez4_p.h new file mode 100644 index 0000000..e3354ea --- /dev/null +++ b/src/bluez4/obexmanager_bluez4_p.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_OBEXMANAGER_BLUEZ4_P_H +#define BLUEZQT_OBEXMANAGER_BLUEZ4_P_H + +#include <QObject> +#include <QDBusAbstractAdaptor> + +#include "types.h" +#include "bluezqt_dbustypes.h" +#include "bluez4obexclient.h" +#include "bluez4obexmanager.h" + +namespace BluezQt +{ + +typedef org::bluez::obex::Client Bluez4ObexClient; +typedef org::bluez::obex::Manager Bluez4ObexManager; + +class ObexManagerPrivate; +class ObexManagerBluez4; + +class ObexManagerNotifier : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.bluezqt.obex.ObexManagerNotifier") + Q_CLASSINFO("D-Bus Introspection", "" +" <interface name=\"org.kde.bluezqt.obex.ObexManagerNotifier\">\n" +" <method name=\"getSessions\">\n" +" <arg type=\"aa{sv}\" direction=\"out\"/>\n" +" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantMapList\"/>\n" +" </method>\n" +" <method name=\"getTransfers\">\n" +" <arg type=\"aa{sv}\" direction=\"out\"/>\n" +" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QVariantMapList\"/>\n" +" </method>\n" +" <method name=\"setTransferAborted\">\n" +" <arg type=\"s\"/>\n" +" </method>\n" +" </interface>\n" + "") + +public: + ObexManagerNotifier(ObexManagerBluez4 *parent); + + inline static QDBusConnection connection() { return QDBusConnection::sessionBus(); } + inline static QString service() { return QStringLiteral("org.kde.bluezqt.obex"); } + inline static QString objectPath() { return QStringLiteral("/ObexManagerNotifier"); } + inline static QString interface() { return QStringLiteral("org.kde.bluezqt.obex.ObexManagerNotifier"); } + + static void notifyTransferAborted(const QString &transferPath); + +public Q_SLOTS: + QVariantMapList getSessions(); + QVariantMapList getTransfers(); + Q_NOREPLY void setTransferAborted(const QString &transferPath); + +private: + friend class ObexManagerBluez4; + ObexManagerBluez4 *m_managerBluez4; +}; + + +class ObexManagerBluez4 : public QObject +{ + Q_OBJECT + +public: + explicit ObexManagerBluez4(ObexManagerPrivate *obexManagerPrivate); + + void load(); + + QDBusPendingReply<void> registerAgent(const QDBusObjectPath &agentPath); + QDBusPendingReply<void> unregisterAgent(const QDBusObjectPath &agentPath); + + PendingCall *createSession(const QString &destination, const QVariantMap &args); + PendingCall *removeSession(const QDBusObjectPath &session); + + ObexTransferPtr newObjectPushTransfer(const QDBusObjectPath &transferPath, + const QVariantMap &transferProperties, + const QString &destinationAddress); + + void setTransferAborted(const QString &transferPath); + QList<QVariantMap> sessionProperties() const; + QList<QVariantMap> transferProperties() const; + ObexSessionPtr sessionForObjectPushTransfer(const QDBusObjectPath &transferPath); + + ObexManagerPrivate *m_obexManagerPrivate; + Bluez4ObexClient *m_bluez4ObexClient; + Bluez4ObexManager *m_bluez4ObexManager; + +Q_SIGNALS: + void loaded(); + +private Q_SLOTS: + void objectPushTransferCreated(const QString &transferPath, const QVariantMap &transferProperties, + const QString &sessionPath, const QVariantMap &sessionProperties); + void objectPushTransferFinished(const QString &transferPath, const QString &sessionPath, bool success); + +private: + void getSessionsFinished(QDBusPendingCallWatcher *watcher); + void getTransfersFinished(QDBusPendingCallWatcher *watcher); + void completeLoading(); + + void createSessionFinished(PendingCall *call); + void removeSessionFinished(PendingCall *call); + + void transferStarted(const QDBusObjectPath &objectPath); + void transferCompleted(const QDBusObjectPath &objectPath, bool success); + + void notifyObexManagers(const QString &signalName, const QVariantList &args); + + static QString obexSessionPathKey(); + static QString obexTransferPathKey(); + + QHash<QString, ObexTransferPtr> m_oppTransfers; + ObexManagerNotifier *m_managerNotifier; + bool m_initializedSessions; + bool m_initializedTransfers; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_OBEXMANAGER_BLUEZ4_P_H diff --git a/src/bluez4/obexsession_bluez4.cpp b/src/bluez4/obexsession_bluez4.cpp new file mode 100644 index 0000000..6887356 --- /dev/null +++ b/src/bluez4/obexsession_bluez4.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#include "obexsession_bluez4_p.h" + +#include <QDBusObjectPath> + +namespace BluezQt +{ + +ObexSessionBluez4::ObexSessionBluez4() + : m_valid(false) +{ +} + +ObexSessionBluez4::ObexSessionBluez4(const QString &path, const QVariantMap &properties) + : m_valid(true) +{ + m_sessionPath = QDBusObjectPath(path); + m_oppTransferPath = properties.value(objectPushTransferPathKey()).toString(); + m_properties = properties; +} + +QString ObexSessionBluez4::objectPushTransferPathKey() +{ + return QStringLiteral("org.kde.bluezqt.ObexTransfer.ObjectPush.Path"); +} + +} // namespace BluezQt diff --git a/src/bluez4/obexsession_bluez4_p.h b/src/bluez4/obexsession_bluez4_p.h new file mode 100644 index 0000000..03cfb60 --- /dev/null +++ b/src/bluez4/obexsession_bluez4_p.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + + +#ifndef BLUEZQT_OBEXSESSION_BLUEZ4_P_H +#define BLUEZQT_OBEXSESSION_BLUEZ4_P_H + +#include <QVariantMap> +#include <QDBusObjectPath> + +namespace BluezQt +{ + +class ObexSessionBluez4 +{ +public: + ObexSessionBluez4(); + ObexSessionBluez4(const QString &path, const QVariantMap &properties); + + static QString objectPushTransferPathKey(); + + bool m_valid; + QDBusObjectPath m_sessionPath; + QString m_oppTransferPath; + QVariantMap m_properties; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_OBEXSESSION_BLUEZ4_P_H diff --git a/src/bluez4/obextransfer_bluez4.cpp b/src/bluez4/obextransfer_bluez4.cpp new file mode 100644 index 0000000..7659c2b --- /dev/null +++ b/src/bluez4/obextransfer_bluez4.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#include "obextransfer_bluez4_p.h" +#include "macros_bluez4_p.h" + +#include "obextransfer_p.h" +#include "utils.h" +#include "macros.h" + +#include <QMimeDatabase> + +namespace BluezQt +{ + +ObexTransferBluez4::ObexTransferBluez4(ObexTransferPrivate *obexTransferPrivate, const QString &path, const QVariantMap &properties) + : QObject(obexTransferPrivate) + , m_obexTransferPrivate(obexTransferPrivate) +{ + const bool clientOrigin = path.contains(QStringLiteral("session")); + const QString &service = clientOrigin ? QStringLiteral("org.bluez.obex.client") : Strings::orgBluezObex(); + m_bluez4Transfer = new Bluez4Transfer(service, path, DBusConnection::orgBluezObex(), this); + + // Connect to the transfer signals depending on whether this is a client service. + if (clientOrigin) { + connect(m_bluez4Transfer, &Bluez4Transfer::PropertyChanged, + this, &ObexTransferBluez4::orgBluezObexClientTransferPropertyChanged, Qt::QueuedConnection); + connect(m_bluez4Transfer, &Bluez4Transfer::Complete, + this, &ObexTransferBluez4::orgBluezObexClientTransferComplete, Qt::QueuedConnection); + connect(m_bluez4Transfer, &Bluez4Transfer::Error, + this, &ObexTransferBluez4::orgBluezObexClientTransferError, Qt::QueuedConnection); + } else { + connect(m_bluez4Transfer, &Bluez4Transfer::Progress, + this, &ObexTransferBluez4::orgBluezObexTransferProgress, Qt::QueuedConnection); + } + + // 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 (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()); + } + + obexTransferPrivate->init(modifiedProperties); + m_properties = properties; +} + +void ObexTransferBluez4::setTransferProperty(const QString &property, const QVariant &value) +{ + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezObexTransfer1(), m_obexTransferPrivate, property, value); +} + +void ObexTransferBluez4::orgBluezObexTransferProgress(qint32 total, qint32 transferred) +{ + Q_UNUSED(total) + + QVariant value = static_cast<quint64>(transferred); + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezObexTransfer1(), m_obexTransferPrivate, QStringLiteral("Transferred"), value); +} + +void ObexTransferBluez4::orgBluezObexClientTransferComplete() +{ + m_obexTransferPrivate->m_status = ObexTransfer::Complete; + Q_EMIT m_obexTransferPrivate->q.data()->statusChanged(m_obexTransferPrivate->m_status); +} + +void ObexTransferBluez4::orgBluezObexClientTransferError(const QString &code, const QString &message) +{ + Q_UNUSED(code) + Q_UNUSED(message) + + m_obexTransferPrivate->m_status = ObexTransfer::Error; + Q_EMIT m_obexTransferPrivate->q.data()->statusChanged(m_obexTransferPrivate->m_status); +} + +void ObexTransferBluez4::orgBluezObexClientTransferPropertyChanged(const QString &property, const QDBusVariant &value) +{ + if (property == QStringLiteral("Progress")) { + // 'Transferred' was 'Progress' in BlueZ 4 + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezObexTransfer1(), m_obexTransferPrivate, QStringLiteral("Transferred"), value.variant()); + } else { + INVOKE_PROPERTIES_CHANGED(Strings::orgBluezObexTransfer1(), m_obexTransferPrivate, property, value.variant()); + } +} + +} // namespace BluezQt diff --git a/src/bluez4/obextransfer_bluez4_p.h b/src/bluez4/obextransfer_bluez4_p.h new file mode 100644 index 0000000..ba7cdf2 --- /dev/null +++ b/src/bluez4/obextransfer_bluez4_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_OBEXTRANSFER_BLUEZ4_P_H +#define BLUEZQT_OBEXTRANSFER_BLUEZ4_P_H + +#include "bluez4obextransfer.h" + +namespace BluezQt +{ + +typedef org::bluez::obex::Transfer Bluez4Transfer; + +class ObexTransferPrivate; + +class ObexTransferBluez4 : public QObject +{ + Q_OBJECT + +public: + explicit ObexTransferBluez4(ObexTransferPrivate *obexTransferPrivate, const QString &path, const QVariantMap &properties); + + void init(const QVariantMap &properties); + void setTransferProperty(const QString &property, const QVariant &value); + + ObexTransferPrivate *m_obexTransferPrivate; + Bluez4Transfer *m_bluez4Transfer; + QVariantMap m_properties; + +private: + // 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); +}; + +} // namespace BluezQt + +#endif // BLUEZQT_OBEXTRANSFER_BLUEZ4_P_H diff --git a/src/bluez4/proxyagent.cpp b/src/bluez4/proxyagent.cpp new file mode 100644 index 0000000..2410712 --- /dev/null +++ b/src/bluez4/proxyagent.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#include "proxyagent_p.h" + +#include <QDBusObjectPath> + +namespace BluezQt +{ + +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(); +} + +} // namespace BluezQt diff --git a/src/bluez4/proxyagent_p.h b/src/bluez4/proxyagent_p.h new file mode 100644 index 0000000..d7647ad --- /dev/null +++ b/src/bluez4/proxyagent_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Jolla Ltd. +** Contact: Bea Lam <bea.lam@jolla.com> +** +** This file is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This file is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this file; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +** +****************************************************************************/ + +#ifndef BLUEZQT_PROXYAGENT_H +#define BLUEZQT_PROXYAGENT_H + +#include <QObject> + +#include "agent.h" + +namespace BluezQt +{ + +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; +}; + +} // namespace BluezQt + +#endif // BLUEZQT_PROXYAGENT_H diff --git a/src/bluezqt_dbustypes.h b/src/bluezqt_dbustypes.h index cb07da8..2dbf6fd 100644 --- a/src/bluezqt_dbustypes.h +++ b/src/bluezqt_dbustypes.h @@ -36,12 +36,4 @@ 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 33b749f..5b2956b 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -22,9 +22,14 @@ #include "device.h" #include "device_p.h" +#include "adapter.h" #include "pendingcall.h" #include "utils.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/device_bluez4_p.h" +#endif + namespace BluezQt { @@ -46,7 +51,11 @@ DevicePtr Device::toSharedPtr() const QString Device::ubi() const { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return d->m_bluezDevice->path(); +#else + return d->m_bluez4->m_bluez4Device->path(); +#endif } QString Device::address() const @@ -278,24 +287,20 @@ PendingCall *Device::connectToDevice() // 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); + return new PendingCall(d->m_bluez4->orgBluezInput()->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); + return new PendingCall(d->m_bluez4->orgBluezAudio()->asyncCall(QStringLiteral("Connect")), PendingCall::ReturnVoid, this); } #endif } PendingCall *Device::disconnectFromDevice() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezDevice->Disconnect(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(d->m_bluez4->m_bluez4Device->Disconnect(), PendingCall::ReturnVoid, this); +#endif } PendingCall *Device::connectProfile(const QString &uuid) @@ -326,7 +331,7 @@ PendingCall *Device::pair() 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); + return new PendingCall(d->m_bluez4->pair(d->m_adapter), PendingCall::ReturnObjectPath, this); #endif } @@ -338,7 +343,7 @@ PendingCall *Device::cancelPairing() 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); + return new PendingCall(d->m_bluez4->cancelPairing(d->m_adapter), PendingCall::ReturnVoid, this); #endif } diff --git a/src/device.h b/src/device.h index 42d5159..79c7ca5 100644 --- a/src/device.h +++ b/src/device.h @@ -514,6 +514,8 @@ private: friend class DevicePrivate; friend class ManagerPrivate; friend class Adapter; + + friend class ManagerBluez4; }; } // namespace BluezQt diff --git a/src/device_p.cpp b/src/device_p.cpp index cb34315..30c6046 100644 --- a/src/device_p.cpp +++ b/src/device_p.cpp @@ -33,7 +33,7 @@ #include "macros.h" #if KF5BLUEZQT_BLUEZ_VERSION < 5 -#include "adapter_p.h" +#include "bluez4/device_bluez4_p.h" #endif namespace BluezQt @@ -42,12 +42,9 @@ 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) @@ -59,7 +56,11 @@ DevicePrivate::DevicePrivate(const QString &path, const QVariantMap &properties, , m_connected(false) , m_adapter(adapter) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_bluezDevice = new BluezDevice(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); +#else + m_bluez4 = new DeviceBluez4(this, path); +#endif init(properties); } @@ -73,9 +74,6 @@ void DevicePrivate::init(const QVariantMap &properties) // 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 @@ -99,7 +97,6 @@ void DevicePrivate::init(const QVariantMap &properties) } } -#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void DevicePrivate::interfacesAdded(const QString &path, const QVariantMapMap &interfaces) { bool changed = false; @@ -128,9 +125,7 @@ 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) @@ -156,26 +151,21 @@ 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)); + return m_bluez4->m_bluez4Device->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) { @@ -259,23 +249,4 @@ 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 24ca5c5..681c8fa 100644 --- a/src/device_p.h +++ b/src/device_p.h @@ -25,13 +25,14 @@ #include <QObject> #include <QStringList> +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include <QDBusPendingReply> +#endif #include "types.h" #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "bluezdevice1.h" #include "dbusproperties.h" -#else -#include "bluezdevice.h" #endif #include "bluezqt_dbustypes.h" @@ -42,7 +43,7 @@ namespace BluezQt typedef org::bluez::Device1 BluezDevice; typedef org::freedesktop::DBus::Properties DBusProperties; #else -typedef org::bluez::Device BluezDevice; +class DeviceBluez4; #endif class DevicePrivate : public QObject @@ -54,10 +55,8 @@ 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); @@ -65,19 +64,10 @@ 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 + BluezDevice *m_bluezDevice; DBusProperties *m_dbusProperties; -#else - QDBusInterface *m_inputInterface; - QDBusInterface *m_audioInterface; #endif QString m_address; @@ -98,6 +88,10 @@ public: MediaPlayerPtr m_mediaPlayer; MediaTransportPtr m_mediaTransport; AdapterPtr m_adapter; + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + DeviceBluez4 *m_bluez4; +#endif }; } // namespace BluezQt diff --git a/src/input.cpp b/src/input.cpp index 3789b71..8489278 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -25,6 +25,10 @@ #include "utils.h" #include "macros.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "debug.h" +#endif + namespace BluezQt { @@ -53,6 +57,8 @@ InputPrivate::InputPrivate(const QString &path, const QVariantMap &properties) connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &InputPrivate::propertiesChanged, Qt::QueuedConnection); +#else + Q_UNUSED(path) #endif // Init properties @@ -63,13 +69,9 @@ 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) { @@ -99,6 +101,9 @@ InputPtr Input::toSharedPtr() const Input::ReconnectMode Input::reconnectMode() const { +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + qCWarning(BLUEZQT) << "Input::reconnectMode() not available in BlueZ 4!"; +#endif return d->m_reconnectMode; } diff --git a/src/interfaces/bluez4/bluez4.pri b/src/interfaces/bluez4/bluez4.pri index a2977f1..c3f3d04 100644 --- a/src/interfaces/bluez4/bluez4.pri +++ b/src/interfaces/bluez4/bluez4.pri @@ -1,46 +1,46 @@ 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 +system(qdbusxml2cpp -c Bluez4Adapter -p $$SRC_DIR/bluez4adapter.h:$$SRC_DIR/bluez4adapter.cpp $$PWD/org.bluez.Adapter.xml) +system(qdbusxml2cpp -c Bluez4Device -p $$SRC_DIR/bluez4device.h:$$SRC_DIR/bluez4device.cpp $$PWD/org.bluez.Device.xml -i $$SRC_DIR/bluez4/bluezqt_dbustypes_bluez4_p.h) +system(qdbusxml2cpp -c Bluez4Manager -p $$SRC_DIR/bluez4manager.h:$$SRC_DIR/bluez4manager.cpp $$PWD/org.bluez.Manager.xml) +system(qdbusxml2cpp -c Bluez4MediaPlayer -p $$SRC_DIR/bluez4mediaplayer.h:$$SRC_DIR/bluez4mediaplayer.cpp $$PWD/org.bluez.MediaPlayer.xml) +system(qdbusxml2cpp -c Bluez4MediaTransport -p $$SRC_DIR/bluez4mediatransport.h:$$SRC_DIR/bluez4mediatransport.cpp $$PWD/org.bluez.MediaTransport.xml -i $$SRC_DIR/bluez4/bluezqt_dbustypes_bluez4_p.h) + +system(qdbusxml2cpp -c Bluez4ObexManager -p $$SRC_DIR/bluez4obexmanager.h:$$SRC_DIR/bluez4obexmanager.cpp $$PWD/org.bluez.obex.Manager.xml) +system(qdbusxml2cpp -c Bluez4ObexClient -p $$SRC_DIR/bluez4obexclient.h:$$SRC_DIR/bluez4obexclient.cpp $$PWD/org.bluez.obex.Client.xml) +system(qdbusxml2cpp -c Bluez4ObexFileTransfer -p $$SRC_DIR/bluez4obexfiletransfer.h:$$SRC_DIR/bluez4obexfiletransfer.cpp $$PWD/org.bluez.obex.FileTransfer.xml -i $$SRC_DIR/bluez4/bluezqt_dbustypes_bluez4_p.h -i $$SRC_DIR/bluezqt_dbustypes.h) +system(qdbusxml2cpp -c Bluez4ObexTransfer -p $$SRC_DIR/bluez4obextransfer.h:$$SRC_DIR/bluez4obextransfer.cpp $$PWD/org.bluez.obex.Transfer.xml) +system(qdbusxml2cpp -c Bluez4ObexObjectPush -p $$SRC_DIR/bluez4obexobjectpush.h:$$SRC_DIR/bluez4obexobjectpush.cpp $$PWD/org.bluez.obex.ObjectPush.xml -i $$SRC_DIR/bluez4/bluezqt_dbustypes_bluez4_p.h) + +BLUEZ4_DBUS_SOURCES += \ + $$SRC_DIR/bluez4adapter.cpp \ + $$SRC_DIR/bluez4device.cpp \ + $$SRC_DIR/bluez4manager.cpp \ + $$SRC_DIR/bluez4mediaplayer.cpp \ + $$SRC_DIR/bluez4mediatransport.cpp \ + $$SRC_DIR/bluez4obexmanager.cpp \ + $$SRC_DIR/bluez4obexclient.cpp \ + $$SRC_DIR/bluez4obexfiletransfer.cpp \ + $$SRC_DIR/bluez4obextransfer.cpp \ + $$SRC_DIR/bluez4obexobjectpush.cpp + +BLUEZ4_DBUS_HEADERS += \ + $$SRC_DIR/bluez4adapter.h \ + $$SRC_DIR/bluez4device.h \ + $$SRC_DIR/bluez4manager.h \ + $$SRC_DIR/bluez4mediaplayer.h \ + $$SRC_DIR/bluez4mediatransport.h \ + $$SRC_DIR/bluez4obexmanager.h \ + $$SRC_DIR/bluez4obexclient.h \ + $$SRC_DIR/bluez4obexfiletransfer.h \ + $$SRC_DIR/bluez4obextransfer.h \ + $$SRC_DIR/bluez4obexobjectpush.h SOURCES += \ - $$DBUS_SOURCES + $$BLUEZ4_DBUS_SOURCES HEADERS += \ - $$DBUS_HEADERS + $$BLUEZ4_DBUS_HEADERS OTHER_FILES += \ $$PWD/*.xml diff --git a/src/interfaces/interfaces.pri b/src/interfaces/interfaces.pri index 82f9672..693c9e4 100644 --- a/src/interfaces/interfaces.pri +++ b/src/interfaces/interfaces.pri @@ -3,17 +3,17 @@ 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) +system(qdbusxml2cpp -c BluezAdapter1 -p $$SRC_DIR/bluezadapter1.h:$$SRC_DIR/bluezadapter1.cpp $$PWD/org.bluez.Adapter1.xml) +system(qdbusxml2cpp -c BluezAgentManager1 -p $$SRC_DIR/bluezagentmanager1.h:$$SRC_DIR/bluezagentmanager1.cpp $$PWD/org.bluez.AgentManager1.xml) +system(qdbusxml2cpp -c BluezProfileManager1 -p $$SRC_DIR/bluezprofilemanager1.h:$$SRC_DIR/bluezprofilemanager1.cpp $$PWD/org.bluez.ProfileManager1.xml) +system(qdbusxml2cpp -c BluezDevice1 -p $$SRC_DIR/bluezdevice1.h:$$SRC_DIR/bluezdevice1.cpp $$PWD/org.bluez.Device1.xml) +system(qdbusxml2cpp -c BluezMediaPlayer1 -p $$SRC_DIR/bluezmediaplayer1.h:$$SRC_DIR/bluezmediaplayer1.cpp $$PWD/org.bluez.MediaPlayer1.xml) +system(qdbusxml2cpp -c BluezMediaTransport1 -p $$SRC_DIR/bluezmediatransport1.h:$$SRC_DIR/bluezmediatransport1.cpp $$PWD/org.bluez.MediaTransport1.xml) +system(qdbusxml2cpp -c ObexAgentManager1 -p $$SRC_DIR/obexagentmanager1.h:$$SRC_DIR/obexagentmanager1.cpp $$PWD/org.bluez.obex.AgentManager1.xml) +system(qdbusxml2cpp -c ObexClient1 -p $$SRC_DIR/obexclient1.h:$$SRC_DIR/obexclient1.cpp $$PWD/org.bluez.obex.Client1.xml) +system(qdbusxml2cpp -c ObexTransfer1 -p $$SRC_DIR/obextransfer1.h:$$SRC_DIR/obextransfer1.cpp $$PWD/org.bluez.obex.Transfer1.xml) +system(qdbusxml2cpp -c ObexSession1 -p $$SRC_DIR/obexsession1.h:$$SRC_DIR/obexsession1.cpp $$PWD/org.bluez.obex.Session1.xml) +system(qdbusxml2cpp -c ObexObjectPush1 -p $$SRC_DIR/obexobjectpush1.h:$$SRC_DIR/obexobjectpush1.cpp $$PWD/org.bluez.obex.ObjectPush1.xml) DBUS_SOURCES += \ $$SRC_DIR/dbusobjectmanager.cpp \ diff --git a/src/macros.h b/src/macros.h index fbcc524..9b6c6f3 100644 --- a/src/macros.h +++ b/src/macros.h @@ -44,16 +44,4 @@ 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 2368bd9..d96f8f7 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -33,6 +33,10 @@ #include "utils.h" #include "debug.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/manager_bluez4_p.h" +#endif + namespace BluezQt { @@ -158,7 +162,6 @@ PendingCall *Manager::registerAgent(Agent *agent) if (!d->m_bluezAgentManager) { return new PendingCall(PendingCall::InternalError, QStringLiteral("Manager not operational!")); } -#endif QString capability; @@ -180,7 +183,6 @@ PendingCall *Manager::registerAgent(Agent *agent) break; } -#if KF5BLUEZQT_BLUEZ_VERSION >= 5 new AgentAdaptor(agent, this); if (!DBusConnection::orgBluez().registerObject(agent->objectPath().path(), agent)) { @@ -204,20 +206,21 @@ PendingCall *Manager::unregisterAgent(Agent *agent) if (!d->m_bluezAgentManager) { return new PendingCall(PendingCall::InternalError, QStringLiteral("Manager not operational!")); } +#endif DBusConnection::orgBluez().unregisterObject(agent->objectPath().path()); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 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); + AdapterPtr adapter = d->m_bluez4->findAdapterForDefaultAgent(agent); if (!adapter) { return new PendingCall(PendingCall::NoError, QString(), this); } - - return new PendingCall(d->unregisterDefaultAgent(adapter), PendingCall::ReturnVoid, this); + return new PendingCall(d->m_bluez4->unregisterDefaultAgent(adapter), PendingCall::ReturnVoid, this); #endif } @@ -236,9 +239,8 @@ PendingCall *Manager::requestDefaultAgent(Agent *agent) 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); + return new PendingCall(d->m_bluez4->requestDefaultAgent(adapter, agent), PendingCall::ReturnVoid, this); #endif } @@ -288,15 +290,15 @@ PendingCall *Manager::pairWithDevice(const QString &address) if (device) { return device->pair(); } + #if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(PendingCall::InternalError, QStringLiteral("Device unknown!"), 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->createPairedDevice(adapter, address), PendingCall::ReturnObjectPath, this); + return new PendingCall(d->m_bluez4->createPairedDevice(adapter, address), PendingCall::ReturnObjectPath, this); #endif } diff --git a/src/manager_p.cpp b/src/manager_p.cpp index ba5522d..495f3e2 100644 --- a/src/manager_p.cpp +++ b/src/manager_p.cpp @@ -29,15 +29,14 @@ #include "debug.h" #include "utils.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/manager_bluez4_p.h" +#endif + #include <QDBusReply> #include <QDBusConnection> #include <QDBusServiceWatcher> -#if KF5BLUEZQT_BLUEZ_VERSION < 5 -#include "bluezadapter.h" -#include "agentadaptor.h" -#endif - namespace BluezQt { @@ -48,8 +47,6 @@ ManagerPrivate::ManagerPrivate(Manager *parent) , m_dbusObjectManager(nullptr) , m_bluezAgentManager(nullptr) , m_bluezProfileManager(nullptr) -#else - , m_bluezManager(nullptr) #endif , m_usableAdapter(0) , m_initialized(false) @@ -134,17 +131,36 @@ void ManagerPrivate::load() 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); + m_bluez4 = new ManagerBluez4(this); + connect(m_bluez4, &ManagerBluez4::loaded, this, &ManagerPrivate::bluez4ManagerLoaded); + m_bluez4->load(); +#endif +} - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(m_bluezManager->DefaultAdapter(), this); - connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerPrivate::managerDefaultAdapterFinished); +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void ManagerPrivate::bluez4ManagerLoaded(bool success, const QString &errorMessage) +{ + if (success) { + // Initialize here as per getManagedObjectsFinished(). + m_loaded = true; + m_initialized = true; -#endif + Q_EMIT q->operationalChanged(true); + + if (q->isBluetoothOperational()) { + Q_EMIT q->bluetoothOperationalChanged(true); + } + + Q_EMIT initFinished(); + } else { + Q_EMIT initError(errorMessage); + } } +#endif -#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watcher) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 const QDBusPendingReply<DBusManagerStruct> &reply = *watcher; watcher->deleteLater(); @@ -195,8 +211,10 @@ void ManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watcher) } Q_EMIT initFinished(); -} +#else + Q_UNUSED(watcher) #endif +} void ManagerPrivate::clear() { @@ -233,6 +251,11 @@ void ManagerPrivate::clear() m_bluezAgentManager->deleteLater(); m_bluezAgentManager = nullptr; } +#else + if (m_bluez4) { + m_bluez4->deleteLater(); + m_bluez4 = Q_NULLPTR; + } #endif } @@ -269,7 +292,6 @@ 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(); @@ -290,9 +312,7 @@ 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(); @@ -312,12 +332,11 @@ void ManagerPrivate::interfacesRemoved(const QDBusObjectPath &objectPath, const } } } -#endif void ManagerPrivate::adapterRemoved(const AdapterPtr &adapter) { #if KF5BLUEZQT_BLUEZ_VERSION < 5 - m_defaultAgents.remove(adapter->ubi()); + m_bluez4->adapterRemoved(adapter->d); #endif disconnect(adapter.data(), &Adapter::poweredChanged, this, &ManagerPrivate::adapterPoweredChanged); @@ -379,16 +398,7 @@ void ManagerPrivate::addAdapter(const QString &adapterPath, const QVariantMap &p 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); + m_bluez4->addAdapter(adapter->d); #endif } @@ -470,308 +480,4 @@ 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(); - } -} - -QDBusPendingReply<QDBusObjectPath> ManagerPrivate::createPairedDevice(AdapterPtr adapter, const QString &address) -{ - return adapter->d->createPairedDevice(address); -} -#endif - } // namespace BluezQt diff --git a/src/manager_p.h b/src/manager_p.h index 9ef4cd8..ea56da8 100644 --- a/src/manager_p.h +++ b/src/manager_p.h @@ -33,9 +33,8 @@ #include "bluezagentmanager1.h" #include "bluezprofilemanager1.h" #else -#include "bluezmanager.h" -#include "agent.h" -#include <QSet> +#include "bluezqt_dbustypes.h" +class QDBusPendingCallWatcher; #endif namespace BluezQt @@ -45,8 +44,6 @@ namespace BluezQt 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; @@ -54,6 +51,10 @@ class Adapter; class Device; class AdapterPrivate; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +class ManagerBluez4; +#endif + class ManagerPrivate : public QObject { Q_OBJECT @@ -64,20 +65,15 @@ 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); @@ -90,41 +86,12 @@ 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); - - QDBusPendingReply<QDBusObjectPath> createPairedDevice(AdapterPtr adapter, const QString &address); -#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; @@ -137,6 +104,11 @@ public: bool m_adaptersLoaded; bool m_bluetoothBlocked; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void bluez4ManagerLoaded(bool success, const QString &errorMessage); + ManagerBluez4 *m_bluez4; +#endif + Q_SIGNALS: void initError(const QString &errorText); void initFinished(); diff --git a/src/mediaplayer.cpp b/src/mediaplayer.cpp index 623e31c..6d48ed4 100644 --- a/src/mediaplayer.cpp +++ b/src/mediaplayer.cpp @@ -23,7 +23,6 @@ #include "mediaplayer.h" #include "mediaplayer_p.h" #include "pendingcall.h" - #if KF5BLUEZQT_BLUEZ_VERSION < 5 #include "debug.h" #endif @@ -85,12 +84,10 @@ MediaPlayerPtr MediaPlayer::toSharedPtr() const QString MediaPlayer::name() const { -#if KF5BLUEZQT_BLUEZ_VERSION >= 5 - return d->m_name; -#else +#if KF5BLUEZQT_BLUEZ_VERSION < 5 qCWarning(BLUEZQT) << "MediaPlayer::name() not available in BlueZ 4!"; - return QString(); #endif + return d->m_name; } MediaPlayer::Equalizer MediaPlayer::equalizer() const @@ -133,12 +130,10 @@ MediaPlayer::Status MediaPlayer::status() const MediaPlayerTrack MediaPlayer::track() const { -#if KF5BLUEZQT_BLUEZ_VERSION >= 5 - return d->m_track; -#else +#if KF5BLUEZQT_BLUEZ_VERSION < 5 qCWarning(BLUEZQT) << "MediaPlayer::track() not available in BlueZ 4!"; - return MediaPlayerTrack(); #endif + return d->m_track; } quint32 MediaPlayer::position() const diff --git a/src/mediaplayer_p.cpp b/src/mediaplayer_p.cpp index 38dcc8d..53ed2bf 100644 --- a/src/mediaplayer_p.cpp +++ b/src/mediaplayer_p.cpp @@ -24,6 +24,10 @@ #include "utils.h" #include "macros.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/mediaplayer_bluez4_p.h" +#endif + namespace BluezQt { @@ -84,7 +88,11 @@ MediaPlayerPrivate::MediaPlayerPrivate(const QString &path, const QVariantMap &p , m_status(MediaPlayer::Error) , m_position(0) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_bluezMediaPlayer = new BluezMediaPlayer(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); +#else + m_bluez4 = new MediaPlayerBluez4(this, path); +#endif init(properties); } @@ -97,9 +105,6 @@ void MediaPlayerPrivate::init(const QVariantMap &properties) connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &MediaPlayerPrivate::propertiesChanged, Qt::QueuedConnection); -#else - connect(m_bluezMediaPlayer, &BluezMediaPlayer::PropertyChanged, - this, &MediaPlayerPrivate::mediaPlayerPropertyChanged); #endif // Init properties @@ -117,19 +122,15 @@ QDBusPendingReply<> MediaPlayerPrivate::setDBusProperty(const QString &name, con #if KF5BLUEZQT_BLUEZ_VERSION >= 5 return m_dbusProperties->Set(Strings::orgBluezMediaPlayer1(), name, QDBusVariant(value)); #else - return m_bluezMediaPlayer->SetProperty(name, QDBusVariant(value)); + return m_bluez4->m_bluez4MediaPlayer->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) { @@ -180,11 +181,4 @@ 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 acf617c..8367d25 100644 --- a/src/mediaplayer_p.h +++ b/src/mediaplayer_p.h @@ -24,13 +24,14 @@ #define BLUEZQT_MEDIAPLAYER_P_H #include <QObject> +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include <QDBusPendingReply> +#endif #include "mediaplayer.h" #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "bluezmediaplayer1.h" #include "dbusproperties.h" -#else -#include "bluezmediaplayer.h" #endif namespace BluezQt @@ -40,7 +41,7 @@ namespace BluezQt typedef org::bluez::MediaPlayer1 BluezMediaPlayer; typedef org::freedesktop::DBus::Properties DBusProperties; #else -typedef org::bluez::MediaPlayer BluezMediaPlayer; +class MediaPlayerBluez4; #endif class MediaPlayerPrivate : public QObject @@ -57,13 +58,9 @@ 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 + BluezMediaPlayer *m_bluezMediaPlayer; DBusProperties *m_dbusProperties; #endif @@ -74,6 +71,10 @@ public: MediaPlayer::Status m_status; MediaPlayerTrack m_track; quint32 m_position; + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + MediaPlayerBluez4 *m_bluez4; +#endif }; } // namespace BluezQt diff --git a/src/mediatransport.cpp b/src/mediatransport.cpp index 3895df9..0a38647 100644 --- a/src/mediatransport.cpp +++ b/src/mediatransport.cpp @@ -24,6 +24,10 @@ #include "mediatransport_p.h" #include "pendingcall.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/mediatransport_bluez4_p.h" +#endif + namespace BluezQt { @@ -91,7 +95,7 @@ PendingCall *MediaTransport::acquire() return new PendingCall(d->m_bluezMediaTransport->Acquire(), PendingCall::ReturnMediaTransportSocketInfo, this); #else - return new PendingCall(d->m_bluezMediaTransport->Acquire(QStringLiteral("rw")), + return new PendingCall(d->m_bluez4->m_bluez4MediaTransport->Acquire(QStringLiteral("rw")), PendingCall::ReturnMediaTransportSocketInfo, this); #endif } @@ -113,7 +117,7 @@ PendingCall *MediaTransport::release() return new PendingCall(d->m_bluezMediaTransport->Release(), PendingCall::ReturnVoid, this); #else - return new PendingCall(d->m_bluezMediaTransport->Release(QStringLiteral("rw")), + return new PendingCall(d->m_bluez4->m_bluez4MediaTransport->Release(QStringLiteral("rw")), PendingCall::ReturnVoid, this); #endif } diff --git a/src/mediatransport_p.cpp b/src/mediatransport_p.cpp index 73775ca..0c6a785 100644 --- a/src/mediatransport_p.cpp +++ b/src/mediatransport_p.cpp @@ -24,6 +24,10 @@ #include "utils.h" #include "macros.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/mediatransport_bluez4_p.h" +#endif + namespace BluezQt { @@ -47,7 +51,11 @@ MediaTransportPrivate::MediaTransportPrivate(const QString &path, const QVariant , m_delay(0) , m_volume(0) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 m_bluezMediaTransport = new BluezMediaTransport(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); +#else + m_bluez4 = new MediaTransportBluez4(this, path); +#endif init(properties); } @@ -60,9 +68,6 @@ void MediaTransportPrivate::init(const QVariantMap &properties) connect(m_dbusProperties, &DBusProperties::PropertiesChanged, this, &MediaTransportPrivate::propertiesChanged, Qt::QueuedConnection); -#else - connect(m_bluezMediaTransport, &BluezMediaTransport::PropertyChanged, - this, &MediaTransportPrivate::mediaTransportPropertyChanged); #endif // Init properties @@ -79,19 +84,15 @@ QDBusPendingReply<> MediaTransportPrivate::setDBusProperty(const QString &name, #if KF5BLUEZQT_BLUEZ_VERSION >= 5 return m_dbusProperties->Set(Strings::orgBluezMediaTransport1(), name, QDBusVariant(value)); #else - return m_bluezMediaTransport->SetProperty(name, QDBusVariant(value)); + return m_bluez4->m_bluez4MediaTransport->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) { @@ -130,11 +131,4 @@ 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 4ef1b46..d32da78 100644 --- a/src/mediatransport_p.h +++ b/src/mediatransport_p.h @@ -24,14 +24,14 @@ #define BLUEZQT_MEDIATRANSPORT_P_H #include <QObject> +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include <QDBusPendingReply> +#endif #include "mediatransport.h" - #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "bluezmediatransport1.h" #include "dbusproperties.h" -#else -#include "bluezmediatransport.h" #endif namespace BluezQt @@ -41,7 +41,7 @@ namespace BluezQt typedef org::bluez::MediaTransport1 BluezMediaTransport; typedef org::freedesktop::DBus::Properties DBusProperties; #else -typedef org::bluez::MediaTransport BluezMediaTransport; +class MediaTransportBluez4; #endif class MediaTransportPrivate : public QObject @@ -56,13 +56,9 @@ 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 + BluezMediaTransport *m_bluezMediaTransport; DBusProperties *m_dbusProperties; #endif @@ -72,6 +68,10 @@ public: MediaTransport::State m_state; quint16 m_delay; quint16 m_volume; + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + MediaTransportBluez4 *m_bluez4; +#endif }; } // namespace BluezQt diff --git a/src/obexagentadaptor.cpp b/src/obexagentadaptor.cpp index 4d908bd..68c05e1 100644 --- a/src/obexagentadaptor.cpp +++ b/src/obexagentadaptor.cpp @@ -28,7 +28,8 @@ #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "dbusproperties.h" #else -#include "obexmanager_p.h" +#include <QDBusPendingCallWatcher> +#include <QDBusPendingReply> #endif #include "utils.h" @@ -48,13 +49,7 @@ 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); @@ -66,31 +61,7 @@ QString ObexAgentAdaptor::Authorize(const QDBusObjectPath &transfer, const QStri 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(); } @@ -104,7 +75,6 @@ void ObexAgentAdaptor::Release() m_agent->release(); } -#if KF5BLUEZQT_BLUEZ_VERSION >= 5 void ObexAgentAdaptor::getPropertiesFinished(QDBusPendingCallWatcher *watcher) { const QDBusPendingReply<QVariantMap> &reply = *watcher; @@ -117,10 +87,6 @@ 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 ff3ca03..3de3b2b 100644 --- a/src/obexagentadaptor.h +++ b/src/obexagentadaptor.h @@ -40,33 +40,19 @@ 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 9694056..59e7f11 100644 --- a/src/obexfiletransfer.cpp +++ b/src/obexfiletransfer.cpp @@ -27,7 +27,7 @@ #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "obexfiletransfer1.h" #else -#include "bluezobexfiletransfer.h" +#include "bluez4obexfiletransfer.h" #endif namespace BluezQt diff --git a/src/obexmanager.cpp b/src/obexmanager.cpp index d7fbc74..dd78c23 100644 --- a/src/obexmanager.cpp +++ b/src/obexmanager.cpp @@ -30,6 +30,11 @@ #include "obexsession.h" #include "utils.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/obexmanager_bluez4_p.h" +#include "bluez4/obexagentadaptor_bluez4_p.h" +#endif + #include <QDBusServiceWatcher> namespace BluezQt @@ -74,21 +79,15 @@ 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 +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return ObexSessionPtr(); +#else + // 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 using the path parameter to search all known transfers. + return d->m_bluez4->sessionForObjectPushTransfer(path); +#endif } PendingCall *ObexManager::startService() @@ -107,82 +106,75 @@ PendingCall *ObexManager::registerAgent(ObexAgent *agent) { Q_ASSERT(agent); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_obexAgentManager) { 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); +#else + new ObexAgentAdaptorBluez4(agent, d->m_bluez4); +#endif if (!DBusConnection::orgBluezObex().registerObject(agent->objectPath().path(), agent)) { qCDebug(BLUEZQT) << "Cannot register object" << agent->objectPath().path(); } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_obexAgentManager->RegisterAgent(agent->objectPath()), PendingCall::ReturnVoid, this); +#else + return new PendingCall(d->m_bluez4->registerAgent(agent->objectPath()), + PendingCall::ReturnVoid, this); +#endif } PendingCall *ObexManager::unregisterAgent(ObexAgent *agent) { Q_ASSERT(agent); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_obexAgentManager) { return new PendingCall(PendingCall::InternalError, QStringLiteral("ObexManager not operational!")); } +#endif DBusConnection::orgBluezObex().unregisterObject(agent->objectPath().path()); +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_obexAgentManager->UnregisterAgent(agent->objectPath()), PendingCall::ReturnVoid, this); +#else + return new PendingCall(d->m_bluez4->unregisterAgent(agent->objectPath()), + PendingCall::ReturnVoid, this); +#endif } PendingCall *ObexManager::createSession(const QString &destination, const QVariantMap &args) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_obexClient) { 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; + return d->m_bluez4->createSession(destination, args); #endif } PendingCall *ObexManager::removeSession(const QDBusObjectPath &session) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!d->m_obexClient) { 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; + return d->m_bluez4->removeSession(session); #endif } diff --git a/src/obexmanager.h b/src/obexmanager.h index ab613a0..67739e3 100644 --- a/src/obexmanager.h +++ b/src/obexmanager.h @@ -206,9 +206,7 @@ private: friend class ObexManagerPrivate; friend class InitObexManagerJobPrivate; -#if KF5BLUEZQT_BLUEZ_VERSION < 5 - friend class ObexAgentAdaptor; -#endif + friend class ObexManagerBluez4; }; } // namespace BluezQt diff --git a/src/obexmanager_p.cpp b/src/obexmanager_p.cpp index 34e14e3..c4c26a7 100644 --- a/src/obexmanager_p.cpp +++ b/src/obexmanager_p.cpp @@ -30,13 +30,9 @@ #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "dbusobjectmanager.h" #else -#include "obextransfer_p.h" -#include "pendingcall.h" -#include "bluezqt_dbustypes.h" -#include <QDBusMessage> +#include "bluez4/obexmanager_bluez4_p.h" #endif - #include <QDBusServiceWatcher> namespace BluezQt @@ -44,42 +40,15 @@ 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) +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 , 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) @@ -164,39 +133,27 @@ 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); + m_bluez4 = new ObexManagerBluez4(this); + connect(m_bluez4, &ObexManagerBluez4::loaded, this, &ObexManagerPrivate::bluez4ObexManagerLoaded); + m_bluez4->load(); #endif } -#if KF5BLUEZQT_BLUEZ_VERSION >= 5 +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +void ObexManagerPrivate::bluez4ObexManagerLoaded() +{ + // Initialize here as per getManagedObjectsFinished(). + m_loaded = true; + m_initialized = true; + + Q_EMIT q->operationalChanged(true); + Q_EMIT initFinished(); +} +#endif + void ObexManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watcher) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 const QDBusPendingReply<DBusManagerStruct> &reply = *watcher; watcher->deleteLater(); @@ -235,8 +192,10 @@ void ObexManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watc Q_EMIT q->operationalChanged(true); Q_EMIT initFinished(); -} +#else + Q_UNUSED(watcher) #endif +} void ObexManagerPrivate::clear() { @@ -249,6 +208,7 @@ void ObexManagerPrivate::clear() Q_EMIT q->sessionRemoved(session); } +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 // Delete all other objects if (m_obexClient) { m_obexClient->deleteLater(); @@ -260,11 +220,15 @@ void ObexManagerPrivate::clear() m_obexAgentManager = nullptr; } -#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (m_dbusObjectManager) { m_dbusObjectManager->deleteLater(); m_dbusObjectManager = nullptr; } +#else + if (m_bluez4) { + m_bluez4->deleteLater(); + m_bluez4 = Q_NULLPTR; + } #endif } @@ -288,7 +252,6 @@ 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(); @@ -300,9 +263,7 @@ 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(); @@ -313,7 +274,6 @@ void ObexManagerPrivate::interfacesRemoved(const QDBusObjectPath &objectPath, co } } } -#endif void ObexManagerPrivate::addSession(const QString &sessionPath, const QVariantMap &properties) { @@ -338,250 +298,4 @@ 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 58e6d75..00a7af9 100644 --- a/src/obexmanager_p.h +++ b/src/obexmanager_p.h @@ -33,9 +33,7 @@ #include "obexagentmanager1.h" #else #include "bluezqt_dbustypes.h" -#include "bluezobexclient.h" -#include "bluezobexmanager.h" -#include <QDBusAbstractAdaptor> +class QDBusPendingCallWatcher; #endif namespace BluezQt @@ -45,39 +43,14 @@ namespace BluezQt 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); +class ObexManager; -private: - friend class ObexManagerPrivate; - ObexManagerPrivate *m_manager; -}; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +class ObexManagerBluez4; #endif -class ObexManager; - class ObexManagerPrivate : public QObject { Q_OBJECT @@ -93,42 +66,17 @@ 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; +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 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; @@ -138,17 +86,17 @@ public: bool m_obexRunning; bool m_loaded; +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + void bluez4ObexManagerLoaded(); + ObexManagerBluez4 *m_bluez4; +#endif + Q_SIGNALS: void initError(const QString &errorText); void initFinished(); 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 3a6e03e..06a913b 100644 --- a/src/obexobjectpush.cpp +++ b/src/obexobjectpush.cpp @@ -27,7 +27,7 @@ #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "obexobjectpush1.h" #else -#include "bluezobexobjectpush.h" +#include "bluez4obexobjectpush.h" #endif namespace BluezQt diff --git a/src/obexsession.cpp b/src/obexsession.cpp index 7df17e3..0a7da12 100644 --- a/src/obexsession.cpp +++ b/src/obexsession.cpp @@ -25,10 +25,6 @@ #include "pendingcall.h" #include "utils.h" -#if KF5BLUEZQT_BLUEZ_VERSION < 5 -#include <QDBusObjectPath> -#endif - namespace BluezQt { @@ -39,7 +35,7 @@ ObexSessionPrivate::ObexSessionPrivate(const QString &path, const QVariantMap &p m_bluezSession = new BluezSession(Strings::orgBluezObex(), path, DBusConnection::orgBluezObex(), this); #else - m_sessionPath = path; + m_bluez4 = ObexSessionBluez4(path, properties); #endif init(properties); @@ -52,10 +48,6 @@ 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) @@ -79,7 +71,7 @@ QDBusObjectPath ObexSession::objectPath() const #if KF5BLUEZQT_BLUEZ_VERSION >= 5 return QDBusObjectPath(d->m_bluezSession->path()); #else - return QDBusObjectPath(d->m_sessionPath); + return d->m_bluez4.m_sessionPath; #endif } diff --git a/src/obexsession.h b/src/obexsession.h index 4db083c..1b14d29 100644 --- a/src/obexsession.h +++ b/src/obexsession.h @@ -125,6 +125,8 @@ private: friend class ObexSessionPrivate; friend class ObexManagerPrivate; + + friend class ObexManagerBluez4; }; } // namespace BluezQt diff --git a/src/obexsession_p.h b/src/obexsession_p.h index b8cc6f4..3fe968d 100644 --- a/src/obexsession_p.h +++ b/src/obexsession_p.h @@ -27,6 +27,7 @@ #include "obexsession1.h" #else #include "obexsession.h" +#include "bluez4/obexsession_bluez4_p.h" #endif namespace BluezQt @@ -50,10 +51,6 @@ public: 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; @@ -61,6 +58,10 @@ public: quint8 m_channel; QString m_target; QString m_root; + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + ObexSessionBluez4 m_bluez4; +#endif }; } // namespace BluezQt diff --git a/src/obextransfer.cpp b/src/obextransfer.cpp index faef66a..e20aa0b 100644 --- a/src/obextransfer.cpp +++ b/src/obextransfer.cpp @@ -29,7 +29,7 @@ #include "macros.h" #if KF5BLUEZQT_BLUEZ_VERSION < 5 -#include <QMimeDatabase> +#include "bluez4/obextransfer_bluez4_p.h" #endif namespace BluezQt @@ -55,8 +55,6 @@ ObexTransferPrivate::ObexTransferPrivate(const QString &path, const QVariantMap : QObject() #if KF5BLUEZQT_BLUEZ_VERSION >= 5 , m_dbusProperties(nullptr) -#else - , m_clientOrigin(path.contains(QStringLiteral("session"))) #endif , m_status(ObexTransfer::Error) , m_time(0) @@ -67,35 +65,14 @@ ObexTransferPrivate::ObexTransferPrivate(const QString &path, const QVariantMap #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); + m_bluez4 = new ObexTransferBluez4(this, path, properties); #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) @@ -106,18 +83,6 @@ void ObexTransferPrivate::init(const QVariantMap &properties) 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 @@ -134,13 +99,9 @@ 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) { @@ -154,21 +115,18 @@ 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 } } void ObexTransferPrivate::sessionRemoved(const ObexSessionPtr &session) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 if (!m_bluezTransfer->path().startsWith(session->objectPath().path())) { return; } +#else + Q_UNUSED(session) +#endif // Change status to Error if org.bluez.obex crashes if (m_status != ObexTransfer::Complete && m_status != ObexTransfer::Error) { @@ -177,33 +135,6 @@ 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)) @@ -222,7 +153,11 @@ ObexTransferPtr ObexTransfer::toSharedPtr() const QDBusObjectPath ObexTransfer::objectPath() const { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return QDBusObjectPath(d->m_bluezTransfer->path()); +#else + return QDBusObjectPath(d->m_bluez4->m_bluez4Transfer->path()); +#endif } ObexTransfer::Status ObexTransfer::status() const @@ -271,7 +206,11 @@ bool ObexTransfer::isSuspendable() const PendingCall *ObexTransfer::cancel() { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 return new PendingCall(d->m_bluezTransfer->Cancel(), PendingCall::ReturnVoid, this); +#else + return new PendingCall(d->m_bluez4->m_bluez4Transfer->Cancel(), PendingCall::ReturnVoid, this); +#endif } PendingCall *ObexTransfer::suspend() @@ -288,15 +227,8 @@ 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); + return Q_NULLPTR; #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 0840fb6..c055805 100644 --- a/src/obextransfer.h +++ b/src/obextransfer.h @@ -180,10 +180,6 @@ 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. @@ -209,9 +205,7 @@ private: friend class ObexAgentAdaptor; friend class PendingCallPrivate; -#if KF5BLUEZQT_BLUEZ_VERSION < 5 - friend class ObexManagerPrivate; -#endif + friend class ObexManagerBluez4; }; } // namespace BluezQt diff --git a/src/obextransfer_p.h b/src/obextransfer_p.h index ae30150..b0fb88a 100644 --- a/src/obextransfer_p.h +++ b/src/obextransfer_p.h @@ -28,8 +28,6 @@ #if KF5BLUEZQT_BLUEZ_VERSION >= 5 #include "obextransfer1.h" #include "dbusproperties.h" -#else -#include "bluezobextransfer.h" #endif namespace BluezQt @@ -39,7 +37,7 @@ namespace BluezQt typedef org::bluez::obex::Transfer1 BluezTransfer; typedef org::freedesktop::DBus::Properties DBusProperties; #else -typedef org::bluez::obex::Transfer BluezTransfer; +class ObexTransferBluez4; #endif class ObexTransferPrivate : public QObject @@ -54,23 +52,10 @@ 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 + BluezTransfer *m_bluezTransfer; DBusProperties *m_dbusProperties; -#else - bool m_clientOrigin; - QVariantMap m_properties; #endif ObexTransfer::Status m_status; @@ -81,6 +66,10 @@ public: quint64 m_transferred; QString m_fileName; bool m_suspendable; + +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + ObexTransferBluez4 *m_bluez4; +#endif }; } // namespace BluezQt diff --git a/src/pendingcall.cpp b/src/pendingcall.cpp index ee42f6d..6e711ff 100644 --- a/src/pendingcall.cpp +++ b/src/pendingcall.cpp @@ -28,6 +28,11 @@ #include "bluezqt_dbustypes.h" #include "debug.h" +#if KF5BLUEZQT_BLUEZ_VERSION < 5 +#include "bluez4/bluezqt_dbustypes_bluez4_p.h" +#include <QDBusMetaType> +#endif + #include <QTimer> #include <QDBusPendingReply> #include <QDBusPendingCallWatcher> diff --git a/src/pendingcall.h b/src/pendingcall.h index 82b824f..5885c9d 100644 --- a/src/pendingcall.h +++ b/src/pendingcall.h @@ -198,6 +198,8 @@ private: friend class ObexSession; friend class ObexObjectPush; friend class ObexFileTransfer; + + friend class ObexManagerBluez4; }; } // namespace BluezQt diff --git a/src/profile.cpp b/src/profile.cpp index 7af84cd..3e91ee0 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -36,6 +36,9 @@ Profile::Profile(QObject *parent) : QObject(parent) , d(new ProfilePrivate) { +#if KF5BLUEZQT_BLUEZ_VERSION < 5 + qCWarning(BLUEZQT) << "Profile class not available in BlueZ 4!"; +#endif } Profile::~Profile() diff --git a/src/request.cpp b/src/request.cpp index da6cbee..4dd8203 100644 --- a/src/request.cpp +++ b/src/request.cpp @@ -25,7 +25,7 @@ #include "utils.h" #if KF5BLUEZQT_BLUEZ_VERSION < 5 -#include "obexmanager_p.h" +#include "bluez4/obexmanager_bluez4_p.h" #endif #include <QStringBuilder> @@ -50,7 +50,6 @@ public: #if KF5BLUEZQT_BLUEZ_VERSION < 5 QString m_oppTransferPath; - void notifyTransferAborted(); #endif }; @@ -105,7 +104,9 @@ void RequestPrivate::rejectRequest() } #if KF5BLUEZQT_BLUEZ_VERSION < 5 - notifyTransferAborted(); + if (!m_oppTransferPath.isEmpty()) { + ObexManagerNotifier::notifyTransferAborted(m_oppTransferPath); + } #endif } @@ -118,27 +119,11 @@ void RequestPrivate::cancelRequest() } #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"; - } + if (!m_oppTransferPath.isEmpty()) { + ObexManagerNotifier::notifyTransferAborted(m_oppTransferPath); } -} #endif +} // T template<typename T> @@ -193,13 +178,13 @@ void Request<T>::cancel() const d->cancelRequest(); } -#if KF5BLUEZQT_BLUEZ_VERSION < 5 template<typename T> void Request<T>::setObjectPushTransferPath(const QString &transferPath) { +#if KF5BLUEZQT_BLUEZ_VERSION < 5 d->m_oppTransferPath = transferPath; -} #endif +} // void Request<void>::Request() @@ -246,12 +231,14 @@ void Request<void>::cancel() const d->cancelRequest(); } -#if KF5BLUEZQT_BLUEZ_VERSION < 5 void Request<void>::setObjectPushTransferPath(const QString &transferPath) { +#if KF5BLUEZQT_BLUEZ_VERSION >= 5 + Q_UNUSED(transferPath) +#else d->m_oppTransferPath = transferPath; -} #endif +} // Generate classes template class Request<void>; diff --git a/src/request.h b/src/request.h index 88a66e4..bee48a9 100644 --- a/src/request.h +++ b/src/request.h @@ -103,10 +103,6 @@ public: */ void cancel() const; -#if KF5BLUEZQT_BLUEZ_VERSION < 5 - void setObjectPushTransferPath(const QString &transferPath); -#endif - private: explicit Request(RequestOriginatingType type, const QDBusMessage &message); @@ -115,6 +111,11 @@ private: friend class AgentAdaptor; friend class ObexAgentAdaptor; friend class ProfileAdaptor; + + // For BlueZ 4 + void setObjectPushTransferPath(const QString &transferPath); + friend class ObexAgentAdaptorBluez4; + friend class AgentAdaptorBluez4; }; // void @@ -132,10 +133,6 @@ 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); @@ -144,6 +141,11 @@ private: friend class AgentAdaptor; friend class ObexAgentAdaptor; friend class ProfileAdaptor; + + // For BlueZ 4 + void setObjectPushTransferPath(const QString &transferPath); + friend class ObexAgentAdaptorBluez4; + friend class AgentAdaptorBluez4; }; } // namespace BluezQt diff --git a/src/src.pro b/src/src.pro index 9a5d0de..01aad33 100644 --- a/src/src.pro +++ b/src/src.pro @@ -19,6 +19,7 @@ equals(KF5BLUEZQT_BLUEZ_VERSION, 5) { include(interfaces/interfaces.pri) } else { DEFINES += "KF5BLUEZQT_BLUEZ_VERSION=4" + include(bluez4/bluez4.pri) include(interfaces/bluez4/bluez4.pri) } @@ -104,7 +105,10 @@ HEADERS += \ profile_p.h \ debug.h \ utils.h \ - rfkill.h + rfkill.h \ + bluezqt_dbustypes.h \ + services.h \ + macros.h target.path = $$[QT_INSTALL_LIBS] -- 2.33.1