summaryrefslogtreecommitdiffstats
path: root/src
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 /src
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>
Diffstat (limited to 'src')
-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