summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-05-07 16:56:17 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-05-22 09:07:46 +0200
commit26e9cf5bc608c7b50fc27a73442966b3880f0825 (patch)
treed5a845e0052c5f65b159a7442724b10ecba7e4d6
parent91914f0c1f69f3cd79518333cf088a141bb721a0 (diff)
Service discovery via Bluez5
At the same time we shift the ServiceClassUUID to service name mapping to QBluetoothUuid. It was used by Android and now Bluez 5 uses it too. Task-number: QTBUG-32085 Change-Id: I9f2d4dc4e2997683485f2ba7aaefb646cb72fb75 Reviewed-by: Aaron McCarthy <mccarthy.aaron@gmail.com>
-rw-r--r--src/bluetooth/bluetooth.pro2
-rw-r--r--src/bluetooth/bluez/bluez5_helper.cpp188
-rw-r--r--src/bluetooth/bluez/bluez5_helper_p.h3
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.cpp9
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.h1
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_android.cpp78
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp447
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.h13
-rw-r--r--src/bluetooth/qbluetoothuuid.cpp82
-rw-r--r--src/bluetooth/qbluetoothuuid.h4
10 files changed, 717 insertions, 110 deletions
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
index 9caaf794..95c7ae19 100644
--- a/src/bluetooth/bluetooth.pro
+++ b/src/bluetooth/bluetooth.pro
@@ -72,6 +72,8 @@ config_bluez:qtHaveModule(dbus) {
qbluetoothlocaldevice_bluez.cpp \
qbluetoothtransferreply_bluez.cpp
+ CONFIG += link_pkgconfig
+ PKGCONFIG_PRIVATE += bluez
} else:CONFIG(blackberry) {
DEFINES += QT_QNX_BLUETOOTH
diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp
index 7a20abac..c995d948 100644
--- a/src/bluetooth/bluez/bluez5_helper.cpp
+++ b/src/bluetooth/bluez/bluez5_helper.cpp
@@ -46,6 +46,7 @@
#include "objectmanager_p.h"
#include "properties_p.h"
#include "adapter1_bluez5_p.h"
+#include <bluetooth/sdp_lib.h>
QT_BEGIN_NAMESPACE
@@ -269,4 +270,191 @@ void QtBluezDiscoveryManager::removeAdapterFromMonitoring(const QString &dbusPat
emit discoveryInterrupted(dbusPath);
}
+#define BUFFER_SIZE 1024
+
+static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &xmlOutput)
+{
+ if (!data)
+ return;
+
+ const int length = indentation*2 + 1;
+ QByteArray indentString(length, ' ');
+
+ char snBuffer[BUFFER_SIZE];
+
+ xmlOutput.append(indentString);
+
+ // deal with every dtd type
+ switch (data->dtd) {
+ case SDP_DATA_NIL:
+ xmlOutput.append("<nil/>\n");
+ break;
+ case SDP_UINT8:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<uint8 value=\"0x%02x\"/>\n", data->val.uint8);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_UINT16:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<uint16 value=\"0x%04x\"/>\n", data->val.uint16);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_UINT32:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<uint32 value=\"0x%08x\"/>\n", data->val.uint32);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_UINT64:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<uint64 value=\"0x%016x\"/>\n", data->val.uint64);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_UINT128:
+ xmlOutput.append("<uint128 value=\"0x");
+ for (int i = 0; i < 16; i++)
+ ::sprintf(&snBuffer[i * 2], "%02x", data->val.uint128.data[i]);
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ case SDP_INT8:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<int8 value=\"%d\"/>/n", data->val.int8);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_INT16:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<int16 value=\"%d\"/>/n", data->val.int16);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_INT32:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<int32 value=\"%d\"/>/n", data->val.int32);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_INT64:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<int64 value=\"%d\"/>/n", data->val.int64);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_INT128:
+ xmlOutput.append("<int128 value=\"0x");
+ for (int i = 0; i < 16; i++)
+ ::sprintf(&snBuffer[i * 2], "%02x", data->val.int128.data[i]);
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ case SDP_UUID_UNSPEC:
+ break;
+ case SDP_UUID16:
+ case SDP_UUID32:
+ xmlOutput.append("<uuid value=\"0x");
+ sdp_uuid2strn(&(data->val.uuid), snBuffer, BUFFER_SIZE);
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ case SDP_UUID128:
+ xmlOutput.append("<uuid value=\"");
+ sdp_uuid2strn(&(data->val.uuid), snBuffer, BUFFER_SIZE);
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ case SDP_TEXT_STR_UNSPEC:
+ break;
+ case SDP_TEXT_STR8:
+ case SDP_TEXT_STR16:
+ case SDP_TEXT_STR32:
+ {
+ xmlOutput.append("<text ");
+ QByteArray text = QByteArray::fromRawData(data->val.str, data->unitSize);
+
+ bool hasNonPrintableChar = false;
+ for (int i = 0; i < text.count() && !hasNonPrintableChar; i++) {
+ if (!isprint(text[i])) {
+ hasNonPrintableChar = true;
+ break;
+ }
+ }
+
+ if (hasNonPrintableChar) {
+ xmlOutput.append("encoding=\"hex\" value=\"");
+ xmlOutput.append(text.toHex());
+ } else {
+ text.replace("&", "&amp");
+ text.replace("<", "&lt");
+ text.replace(">", "&gt");
+ text.replace("\"", "&quot");
+
+ xmlOutput.append("value=\"");
+ xmlOutput.append(text);
+ }
+
+ xmlOutput.append("\"/>\n");
+ break;
+ }
+ case SDP_BOOL:
+ if (data->val.uint8)
+ xmlOutput.append("<boolean value=\"true\"/>\n");
+ else
+ xmlOutput.append("<boolean value=\"false\"/>\n");
+ break;
+ case SDP_SEQ_UNSPEC:
+ break;
+ case SDP_SEQ8:
+ case SDP_SEQ16:
+ case SDP_SEQ32:
+ xmlOutput.append("<sequence>\n");
+ parseAttributeValues(data->val.dataseq, indentation + 1, xmlOutput);
+ xmlOutput.append(indentString);
+ xmlOutput.append("</sequence>\n");
+ break;
+ case SDP_ALT_UNSPEC:
+ break;
+ case SDP_ALT8:
+ case SDP_ALT16:
+ case SDP_ALT32:
+ xmlOutput.append("<alternate>\n");
+ parseAttributeValues(data->val.dataseq, indentation + 1, xmlOutput);
+ xmlOutput.append(indentString);
+ xmlOutput.append("</alternate>\n");
+ break;
+ case SDP_URL_STR_UNSPEC:
+ break;
+ case SDP_URL_STR8:
+ case SDP_URL_STR16:
+ case SDP_URL_STR32:
+ strncpy(snBuffer, data->val.str, data->unitSize - 1);
+ xmlOutput.append("<url value=\"");
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ default:
+ qDebug(QT_BT_BLUEZ) << "Unknown dtd type";
+ }
+
+ parseAttributeValues(data->next, indentation, xmlOutput);
+}
+
+static void parseAttribute(void *value, void *extraData)
+{
+ sdp_data_t *data = (sdp_data_t *) value;
+ QByteArray *xmlOutput = static_cast<QByteArray *>(extraData);
+
+ char buffer[BUFFER_SIZE];
+
+ ::qsnprintf(buffer, BUFFER_SIZE, " <attribute id=\"0x%04x\">\n", data->attrId);
+ xmlOutput->append(buffer);
+
+ parseAttributeValues(data, 2, *xmlOutput);
+
+ xmlOutput->append(" </attribute>\n");
+}
+
+// the resulting xml output is based on the already used xml parser
+QByteArray parseSdpRecord(sdp_record_t *record)
+{
+ if (!record || !record->attrlist)
+ return QByteArray();
+
+ QByteArray xmlOutput;
+
+ xmlOutput.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<record>\n");
+
+ sdp_list_foreach(record->attrlist, parseAttribute, &xmlOutput);
+ xmlOutput.append("</record>");
+
+ return xmlOutput;
+}
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/bluez/bluez5_helper_p.h b/src/bluetooth/bluez/bluez5_helper_p.h
index 49abc4af..2429c09c 100644
--- a/src/bluetooth/bluez/bluez5_helper_p.h
+++ b/src/bluetooth/bluez/bluez5_helper_p.h
@@ -44,6 +44,7 @@
#include <QtCore/QObject>
#include <QtDBus/QtDBus>
+#include <bluetooth/sdp.h>
typedef QMap<QString, QVariantMap> InterfaceList;
typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList;
@@ -55,6 +56,8 @@ QT_BEGIN_NAMESPACE
bool isBluez5();
+QByteArray parseSdpRecord(sdp_record_t *record);
+
class QtBluezDiscoveryManagerPrivate;
class QtBluezDiscoveryManager : public QObject
{
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
index 36849eed..fb9fb120 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
@@ -178,6 +178,8 @@ QBluetoothServiceDiscoveryAgent::~QBluetoothServiceDiscoveryAgent()
that if a remote Bluetooth device moves out of range in between two subsequent calls
to \l start() the list may contain stale entries.
+ \note The list of services should always be cleared before the discovery mode is changed.
+
\sa clear()
*/
QList<QBluetoothServiceInfo> QBluetoothServiceDiscoveryAgent::discoveredServices() const
@@ -277,6 +279,11 @@ void QBluetoothServiceDiscoveryAgent::start(DiscoveryMode mode)
if (d->discoveryState() == QBluetoothServiceDiscoveryAgentPrivate::Inactive
&& d->error != InvalidBluetoothAdapterError) {
+#ifdef QT_BLUEZ_BLUETOOTH
+ // done to avoid repeated parsing for adapter address
+ // on Bluez5
+ d->foundHostAdapterPath.clear();
+#endif
d->setDiscoveryMode(mode);
if (d->deviceAddress.isNull()) {
d->startDeviceDiscovery();
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.h b/src/bluetooth/qbluetoothservicediscoveryagent.h
index 59c7b74b..37c26a78 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.h
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.h
@@ -114,6 +114,7 @@ private:
#ifdef QT_BLUEZ_BLUETOOTH
Q_PRIVATE_SLOT(d_func(), void _q_discoveredServices(QDBusPendingCallWatcher*))
Q_PRIVATE_SLOT(d_func(), void _q_createdDevice(QDBusPendingCallWatcher*))
+ Q_PRIVATE_SLOT(d_func(), void _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::Error, const QString &, const QStringList &))
#endif
#ifdef QT_ANDROID_BLUETOOTH
Q_PRIVATE_SLOT(d_func(), void _q_processFetchedUuids(const QBluetoothAddress &address,
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
index 2643d7a9..1b248e68 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
@@ -304,80 +304,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids(
}
}
-
-static QString serviceNameForClassUuid(const uint value)
-{
- switch (value & 0xffff) {
- case QBluetoothUuid::ServiceDiscoveryServer: return QBluetoothServiceDiscoveryAgent::tr("Service Discovery");
- //case QBluetoothUuid::BrowseGroupDescriptor: return QString();
- //case QBluetoothUuid::PublicBrowseGroup: return QString();
- case QBluetoothUuid::SerialPort: return QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile");
- case QBluetoothUuid::LANAccessUsingPPP: return QBluetoothServiceDiscoveryAgent::tr("LAN Access Profile");
- case QBluetoothUuid::DialupNetworking: return QBluetoothServiceDiscoveryAgent::tr("Dial-up Networking");
- case QBluetoothUuid::IrMCSync: return QBluetoothServiceDiscoveryAgent::tr("Synchronization");
- case QBluetoothUuid::ObexObjectPush: return QBluetoothServiceDiscoveryAgent::tr("Object Push");
- case QBluetoothUuid::OBEXFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("File Transfer");
- case QBluetoothUuid::IrMCSyncCommand: return QBluetoothServiceDiscoveryAgent::tr("Synchronization Command");
- case QBluetoothUuid::Headset: return QBluetoothServiceDiscoveryAgent::tr("Headset");
- case QBluetoothUuid::AudioSource: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution Source");
- case QBluetoothUuid::AudioSink: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution Sink");
- case QBluetoothUuid::AV_RemoteControlTarget: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Target");
- case QBluetoothUuid::AdvancedAudioDistribution: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution");
- case QBluetoothUuid::AV_RemoteControl: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control");
- case QBluetoothUuid::AV_RemoteControlController: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Controller");
- case QBluetoothUuid::HeadsetAG: return QBluetoothServiceDiscoveryAgent::tr("Headset AG");
- case QBluetoothUuid::PANU: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (PANU)");
- case QBluetoothUuid::NAP: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (NAP)");
- case QBluetoothUuid::GN: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (GN)");
- case QBluetoothUuid::DirectPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Direct Printing (BPP)");
- case QBluetoothUuid::ReferencePrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Reference Printing (BPP)");
- case QBluetoothUuid::BasicImage: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Profile");
- case QBluetoothUuid::ImagingResponder: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Responder");
- case QBluetoothUuid::ImagingAutomaticArchive: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Archive");
- case QBluetoothUuid::ImagingReferenceObjects: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Ref Objects");
- case QBluetoothUuid::Handsfree: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free");
- case QBluetoothUuid::HandsfreeAudioGateway: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free AG");
- case QBluetoothUuid::DirectPrintingReferenceObjectsService: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing RefObject Service");
- case QBluetoothUuid::ReflectedUI: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Reflected UI");
- case QBluetoothUuid::BasicPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing");
- case QBluetoothUuid::PrintingStatus: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Status");
- case QBluetoothUuid::HumanInterfaceDeviceService: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device");
- case QBluetoothUuid::HardcopyCableReplacement: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement");
- case QBluetoothUuid::HCRPrint: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Print");
- case QBluetoothUuid::HCRScan: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Scan");
- case QBluetoothUuid::SIMAccess: return QBluetoothServiceDiscoveryAgent::tr("SIM Access");
- case QBluetoothUuid::PhonebookAccessPCE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PCE");
- case QBluetoothUuid::PhonebookAccessPSE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PSE");
- case QBluetoothUuid::PhonebookAccess: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access");
- case QBluetoothUuid::HeadsetHS: return QBluetoothServiceDiscoveryAgent::tr("Headset HS");
- case QBluetoothUuid::MessageAccessServer: return QBluetoothServiceDiscoveryAgent::tr("Message Access Server");
- case QBluetoothUuid::MessageNotificationServer: return QBluetoothServiceDiscoveryAgent::tr("Message Notification Server");
- case QBluetoothUuid::MessageAccessProfile: return QBluetoothServiceDiscoveryAgent::tr("Message Access");
- case QBluetoothUuid::GNSS: return QBluetoothServiceDiscoveryAgent::tr("Global Navigation Satellite System");
- case QBluetoothUuid::GNSSServer: return QBluetoothServiceDiscoveryAgent::tr("Global Navigation Satellite System Server");
- case QBluetoothUuid::Display3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization Display");
- case QBluetoothUuid::Glasses3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization Glasses");
- case QBluetoothUuid::Synchronization3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization");
- case QBluetoothUuid::MPSProfile: return QBluetoothServiceDiscoveryAgent::tr("Multi-Profile Specification (Profile)");
- case QBluetoothUuid::MPSService: return QBluetoothServiceDiscoveryAgent::tr("Multi-Profile Specification");
- case QBluetoothUuid::PnPInformation: return QBluetoothServiceDiscoveryAgent::tr("Device Identification");
- //case QBluetoothUuid::GenericNetworking: return QBluetoothServiceDiscoveryAgent::tr("");
- //case QBluetoothUuid::GenericFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("");
- //case QBluetoothUuid::GenericAudio: return QBluetoothServiceDiscoveryAgent::tr("");
- //case QBluetoothUuid::GenericTelephony: return QBluetoothServiceDiscoveryAgent::tr("");
- case QBluetoothUuid::VideoSource: return QBluetoothServiceDiscoveryAgent::tr("Video Source");
- case QBluetoothUuid::VideoSink: return QBluetoothServiceDiscoveryAgent::tr("Video Sink");
- case QBluetoothUuid::VideoDistribution: return QBluetoothServiceDiscoveryAgent::tr("Video Distribution");
- case QBluetoothUuid::HDP: return QBluetoothServiceDiscoveryAgent::tr("Health Device");
- case QBluetoothUuid::HDPSource: return QBluetoothServiceDiscoveryAgent::tr("Health Device Source");
- case QBluetoothUuid::HDPSink: return QBluetoothServiceDiscoveryAgent::tr("Health Device Sink");
- default:
- break;
- }
-
- return QString();
-}
-
void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QBluetoothDeviceInfo &remoteDevice, const QList<QBluetoothUuid> &uuids)
{
/* Android doesn't provide decent SDP data. A list of uuids is close to meaning-less
@@ -483,7 +409,9 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
QBluetoothServiceInfo::Sequence classId;
classId << QVariant::fromValue(uuids.at(i));
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
- serviceInfo.setServiceName(serviceNameForClassUuid(uuids.at(i).data1));
+ QBluetoothUuid::ServiceClassUuid clsId
+ = static_cast<QBluetoothUuid::ServiceClassUuid>(uuids.at(i).toUInt16());
+ serviceInfo.setServiceName(QBluetoothUuid::serviceClassToString(clsId));
}
//don't include the service if we already discovered it before
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
index 0c9addfb..a65b99f6 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
@@ -45,30 +45,58 @@
#include "bluez/manager_p.h"
#include "bluez/adapter_p.h"
#include "bluez/device_p.h"
+#include "bluez/bluez5_helper_p.h"
+#include "bluez/objectmanager_p.h"
+#include "bluez/adapter1_bluez5_p.h"
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/sdp.h"
+#include "bluetooth/sdp_lib.h"
#include <QtCore/QLoggingCategory>
#include <QtDBus/QDBusPendingCallWatcher>
+#include <QtConcurrent/QtConcurrentRun>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+static inline void convertAddress(quint64 from, quint8 (&to)[6])
+{
+ to[0] = (from >> 0) & 0xff;
+ to[1] = (from >> 8) & 0xff;
+ to[2] = (from >> 16) & 0xff;
+ to[3] = (from >> 24) & 0xff;
+ to[4] = (from >> 32) & 0xff;
+ to[5] = (from >> 40) & 0xff;
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QUuid, btBaseUuid, ("{00000000-0000-1000-8000-00805F9B34FB}"));
+
QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter)
: error(QBluetoothServiceDiscoveryAgent::NoError), m_deviceAdapterAddress(deviceAdapter), state(Inactive), deviceDiscoveryAgent(0),
mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), singleDevice(false),
- manager(0), adapter(0), device(0)
+ manager(0), managerBluez5(0), adapter(0), device(0)
{
- qRegisterMetaType<ServiceMap>("ServiceMap");
- qDBusRegisterMetaType<ServiceMap>();
+ if (isBluez5()) {
+ managerBluez5 = new OrgFreedesktopDBusObjectManagerInterface(
+ QStringLiteral("org.bluez"), QStringLiteral("/"),
+ QDBusConnection::systemBus());
+ qRegisterMetaType<QBluetoothServiceDiscoveryAgent::Error>("QBluetoothServiceDiscoveryAgent::Error");
+ } else {
+ qRegisterMetaType<ServiceMap>("ServiceMap");
+ qDBusRegisterMetaType<ServiceMap>();
- manager = new OrgBluezManagerInterface(QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus());
+ manager = new OrgBluezManagerInterface(QStringLiteral("org.bluez"), QStringLiteral("/"),
+ QDBusConnection::systemBus());
+ }
}
QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
{
delete device;
delete manager;
+ delete managerBluez5;
delete adapter;
}
@@ -76,7 +104,12 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
{
Q_Q(QBluetoothServiceDiscoveryAgent);
- qCDebug(QT_BT_BLUEZ) << "Full discovery on: " << address.toString();
+ qCDebug(QT_BT_BLUEZ) << "Discovery on: " << address.toString() << "Mode:" << DiscoveryMode();
+
+ if (managerBluez5) {
+ startBluez5(address);
+ return;
+ }
QDBusPendingReply<QDBusObjectPath> reply;
if (m_deviceAdapterAddress.isNull())
@@ -105,6 +138,242 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
}
+void QBluetoothServiceDiscoveryAgentPrivate::startBluez5(const QBluetoothAddress &address)
+{
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+
+ if (foundHostAdapterPath.isEmpty()) {
+ // check that we match adapter addresses or use first if it wasn't specified
+
+ QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects();
+ reply.waitForFinished();
+ if (reply.isError()) {
+ discoveredDevices.clear();
+ error = QBluetoothServiceDiscoveryAgent::InputOutputError;
+ errorString = reply.error().message();
+ emit q->error(error);
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
+ const QString desiredAdapter = m_deviceAdapterAddress.toString();
+ foreach (const QDBusObjectPath &path, reply.value().keys()) {
+ const InterfaceList ifaceList = reply.value().value(path);
+ foreach (const QString &iface, ifaceList.keys()) {
+ if (iface == QStringLiteral("org.bluez.Adapter1")) {
+ if (m_deviceAdapterAddress.isNull()
+ || desiredAdapter == ifaceList.value(iface).
+ value(QStringLiteral("Address")).toString()) {
+ // use first adapter or we just matched one
+ foundHostAdapterPath = path.path();
+ }
+
+ if (!foundHostAdapterPath.isEmpty())
+ break;
+ }
+ }
+
+ if (!foundHostAdapterPath.isEmpty())
+ break;
+ }
+
+ if (foundHostAdapterPath.isEmpty()) {
+ // Cannot find a local adapter
+ // Abort any outstanding discoveries
+ discoveredDevices.clear();
+
+ error = QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Cannot find local Bluetooth adapter");
+ emit q->error(error);
+ _q_serviceDiscoveryFinished();
+
+ return;
+ }
+ }
+
+ // ensure we didn't go offline yet
+ OrgBluezAdapter1Interface adapter(QStringLiteral("org.bluez"),
+ foundHostAdapterPath, QDBusConnection::systemBus());
+ if (!adapter.powered()) {
+ discoveredDevices.clear();
+
+ error = QBluetoothServiceDiscoveryAgent::PoweredOffError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr("Local device is powered off");
+ emit q->error(error);
+
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
+ if (DiscoveryMode() == QBluetoothServiceDiscoveryAgent::MinimalDiscovery) {
+ performMinimalServiceDiscovery(address);
+ } else {
+ // we need to run the discovery in a different thread
+ // as it involves blocking calls
+ QtConcurrent::run(this, &QBluetoothServiceDiscoveryAgentPrivate::runSdpScan,
+ address, QBluetoothAddress(adapter.address()));
+ }
+}
+
+/*
+ * This function runs in a different thread. We need to be very careful what we
+ * access from here. That's why invokeMethod is used below.
+ */
+void QBluetoothServiceDiscoveryAgentPrivate::runSdpScan(
+ const QBluetoothAddress &remoteAddress, const QBluetoothAddress localAddress)
+{
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+
+ // connect to SDP server
+ bdaddr_t local, remote;
+ convertAddress(localAddress.toUInt64(), local.b);
+ convertAddress(remoteAddress.toUInt64(), remote.b);
+
+ /* We use singleshot timer below because this function runs in a different
+ * thread than the rest of this class.
+ */
+
+ sdp_session_t *session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY);
+ // try one more time if first attempt fails
+ if (!session)
+ session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY);
+
+ qCDebug(QT_BT_BLUEZ) << "SDP for" << remoteAddress.toString() << session << qt_error_string(errno);
+ if (!session) {
+ if (singleDevice) {
+ // was sole device without result -> error
+ QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
+ Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
+ QBluetoothServiceDiscoveryAgent::InputOutputError),
+ Q_ARG(QString,
+ QBluetoothServiceDiscoveryAgent::tr("Unable to access device")),
+ Q_ARG(QStringList, QStringList()));
+ } else {
+ // go to next device
+ QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
+ Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
+ QBluetoothServiceDiscoveryAgent::NoError),
+ Q_ARG(QString, QString()),
+ Q_ARG(QStringList, QStringList()));
+ }
+
+ return;
+ }
+
+
+ // set the filter for service matches
+ uuid_t publicBrowseGroupUuid;
+ sdp_uuid16_create(&publicBrowseGroupUuid, QBluetoothUuid::PublicBrowseGroup);
+ sdp_list_t *serviceFilter;
+ serviceFilter = sdp_list_append(0, &publicBrowseGroupUuid);
+
+ uint32_t attributeRange = 0x0000ffff; //all attributes
+ sdp_list_t *attributes;
+ attributes = sdp_list_append(0, &attributeRange);
+
+ sdp_list_t* sdpResults;
+ int result = sdp_service_search_attr_req(session, serviceFilter, SDP_ATTR_REQ_RANGE,
+ attributes, &sdpResults);
+ sdp_list_free(attributes, 0);
+ sdp_list_free(serviceFilter, 0);
+
+ if (result != 0) {
+ qCDebug(QT_BT_BLUEZ) << "SDP search failed" << qt_error_string(errno);
+ sdp_close(session);
+ if (singleDevice) {
+ QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
+ Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
+ QBluetoothServiceDiscoveryAgent::InputOutputError),
+ Q_ARG(QString,
+ QBluetoothServiceDiscoveryAgent::tr("Unable to access device")),
+ Q_ARG(QStringList, QStringList()));
+ } else {
+ QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
+ Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
+ QBluetoothServiceDiscoveryAgent::NoError),
+ Q_ARG(QString, QString()),
+ Q_ARG(QStringList, QStringList()));
+ }
+ return;
+ }
+
+ qCDebug(QT_BT_BLUEZ) << "SDP search a success. Iterating results" << sdpResults;
+ QStringList xmlRecords;
+
+ // process the results
+ for ( ; sdpResults; sdpResults = sdpResults->next) {
+ sdp_record_t *record = (sdp_record_t *) sdpResults->data;
+
+ QByteArray xml = parseSdpRecord(record);
+ if (xml.isEmpty())
+ continue;
+
+ //qDebug() << xml;
+ xmlRecords.append(QString::fromUtf8(xml));
+ }
+
+ sdp_close(session);
+
+ QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
+ Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
+ QBluetoothServiceDiscoveryAgent::NoError),
+ Q_ARG(QString, QString()),
+ Q_ARG(QStringList, xmlRecords));
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::_q_finishSdpScan(QBluetoothServiceDiscoveryAgent::Error errorCode,
+ const QString &errorDescription,
+ const QStringList &xmlRecords)
+{
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+
+ if (errorCode != QBluetoothServiceDiscoveryAgent::NoError) {
+ qCWarning(QT_BT_BLUEZ) << "SDP search failed for"
+ << discoveredDevices.at(0).address().toString();
+ // We have an error which we need to indicate and stop further processing
+ discoveredDevices.clear();
+ error = errorCode;
+ errorString = errorDescription;
+ emit q->error(error);
+ } else if (!xmlRecords.isEmpty()) {
+ foreach (const QString &record, xmlRecords) {
+ const QBluetoothServiceInfo serviceInfo = parseServiceXml(record);
+
+ //apply uuidFilter
+ if (!uuidFilter.isEmpty()) {
+ bool serviceNameMatched = uuidFilter.contains(serviceInfo.serviceUuid());
+ bool serviceClassMatched = false;
+ foreach (const QBluetoothUuid &id, serviceInfo.serviceClassUuids()) {
+ if (uuidFilter.contains(id)) {
+ serviceClassMatched = true;
+ break;
+ }
+ }
+
+ if (!serviceNameMatched && !serviceClassMatched)
+ continue;
+ }
+
+ if (!serviceInfo.isValid())
+ continue;
+
+ discoveredServices.append(serviceInfo);
+ qCDebug(QT_BT_BLUEZ) << "Discovered services" << discoveredDevices.at(0).address().toString()
+ << serviceInfo.serviceName() << serviceInfo.serviceUuid()
+ << ">>>" << serviceInfo.serviceClassUuids();
+
+ // TODO check for duplicates (wait until stable has merged due to related change)
+ emit q->serviceDiscovered(serviceInfo);
+
+ // could stop discovery, check for state
+ if (discoveryState() == Inactive)
+ qCDebug(QT_BT_BLUEZ) << "Exit discovery after stop";
+ }
+ }
+
+ _q_serviceDiscoveryFinished();
+}
+
void QBluetoothServiceDiscoveryAgentPrivate::stop()
{
qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "Stop called";
@@ -186,6 +455,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_createdDevice(QDBusPendingCallWa
q, SLOT(_q_discoveredServices(QDBusPendingCallWatcher*)));
}
+// Bluez 4
void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingCallWatcher *watcher)
{
if (!device)
@@ -214,29 +484,13 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingC
qCDebug(QT_BT_BLUEZ) << "Parsing xml" << discoveredDevices.at(0).address().toString() << discoveredDevices.count() << map.count();
foreach (const QString &record, reply.value()) {
- QXmlStreamReader xml(record);
-
- QBluetoothServiceInfo serviceInfo;
- serviceInfo.setDevice(discoveredDevices.at(0));
-
- while (!xml.atEnd()) {
- xml.readNext();
-
- if (xml.tokenType() == QXmlStreamReader::StartElement &&
- xml.name() == QLatin1String("attribute")) {
- quint16 attributeId =
- xml.attributes().value(QStringLiteral("id")).toString().toUShort(0, 0);
-
- if (xml.readNextStartElement()) {
- QVariant value = readAttributeValue(xml);
-
- serviceInfo.setAttribute(attributeId, value);
- }
- }
- }
+ const QBluetoothServiceInfo serviceInfo = parseServiceXml(record);
if (!serviceInfo.isValid())
- continue;
+ return;
+
+ // Don't need to apply uuidFilter because Bluez 4 applies
+ // search pattern during DiscoverServices() call
Q_Q(QBluetoothServiceDiscoveryAgent);
@@ -254,15 +508,14 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingC
if (!alreadyDiscovered) {
discoveredServices.append(serviceInfo);
- qCDebug(QT_BT_BLUEZ) << "Discovered services" << discoveredDevices.at(0).address().toString();
+ qCDebug(QT_BT_BLUEZ) << "Discovered services" << discoveredDevices.at(0).address().toString()
+ << serviceInfo.serviceName();
emit q->serviceDiscovered(serviceInfo);
}
// could stop discovery, check for state
- if(discoveryState() == Inactive){
+ if (discoveryState() == Inactive)
qCDebug(QT_BT_BLUEZ) << "Exit discovery after stop";
- break;
- }
}
watcher->deleteLater();
@@ -272,6 +525,138 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingC
_q_serviceDiscoveryFinished();
}
+QBluetoothServiceInfo QBluetoothServiceDiscoveryAgentPrivate::parseServiceXml(const QString& xmlRecord)
+{
+ QXmlStreamReader xml(xmlRecord);
+
+ QBluetoothServiceInfo serviceInfo;
+ serviceInfo.setDevice(discoveredDevices.at(0));
+
+ while (!xml.atEnd()) {
+ xml.readNext();
+
+ if (xml.tokenType() == QXmlStreamReader::StartElement &&
+ xml.name() == QLatin1String("attribute")) {
+ quint16 attributeId =
+ xml.attributes().value(QLatin1String("id")).toString().toUShort(0, 0);
+
+ if (xml.readNextStartElement()) {
+ QVariant value = readAttributeValue(xml);
+
+ serviceInfo.setAttribute(attributeId, value);
+ }
+ }
+ }
+
+ return serviceInfo;
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(const QBluetoothAddress &deviceAddress)
+{
+ if (foundHostAdapterPath.isEmpty()) {
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+
+ QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects();
+ reply.waitForFinished();
+ if (reply.isError()) {
+ if (singleDevice) {
+ error = QBluetoothServiceDiscoveryAgent::InputOutputError;
+ errorString = reply.error().message();
+ emit q->error(error);
+
+ }
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
+ QStringList uuidStrings;
+ foreach (const QDBusObjectPath &path, reply.value().keys()) {
+ const InterfaceList ifaceList = reply.value().value(path);
+ foreach (const QString &iface, ifaceList.keys()) {
+ if (iface == QStringLiteral("org.bluez.Device1")) {
+ const QVariantMap details = ifaceList.value(iface);
+ if (deviceAddress.toString()
+ == details.value(QStringLiteral("Address")).toString()) {
+ uuidStrings = details.value(QStringLiteral("UUIDs")).toStringList();
+ break;
+
+ }
+ }
+ }
+ if (!uuidStrings.isEmpty())
+ break;
+ }
+
+ if (uuidStrings.isEmpty() || discoveredDevices.isEmpty()) {
+ // nothing found -> go to next uuid
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
+ qCDebug(QT_BT_BLUEZ) << "Minimal uuid list for" << deviceAddress.toString() << uuidStrings;
+
+ QBluetoothUuid uuid;
+ for (int i = 0; i < uuidStrings.count(); i++) {
+ uuid = QBluetoothUuid(uuidStrings.at(i));
+ if (uuid.isNull())
+ continue;
+
+ //apply uuidFilter
+ if (!uuidFilter.isEmpty() && !uuidFilter.contains(uuid))
+ continue;
+
+ bool isBaseUuid = false;
+ if (btBaseUuid()->data2 == uuid.data2 && btBaseUuid()->data3 == uuid.data3
+ && btBaseUuid()->data4[0] == uuid.data4[0] && btBaseUuid()->data4[1] == uuid.data4[1]
+ && btBaseUuid()->data4[2] == uuid.data4[2] && btBaseUuid()->data4[3] == uuid.data4[3]
+ && btBaseUuid()->data4[4] == uuid.data4[4] && btBaseUuid()->data4[5] == uuid.data4[5]
+ && btBaseUuid()->data4[6] == uuid.data4[6] && btBaseUuid()->data4[7] == uuid.data4[7])
+ {
+ isBaseUuid = true;
+ }
+
+ QBluetoothServiceInfo serviceInfo;
+ serviceInfo.setDevice(discoveredDevices.at(0));
+
+ if (!isBaseUuid) {
+ serviceInfo.setServiceUuid(uuid);
+ serviceInfo.setServiceName(QBluetoothServiceDiscoveryAgent::tr("Custom Service"));
+ } else {
+ // set uuid as service class id
+ QBluetoothServiceInfo::Sequence classId;
+ classId << QVariant::fromValue(uuid);
+ serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
+ QBluetoothUuid::ServiceClassUuid clsId
+ = static_cast<QBluetoothUuid::ServiceClassUuid>(uuid.data1 & 0xffff);
+ serviceInfo.setServiceName(QBluetoothUuid::serviceClassToString(clsId));
+ }
+
+ //don't include the service if we already discovered it before
+ bool alreadyDiscovered = false;
+ for (int j = 0; j < discoveredServices.count(); j++) {
+ const QBluetoothServiceInfo &info = discoveredServices.at(j);
+ if (info.device() == serviceInfo.device()
+ && info.serviceClassUuids() == serviceInfo.serviceClassUuids()
+ && info.serviceUuid() == serviceInfo.serviceUuid()) {
+ alreadyDiscovered = true;
+ break;
+ }
+ }
+
+ if (!alreadyDiscovered) {
+ discoveredServices << serviceInfo;
+ //qCDebug(QT_BT_ANDROID) << serviceInfo;
+ emit q->serviceDiscovered(serviceInfo);
+ }
+ }
+
+ _q_serviceDiscoveryFinished();
+}
+
QVariant QBluetoothServiceDiscoveryAgentPrivate::readAttributeValue(QXmlStreamReader &xml)
{
if (xml.name() == QLatin1String("boolean")) {
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
index d878869d..b3910a7e 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
@@ -53,6 +53,7 @@
class OrgBluezManagerInterface;
class OrgBluezAdapterInterface;
class OrgBluezDeviceInterface;
+class OrgFreedesktopDBusObjectManagerInterface;
QT_BEGIN_NAMESPACE
class QDBusPendingCallWatcher;
class QXmlStreamReader;
@@ -116,6 +117,9 @@ public:
#ifdef QT_BLUEZ_BLUETOOTH
void _q_discoveredServices(QDBusPendingCallWatcher *watcher);
void _q_createdDevice(QDBusPendingCallWatcher *watcher);
+ void _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::Error errorCode,
+ const QString &errorDescription,
+ const QStringList &xmlRecords);
#endif
#ifdef QT_ANDROID_BLUETOOTH
void _q_processFetchedUuids(const QBluetoothAddress &address, const QList<QBluetoothUuid> &uuids);
@@ -131,7 +135,12 @@ private:
void stop();
#ifdef QT_BLUEZ_BLUETOOTH
+ void startBluez5(const QBluetoothAddress &address);
+ void runSdpScan(const QBluetoothAddress &remoteAddress,
+ const QBluetoothAddress localAddress);
QVariant readAttributeValue(QXmlStreamReader &xml);
+ QBluetoothServiceInfo parseServiceXml(const QString& xml);
+ void performMinimalServiceDiscovery(const QBluetoothAddress &deviceAddress);
#endif
#ifdef QT_QNX_BLUETOOTH
@@ -170,7 +179,9 @@ private:
bool singleDevice;
#ifdef QT_BLUEZ_BLUETOOTH
+ QString foundHostAdapterPath;
OrgBluezManagerInterface *manager;
+ OrgFreedesktopDBusObjectManagerInterface *managerBluez5;
OrgBluezAdapterInterface *adapter;
OrgBluezDeviceInterface *device;
#endif
diff --git a/src/bluetooth/qbluetoothuuid.cpp b/src/bluetooth/qbluetoothuuid.cpp
index 85d48d49..91d0fc8b 100644
--- a/src/bluetooth/qbluetoothuuid.cpp
+++ b/src/bluetooth/qbluetoothuuid.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qbluetoothuuid.h"
+#include "qbluetoothservicediscoveryagent.h"
#include <QStringList>
#include <QtEndian>
@@ -364,6 +365,85 @@ quint128 QBluetoothUuid::toUInt128() const
}
/*!
+ Returns a human-readable and translated name for the given service class
+ represented by \a uuid.
+
+ \sa QBluetoothUuid::ServiceClassUuid
+ */
+QString QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid uuid)
+{
+ switch (uuid) {
+ case QBluetoothUuid::ServiceDiscoveryServer: return QBluetoothServiceDiscoveryAgent::tr("Service Discovery");
+ case QBluetoothUuid::BrowseGroupDescriptor: return QBluetoothServiceDiscoveryAgent::tr("Browse Group Descriptor");
+ case QBluetoothUuid::PublicBrowseGroup: return QBluetoothServiceDiscoveryAgent::tr("Public Browse Group");
+ case QBluetoothUuid::SerialPort: return QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile");
+ case QBluetoothUuid::LANAccessUsingPPP: return QBluetoothServiceDiscoveryAgent::tr("LAN Access Profile");
+ case QBluetoothUuid::DialupNetworking: return QBluetoothServiceDiscoveryAgent::tr("Dial-Up Networking");
+ case QBluetoothUuid::IrMCSync: return QBluetoothServiceDiscoveryAgent::tr("Synchronization");
+ case QBluetoothUuid::ObexObjectPush: return QBluetoothServiceDiscoveryAgent::tr("Object Push");
+ case QBluetoothUuid::OBEXFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("File Transfer");
+ case QBluetoothUuid::IrMCSyncCommand: return QBluetoothServiceDiscoveryAgent::tr("Synchronization Command");
+ case QBluetoothUuid::Headset: return QBluetoothServiceDiscoveryAgent::tr("Headset");
+ case QBluetoothUuid::AudioSource: return QBluetoothServiceDiscoveryAgent::tr("Audio Source");
+ case QBluetoothUuid::AudioSink: return QBluetoothServiceDiscoveryAgent::tr("Audio Sink");
+ case QBluetoothUuid::AV_RemoteControlTarget: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Target");
+ case QBluetoothUuid::AdvancedAudioDistribution: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution");
+ case QBluetoothUuid::AV_RemoteControl: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control");
+ case QBluetoothUuid::AV_RemoteControlController: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Controller");
+ case QBluetoothUuid::HeadsetAG: return QBluetoothServiceDiscoveryAgent::tr("Headset AG");
+ case QBluetoothUuid::PANU: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (PANU)");
+ case QBluetoothUuid::NAP: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (NAP)");
+ case QBluetoothUuid::GN: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (GN)");
+ case QBluetoothUuid::DirectPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Direct Printing (BPP)");
+ case QBluetoothUuid::ReferencePrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Reference Printing (BPP)");
+ case QBluetoothUuid::BasicImage: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Profile");
+ case QBluetoothUuid::ImagingResponder: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Responder");
+ case QBluetoothUuid::ImagingAutomaticArchive: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Archive");
+ case QBluetoothUuid::ImagingReferenceObjects: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Ref Objects");
+ case QBluetoothUuid::Handsfree: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free");
+ case QBluetoothUuid::HandsfreeAudioGateway: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free AG");
+ case QBluetoothUuid::DirectPrintingReferenceObjectsService: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing RefObject Service");
+ case QBluetoothUuid::ReflectedUI: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Reflected UI");
+ case QBluetoothUuid::BasicPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing");
+ case QBluetoothUuid::PrintingStatus: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Status");
+ case QBluetoothUuid::HumanInterfaceDeviceService: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device");
+ case QBluetoothUuid::HardcopyCableReplacement: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement");
+ case QBluetoothUuid::HCRPrint: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Print");
+ case QBluetoothUuid::HCRScan: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Scan");
+ case QBluetoothUuid::SIMAccess: return QBluetoothServiceDiscoveryAgent::tr("SIM Access Server");
+ case QBluetoothUuid::PhonebookAccessPCE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PCE");
+ case QBluetoothUuid::PhonebookAccessPSE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PSE");
+ case QBluetoothUuid::PhonebookAccess: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access");
+ case QBluetoothUuid::HeadsetHS: return QBluetoothServiceDiscoveryAgent::tr("Headset HS");
+ case QBluetoothUuid::MessageAccessServer: return QBluetoothServiceDiscoveryAgent::tr("Message Access Server");
+ case QBluetoothUuid::MessageNotificationServer: return QBluetoothServiceDiscoveryAgent::tr("Message Notification Server");
+ case QBluetoothUuid::MessageAccessProfile: return QBluetoothServiceDiscoveryAgent::tr("Message Access");
+ case QBluetoothUuid::GNSS: return QBluetoothServiceDiscoveryAgent::tr("Global Navigation Satellite System");
+ case QBluetoothUuid::GNSSServer: return QBluetoothServiceDiscoveryAgent::tr("Global Navigation Satellite System Server");
+ case QBluetoothUuid::Display3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization Display");
+ case QBluetoothUuid::Glasses3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization Glasses");
+ case QBluetoothUuid::Synchronization3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization");
+ case QBluetoothUuid::MPSProfile: return QBluetoothServiceDiscoveryAgent::tr("Multi-Profile Specification (Profile)");
+ case QBluetoothUuid::MPSService: return QBluetoothServiceDiscoveryAgent::tr("Multi-Profile Specification");
+ case QBluetoothUuid::PnPInformation: return QBluetoothServiceDiscoveryAgent::tr("Device Identification");
+ case QBluetoothUuid::GenericNetworking: return QBluetoothServiceDiscoveryAgent::tr("Generic Networking");
+ case QBluetoothUuid::GenericFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("Generic File Transfer");
+ case QBluetoothUuid::GenericAudio: return QBluetoothServiceDiscoveryAgent::tr("Generic Audio");
+ case QBluetoothUuid::GenericTelephony: return QBluetoothServiceDiscoveryAgent::tr("Generic Telephony");
+ case QBluetoothUuid::VideoSource: return QBluetoothServiceDiscoveryAgent::tr("Video Source");
+ case QBluetoothUuid::VideoSink: return QBluetoothServiceDiscoveryAgent::tr("Video Sink");
+ case QBluetoothUuid::VideoDistribution: return QBluetoothServiceDiscoveryAgent::tr("Video Distribution");
+ case QBluetoothUuid::HDP: return QBluetoothServiceDiscoveryAgent::tr("Health Device");
+ case QBluetoothUuid::HDPSource: return QBluetoothServiceDiscoveryAgent::tr("Health Device Source");
+ case QBluetoothUuid::HDPSink: return QBluetoothServiceDiscoveryAgent::tr("Health Device Sink");
+ default:
+ break;
+ }
+
+ return QString();
+}
+
+/*!
Returns true if \a other is equal to this Bluetooth UUID, otherwise false.
*/
bool QBluetoothUuid::operator==(const QBluetoothUuid &other) const
diff --git a/src/bluetooth/qbluetoothuuid.h b/src/bluetooth/qbluetoothuuid.h
index f33d8c13..46cff826 100644
--- a/src/bluetooth/qbluetoothuuid.h
+++ b/src/bluetooth/qbluetoothuuid.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
@@ -172,6 +172,8 @@ public:
quint16 toUInt16(bool *ok = 0) const;
quint32 toUInt32(bool *ok = 0) const;
quint128 toUInt128() const;
+
+ static QString serviceClassToString(ServiceClassUuid uuid);
};
#ifndef QT_NO_DEBUG_STREAM