summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp')
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp607
1 files changed, 607 insertions, 0 deletions
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
new file mode 100644
index 00000000..29ccb290
--- /dev/null
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
@@ -0,0 +1,607 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothservicediscoveryagent.h"
+#include "qbluetoothservicediscoveryagent_p.h"
+
+#include <qfunctions_winrt.h>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/private/qeventdispatcher_winrt_p.h>
+
+#include <functional>
+#include <robuffer.h>
+#include <windows.devices.enumeration.h>
+#include <windows.devices.bluetooth.h>
+#include <windows.foundation.collections.h>
+#include <windows.storage.streams.h>
+#include <wrl.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Devices;
+using namespace ABI::Windows::Devices::Bluetooth;
+using namespace ABI::Windows::Devices::Bluetooth::Rfcomm;
+using namespace ABI::Windows::Devices::Enumeration;
+using namespace ABI::Windows::Storage::Streams;
+
+typedef Collections::IKeyValuePair<UINT32, IBuffer *> ValueItem;
+typedef Collections::IIterable<ValueItem *> ValueIterable;
+typedef Collections::IIterator<ValueItem *> ValueIterator;
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+
+#define TYPE_UINT8 8
+#define TYPE_UINT16 9
+#define TYPE_UINT32 10
+#define TYPE_SHORT_UUID 25
+#define TYPE_LONG_UUID 28
+#define TYPE_STRING 37
+#define TYPE_SEQUENCE 53
+
+static QByteArray byteArrayFromBuffer(const ComPtr<IBuffer> &buffer, bool isWCharString = false)
+{
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
+ HRESULT hr = buffer.As(&byteAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ char *data;
+ hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
+ Q_ASSERT_SUCCEEDED(hr);
+ UINT32 size;
+ hr = buffer->get_Length(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (isWCharString) {
+ QString valueString = QString::fromUtf16(reinterpret_cast<ushort *>(data)).left(size / 2);
+ return valueString.toUtf8();
+ }
+ return QByteArray(data, size);
+}
+
+class QWinRTBluetoothServiceDiscoveryWorker : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QWinRTBluetoothServiceDiscoveryWorker(quint64 targetAddress,
+ QBluetoothServiceDiscoveryAgent::DiscoveryMode mode);
+ ~QWinRTBluetoothServiceDiscoveryWorker();
+ void start();
+
+Q_SIGNALS:
+ void serviceFound(quint64 deviceAddress, const QBluetoothServiceInfo &info);
+ void scanFinished(quint64 deviceAddress);
+ void scanCanceled();
+ void errorOccured();
+
+private:
+ HRESULT onBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status);
+
+ void processServiceSearchResult(quint64 address, ComPtr<IVectorView<RfcommDeviceService*>> services);
+ QBluetoothServiceInfo::Sequence readSequence(ComPtr<IDataReader> dataReader, bool *ok, quint8 *bytesRead);
+
+private:
+ quint64 m_targetAddress;
+ QBluetoothServiceDiscoveryAgent::DiscoveryMode m_mode;
+};
+
+QWinRTBluetoothServiceDiscoveryWorker::QWinRTBluetoothServiceDiscoveryWorker(quint64 targetAddress,
+ QBluetoothServiceDiscoveryAgent::DiscoveryMode mode)
+ : m_targetAddress(targetAddress)
+ , m_mode(mode)
+{
+}
+
+QWinRTBluetoothServiceDiscoveryWorker::~QWinRTBluetoothServiceDiscoveryWorker()
+{
+}
+
+void QWinRTBluetoothServiceDiscoveryWorker::start()
+{
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
+ ComPtr<IBluetoothDeviceStatics> deviceStatics;
+ HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromAddressOperation;
+ hr = deviceStatics->FromBluetoothAddressAsync(m_targetAddress, &deviceFromAddressOperation);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
+ (this, &QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+HRESULT QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
+{
+ if (status != Completed) {
+ qCDebug(QT_BT_WINRT) << "Could not find device";
+ emit errorOccured();
+ return S_OK;
+ }
+
+ ComPtr<IBluetoothDevice> device;
+ HRESULT hr;
+ hr = op->GetResults(&device);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint64 address;
+ device->get_BluetoothAddress(&address);
+
+#ifdef QT_WINRT_LIMITED_SERVICEDISCOVERY
+ if (m_mode != QBluetoothServiceDiscoveryAgent::MinimalDiscovery) {
+ qWarning() << "Used Windows SDK version (" << QString::number(QT_UCRTVERSION) << ") does not "
+ "support full service discovery. Consider updating to a more recent Windows 10 "
+ "SDK (14393 or above).";
+ }
+ ComPtr<IVectorView<RfcommDeviceService*>> commServices;
+ hr = device->get_RfcommServices(&commServices);
+ Q_ASSERT_SUCCEEDED(hr);
+ processServiceSearchResult(address, commServices);
+#else // !QT_WINRT_LIMITED_SERVICEDISOVERY
+ ComPtr<IBluetoothDevice3> device3;
+ hr = device.As(&device3);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<RfcommDeviceServicesResult *>> serviceOp;
+ const BluetoothCacheMode cacheMode = m_mode == QBluetoothServiceDiscoveryAgent::MinimalDiscovery
+ ? BluetoothCacheMode_Cached : BluetoothCacheMode_Uncached;
+ hr = device3->GetRfcommServicesWithCacheModeAsync(cacheMode, &serviceOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = serviceOp->put_Completed(Callback<IAsyncOperationCompletedHandler<RfcommDeviceServicesResult *>>
+ ([address, this](IAsyncOperation<RfcommDeviceServicesResult *> *op, AsyncStatus status)
+ {
+ if (status != Completed) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain service list";
+ emit errorOccured();
+ return S_OK;
+ }
+
+ ComPtr<IRfcommDeviceServicesResult> result;
+ HRESULT hr = op->GetResults(&result);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<RfcommDeviceService*>> commServices;
+ hr = result->get_Services(&commServices);
+ Q_ASSERT_SUCCEEDED(hr);
+ processServiceSearchResult(address, commServices);
+ return S_OK;
+ }).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+#endif // !QT_WINRT_LIMITED_SERVICEDISOVERY
+
+ return S_OK;
+}
+
+void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 address, ComPtr<IVectorView<RfcommDeviceService*>> services)
+{
+ quint32 size;
+ HRESULT hr;
+ hr = services->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint32 i = 0; i < size; ++i) {
+ ComPtr<IRfcommDeviceService> service;
+ hr = services->GetAt(i, &service);
+ Q_ASSERT_SUCCEEDED(hr);
+ HString name;
+ hr = service->get_ConnectionServiceName(name.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ const QString serviceName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
+ ComPtr<IRfcommServiceId> id;
+ hr = service->get_ServiceId(&id);
+ Q_ASSERT_SUCCEEDED(hr);
+ GUID guid;
+ hr = id->get_Uuid(&guid);
+ const QBluetoothUuid uuid(guid);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ QBluetoothServiceInfo info;
+ info.setServiceName(serviceName);
+ info.setServiceUuid(uuid);
+ ComPtr<IAsyncOperation<IMapView<UINT32, IBuffer *> *>> op;
+ hr = service->GetSdpRawAttributesAsync(op.GetAddressOf());
+ if (FAILED(hr)) {
+ emit errorOccured();
+ qDebug() << "Check manifest capabilities";
+ continue;
+ }
+ ComPtr<IMapView<UINT32, IBuffer *>> mapView;
+ hr = QWinRTFunctions::await(op, mapView.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ // TODO timeout
+ ComPtr<ValueIterable> iterable;
+ ComPtr<ValueIterator> iterator;
+
+ hr = mapView.As(&iterable);
+ if (FAILED(hr))
+ continue;
+
+ boolean current = false;
+ hr = iterable->First(&iterator);
+ if (FAILED(hr))
+ continue;
+ hr = iterator->get_HasCurrent(&current);
+ if (FAILED(hr))
+ continue;
+
+ while (SUCCEEDED(hr) && current) {
+ ComPtr<ValueItem> item;
+ hr = iterator->get_Current(&item);
+ if (FAILED(hr))
+ continue;
+
+ UINT32 key;
+ hr = item->get_Key(&key);
+ if (FAILED(hr))
+ continue;
+
+ ComPtr<IBuffer> buffer;
+ hr = item->get_Value(&buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IDataReader> dataReader;
+ ComPtr<IDataReaderStatics> dataReaderStatics;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(), &dataReaderStatics);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = dataReaderStatics->FromBuffer(buffer.Get(), dataReader.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ BYTE type;
+ hr = dataReader->ReadByte(&type);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (type == TYPE_UINT8) {
+ quint8 value;
+ hr = dataReader->ReadByte(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ info.setAttribute(key, value);
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UINT8" << hex << value;
+ } else if (type == TYPE_UINT16) {
+ quint16 value;
+ hr = dataReader->ReadUInt16(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ info.setAttribute(key, value);
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UINT16" << hex << value;
+ } else if (type == TYPE_UINT32) {
+ quint32 value;
+ hr = dataReader->ReadUInt32(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ info.setAttribute(key, value);
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UINT32" << hex << value;
+ } else if (type == TYPE_SHORT_UUID) {
+ quint16 value;
+ hr = dataReader->ReadUInt16(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QBluetoothUuid uuid(value);
+ info.setAttribute(key, uuid);
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UUID" << hex << uuid;
+ } else if (type == TYPE_LONG_UUID) {
+ GUID value;
+ hr = dataReader->ReadGuid(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QBluetoothUuid uuid(value);
+ info.setAttribute(key, uuid);
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UUID" << hex << uuid;
+ } else if (type == TYPE_STRING) {
+ BYTE length;
+ hr = dataReader->ReadByte(&length);
+ Q_ASSERT_SUCCEEDED(hr);
+ HString value;
+ hr = dataReader->ReadString(length, value.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(), nullptr));
+ info.setAttribute(key, str);
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "STRING" << str;
+ } else if (type == TYPE_SEQUENCE) {
+ bool ok;
+ QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, &ok, nullptr);
+ if (ok) {
+ info.setAttribute(key, sequence);
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "SEQUENCE" << sequence;
+ } else {
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "SEQUENCE ERROR";
+ }
+ } else {
+ qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type;
+ }
+ hr = iterator->MoveNext(&current);
+ }
+ emit serviceFound(address, info);
+ }
+ emit scanFinished(address);
+ deleteLater();
+}
+
+QBluetoothServiceInfo::Sequence QWinRTBluetoothServiceDiscoveryWorker::readSequence(ComPtr<IDataReader> dataReader, bool *ok, quint8 *bytesRead)
+{
+ if (ok)
+ *ok = false;
+ if (bytesRead)
+ *bytesRead = 0;
+ QBluetoothServiceInfo::Sequence result;
+ if (!dataReader)
+ return result;
+
+ quint8 remainingLength;
+ HRESULT hr = dataReader->ReadByte(&remainingLength);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (bytesRead)
+ *bytesRead += 1;
+ BYTE type;
+ hr = dataReader->ReadByte(&type);
+ remainingLength -= 1;
+ if (bytesRead)
+ *bytesRead += 1;
+ Q_ASSERT_SUCCEEDED(hr);
+ while (true) {
+ switch (type) {
+ case TYPE_UINT8: {
+ quint8 value;
+ hr = dataReader->ReadByte(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.append(QVariant::fromValue(value));
+ remainingLength -= 1;
+ if (bytesRead)
+ *bytesRead += 1;
+ break;
+ }
+ case TYPE_UINT16: {
+ quint16 value;
+ hr = dataReader->ReadUInt16(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.append(QVariant::fromValue(value));
+ remainingLength -= 2;
+ if (bytesRead)
+ *bytesRead += 2;
+ break;
+ }
+ case TYPE_UINT32: {
+ quint32 value;
+ hr = dataReader->ReadUInt32(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ result.append(QVariant::fromValue(value));
+ remainingLength -= 4;
+ if (bytesRead)
+ *bytesRead += 4;
+ break;
+ }
+ case TYPE_SHORT_UUID: {
+ quint16 b;
+ hr = dataReader->ReadUInt16(&b);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ const QBluetoothUuid uuid(b);
+ result.append(QVariant::fromValue(uuid));
+ remainingLength -= 2;
+ if (bytesRead)
+ *bytesRead += 2;
+ break;
+ }
+ case TYPE_LONG_UUID: {
+ GUID b;
+ hr = dataReader->ReadGuid(&b);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ const QBluetoothUuid uuid(b);
+ result.append(QVariant::fromValue(uuid));
+ remainingLength -= sizeof(GUID);
+ if (bytesRead)
+ *bytesRead += sizeof(GUID);
+ break;
+ }
+ case TYPE_STRING: {
+ BYTE length;
+ hr = dataReader->ReadByte(&length);
+ Q_ASSERT_SUCCEEDED(hr);
+ remainingLength -= 1;
+ if (bytesRead)
+ *bytesRead += 1;
+ HString value;
+ hr = dataReader->ReadString(length, value.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(), nullptr));
+ result.append(QVariant::fromValue(str));
+ remainingLength -= length;
+ if (bytesRead)
+ *bytesRead += length;
+ break;
+ }
+ case TYPE_SEQUENCE: {
+ quint8 bytesR;
+ const QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, ok, &bytesR);
+ if (*ok)
+ result.append(QVariant::fromValue(sequence));
+ else
+ return result;
+ remainingLength -= bytesR;
+ if (bytesRead)
+ *bytesRead += bytesR;
+ break;
+ }
+ default:
+ qCDebug(QT_BT_WINRT) << "SEQUENCE ERROR" << type;
+ result.clear();
+ return result;
+ }
+ if (remainingLength == 0)
+ break;
+
+ hr = dataReader->ReadByte(&type);
+ Q_ASSERT_SUCCEEDED(hr);
+ remainingLength -= 1;
+ if (bytesRead)
+ *bytesRead += 1;
+ }
+
+ if (ok)
+ *ok = true;
+ return result;
+}
+
+QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
+ QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
+ : error(QBluetoothServiceDiscoveryAgent::NoError),
+ state(Inactive),
+ deviceDiscoveryAgent(0),
+ mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery),
+ singleDevice(false),
+ q_ptr(qp)
+{
+ // TODO: use local adapter for discovery. Possible?
+ Q_UNUSED(deviceAdapter);
+}
+
+QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
+{
+ stop();
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
+{
+ if (worker)
+ return;
+
+ worker = new QWinRTBluetoothServiceDiscoveryWorker(address.toUInt64(), mode);
+
+ connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::serviceFound,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService, Qt::QueuedConnection);
+ connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished, Qt::QueuedConnection);
+ connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanCanceled,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled, Qt::QueuedConnection);
+ connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::onError, Qt::QueuedConnection);
+ worker->start();
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::stop()
+{
+ if (!worker)
+ return;
+
+ disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::serviceFound,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService);
+ disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished);
+ disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanCanceled,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled);
+ disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::onError);
+ // mWorker will delete itself as soon as it is done with its discovery
+ worker = nullptr;
+ setDiscoveryState(Inactive);
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::processFoundService(quint64 deviceAddress, const QBluetoothServiceInfo &info)
+{
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ //apply uuidFilter
+ if (!uuidFilter.isEmpty()) {
+ bool serviceNameMatched = uuidFilter.contains(info.serviceUuid());
+ bool serviceClassMatched = false;
+ for (const QBluetoothUuid &id : info.serviceClassUuids()) {
+ if (uuidFilter.contains(id)) {
+ serviceClassMatched = true;
+ break;
+ }
+ }
+
+ if (!serviceNameMatched && !serviceClassMatched)
+ return;
+ }
+
+ if (!info.isValid())
+ return;
+
+ QBluetoothServiceInfo returnInfo(info);
+ bool deviceFound;
+ for (const QBluetoothDeviceInfo &deviceInfo : discoveredDevices) {
+ if (deviceInfo.address().toUInt64() == deviceAddress) {
+ deviceFound = true;
+ returnInfo.setDevice(deviceInfo);
+ break;
+ }
+ }
+ Q_ASSERT(deviceFound);
+
+ if (!isDuplicatedService(returnInfo)) {
+ discoveredServices.append(returnInfo);
+ qCDebug(QT_BT_WINRT) << "Discovered services" << discoveredDevices.at(0).address().toString()
+ << returnInfo.serviceName() << returnInfo.serviceUuid()
+ << ">>>" << returnInfo.serviceClassUuids();
+
+ emit q->serviceDiscovered(returnInfo);
+ }
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::onScanFinished(quint64 deviceAddress)
+{
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ bool deviceFound;
+ for (const QBluetoothDeviceInfo &deviceInfo : discoveredDevices) {
+ if (deviceInfo.address().toUInt64() == deviceAddress) {
+ deviceFound = true;
+ discoveredDevices.removeOne(deviceInfo);
+ if (discoveredDevices.isEmpty())
+ setDiscoveryState(Inactive);
+ break;
+ }
+ }
+ Q_ASSERT(deviceFound);
+ stop();
+ emit q->finished();
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled()
+{
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ emit q->canceled();
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::onError()
+{
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ discoveredDevices.clear();
+ error = QBluetoothServiceDiscoveryAgent::InputOutputError;
+ errorString = "errorDescription";
+ emit q->error(error);
+}
+
+QT_END_NAMESPACE
+
+#include <qbluetoothservicediscoveryagent_winrt.moc>