Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtBluetooth module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qbluetoothservicediscoveryagent.h"
41#include "qbluetoothservicediscoveryagent_p.h"
42
43#ifdef CLASSIC_APP_BUILD
44#define Q_OS_WINRT
45#endif
46#include <qfunctions_winrt.h>
47#include <QtCore/QLoggingCategory>
48#include <QtCore/private/qeventdispatcher_winrt_p.h>
49
50#include <functional>
51#include <robuffer.h>
52#include <windows.devices.enumeration.h>
53#include <windows.devices.bluetooth.h>
54#include <windows.foundation.collections.h>
55#include <windows.networking.h>
56#include <windows.storage.streams.h>
57#include <wrl.h>
58
59using namespace Microsoft::WRL;
60using namespace Microsoft::WRL::Wrappers;
61using namespace ABI::Windows::Foundation;
62using namespace ABI::Windows::Foundation::Collections;
63using namespace ABI::Windows::Devices;
64using namespace ABI::Windows::Devices::Bluetooth;
65using namespace ABI::Windows::Devices::Bluetooth::Rfcomm;
66using namespace ABI::Windows::Devices::Enumeration;
67using namespace ABI::Windows::Storage::Streams;
68
69typedef Collections::IKeyValuePair<UINT32, IBuffer *> ValueItem;
70typedef Collections::IIterable<ValueItem *> ValueIterable;
71typedef Collections::IIterator<ValueItem *> ValueIterator;
72
73QT_BEGIN_NAMESPACE
74
75Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
76
77#define TYPE_UINT8 8
78#define TYPE_UINT16 9
79#define TYPE_UINT32 10
80#define TYPE_SHORT_UUID 25
81#define TYPE_LONG_UUID 28
82#define TYPE_STRING 37
83#define TYPE_SEQUENCE 53
84
85class QWinRTBluetoothServiceDiscoveryWorker : public QObject
86{
87 Q_OBJECT
88public:
89 explicit QWinRTBluetoothServiceDiscoveryWorker(quint64 targetAddress,
90 QBluetoothServiceDiscoveryAgent::DiscoveryMode mode);
91 ~QWinRTBluetoothServiceDiscoveryWorker();
92 void start();
93
94Q_SIGNALS:
95 void serviceFound(quint64 deviceAddress, const QBluetoothServiceInfo &info);
96 void scanFinished(quint64 deviceAddress);
97 void scanCanceled();
98 void errorOccured();
99
100private:
101 HRESULT onBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status);
102
103 void processServiceSearchResult(quint64 address, ComPtr<IVectorView<RfcommDeviceService*>> services);
104 QBluetoothServiceInfo::Sequence readSequence(ComPtr<IDataReader> dataReader, bool *ok, quint8 *bytesRead);
105
106private:
107 quint64 m_targetAddress;
108 QBluetoothServiceDiscoveryAgent::DiscoveryMode m_mode;
109};
110
111QWinRTBluetoothServiceDiscoveryWorker::QWinRTBluetoothServiceDiscoveryWorker(quint64 targetAddress,
112 QBluetoothServiceDiscoveryAgent::DiscoveryMode mode)
113 : m_targetAddress(targetAddress)
114 , m_mode(mode)
115{
116}
117
118QWinRTBluetoothServiceDiscoveryWorker::~QWinRTBluetoothServiceDiscoveryWorker()
119{
120}
121
122void QWinRTBluetoothServiceDiscoveryWorker::start()
123{
124 HRESULT hr;
125 hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
126 ComPtr<IBluetoothDeviceStatics> deviceStatics;
127 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics);
128 Q_ASSERT_SUCCEEDED(hr);
129 ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromAddressOperation;
130 hr = deviceStatics->FromBluetoothAddressAsync(m_targetAddress, &deviceFromAddressOperation);
131 Q_ASSERT_SUCCEEDED(hr);
132 hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
133 (this, &QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync).Get());
134 Q_ASSERT_SUCCEEDED(hr);
135 return S_OK;
136 });
137 Q_ASSERT_SUCCEEDED(hr);
138}
139
140HRESULT QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
141{
142 if (status != Completed) {
143 qCDebug(QT_BT_WINRT) << "Could not find device";
144 emit errorOccured();
145 return S_OK;
146 }
147
148 ComPtr<IBluetoothDevice> device;
149 HRESULT hr;
150 hr = op->GetResults(&device);
151 Q_ASSERT_SUCCEEDED(hr);
152 quint64 address;
153 device->get_BluetoothAddress(&address);
154
155#ifdef QT_WINRT_LIMITED_SERVICEDISCOVERY
156 if (m_mode != QBluetoothServiceDiscoveryAgent::MinimalDiscovery) {
157 qWarning() << "Used Windows SDK version (" << QString::number(QT_UCRTVERSION) << ") does not "
158 "support full service discovery. Consider updating to a more recent Windows 10 "
159 "SDK (14393 or above).";
160 }
161 ComPtr<IVectorView<RfcommDeviceService*>> commServices;
162 hr = device->get_RfcommServices(&commServices);
163 Q_ASSERT_SUCCEEDED(hr);
164 processServiceSearchResult(address, commServices);
165#else // !QT_WINRT_LIMITED_SERVICEDISOVERY
166 ComPtr<IBluetoothDevice3> device3;
167 hr = device.As(&device3);
168 Q_ASSERT_SUCCEEDED(hr);
169 ComPtr<IAsyncOperation<RfcommDeviceServicesResult *>> serviceOp;
170 const BluetoothCacheMode cacheMode = m_mode == QBluetoothServiceDiscoveryAgent::MinimalDiscovery
171 ? BluetoothCacheMode_Cached : BluetoothCacheMode_Uncached;
172 hr = device3->GetRfcommServicesWithCacheModeAsync(cacheMode, &serviceOp);
173 Q_ASSERT_SUCCEEDED(hr);
174 hr = serviceOp->put_Completed(Callback<IAsyncOperationCompletedHandler<RfcommDeviceServicesResult *>>
175 ([address, this](IAsyncOperation<RfcommDeviceServicesResult *> *op, AsyncStatus status)
176 {
177 if (status != Completed) {
178 qCDebug(QT_BT_WINRT) << "Could not obtain service list";
179 emit errorOccured();
180 return S_OK;
181 }
182
183 ComPtr<IRfcommDeviceServicesResult> result;
184 HRESULT hr = op->GetResults(&result);
185 Q_ASSERT_SUCCEEDED(hr);
186 ComPtr<IVectorView<RfcommDeviceService*>> commServices;
187 hr = result->get_Services(&commServices);
188 Q_ASSERT_SUCCEEDED(hr);
189 processServiceSearchResult(address, commServices);
190 return S_OK;
191 }).Get());
192 Q_ASSERT_SUCCEEDED(hr);
193#endif // !QT_WINRT_LIMITED_SERVICEDISOVERY
194
195 return S_OK;
196}
197
198void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 address, ComPtr<IVectorView<RfcommDeviceService*>> services)
199{
200 quint32 size;
201 HRESULT hr;
202 hr = services->get_Size(&size);
203 Q_ASSERT_SUCCEEDED(hr);
204 for (quint32 i = 0; i < size; ++i) {
205 ComPtr<IRfcommDeviceService> service;
206 hr = services->GetAt(i, &service);
207 Q_ASSERT_SUCCEEDED(hr);
208 HString name;
209 hr = service->get_ConnectionServiceName(name.GetAddressOf());
210 Q_ASSERT_SUCCEEDED(hr);
211 const QString serviceName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
212 ComPtr<ABI::Windows::Networking::IHostName> host;
213 hr = service->get_ConnectionHostName(host.GetAddressOf());
214 Q_ASSERT_SUCCEEDED(hr);
215 HString hostName;
216 hr = host->get_RawName(hostName.GetAddressOf());
217 Q_ASSERT_SUCCEEDED(hr);
218 const QString qHostName = QString::fromWCharArray(WindowsGetStringRawBuffer(hostName.Get(),
219 nullptr));
220 ComPtr<IRfcommServiceId> id;
221 hr = service->get_ServiceId(&id);
222 Q_ASSERT_SUCCEEDED(hr);
223 GUID guid;
224 hr = id->get_Uuid(&guid);
225 const QBluetoothUuid uuid(guid);
226 Q_ASSERT_SUCCEEDED(hr);
227
228 QBluetoothServiceInfo info;
229 info.setAttribute(0xBEEF, QVariant(qHostName));
230 info.setAttribute(0xBEF0, QVariant(serviceName));
231 info.setServiceName(serviceName);
232 info.setServiceUuid(uuid);
233 ComPtr<IAsyncOperation<IMapView<UINT32, IBuffer *> *>> op;
234 hr = service->GetSdpRawAttributesAsync(op.GetAddressOf());
235 if (FAILED(hr)) {
236 emit errorOccured();
237 qDebug() << "Check manifest capabilities";
238 continue;
239 }
240 ComPtr<IMapView<UINT32, IBuffer *>> mapView;
241 hr = QWinRTFunctions::await(op, mapView.GetAddressOf());
242 Q_ASSERT_SUCCEEDED(hr);
243 // TODO timeout
244 ComPtr<ValueIterable> iterable;
245 ComPtr<ValueIterator> iterator;
246
247 hr = mapView.As(&iterable);
248 if (FAILED(hr))
249 continue;
250
251 boolean current = false;
252 hr = iterable->First(&iterator);
253 if (FAILED(hr))
254 continue;
255 hr = iterator->get_HasCurrent(&current);
256 if (FAILED(hr))
257 continue;
258
259 while (SUCCEEDED(hr) && current) {
260 ComPtr<ValueItem> item;
261 hr = iterator->get_Current(&item);
262 if (FAILED(hr))
263 continue;
264
265 UINT32 key;
266 hr = item->get_Key(&key);
267 if (FAILED(hr))
268 continue;
269
270 ComPtr<IBuffer> buffer;
271 hr = item->get_Value(&buffer);
272 Q_ASSERT_SUCCEEDED(hr);
273
274 ComPtr<IDataReader> dataReader;
275 ComPtr<IDataReaderStatics> dataReaderStatics;
276 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(), &dataReaderStatics);
277 Q_ASSERT_SUCCEEDED(hr);
278 hr = dataReaderStatics->FromBuffer(buffer.Get(), dataReader.GetAddressOf());
279 Q_ASSERT_SUCCEEDED(hr);
280 BYTE type;
281 hr = dataReader->ReadByte(&type);
282 Q_ASSERT_SUCCEEDED(hr);
283 if (type == TYPE_UINT8) {
284 quint8 value;
285 hr = dataReader->ReadByte(&value);
286 Q_ASSERT_SUCCEEDED(hr);
287 info.setAttribute(key, value);
288 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UINT8" << hex << value;
289 } else if (type == TYPE_UINT16) {
290 quint16 value;
291 hr = dataReader->ReadUInt16(&value);
292 Q_ASSERT_SUCCEEDED(hr);
293 info.setAttribute(key, value);
294 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UINT16" << hex << value;
295 } else if (type == TYPE_UINT32) {
296 quint32 value;
297 hr = dataReader->ReadUInt32(&value);
298 Q_ASSERT_SUCCEEDED(hr);
299 info.setAttribute(key, value);
300 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UINT32" << hex << value;
301 } else if (type == TYPE_SHORT_UUID) {
302 quint16 value;
303 hr = dataReader->ReadUInt16(&value);
304 Q_ASSERT_SUCCEEDED(hr);
305 const QBluetoothUuid uuid(value);
306 info.setAttribute(key, uuid);
307 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UUID" << hex << uuid;
308 } else if (type == TYPE_LONG_UUID) {
309 GUID value;
310 hr = dataReader->ReadGuid(&value);
311 Q_ASSERT_SUCCEEDED(hr);
312 const QBluetoothUuid uuid(value);
313 info.setAttribute(key, uuid);
314 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "UUID" << hex << uuid;
315 } else if (type == TYPE_STRING) {
316 BYTE length;
317 hr = dataReader->ReadByte(&length);
318 Q_ASSERT_SUCCEEDED(hr);
319 HString value;
320 hr = dataReader->ReadString(length, value.GetAddressOf());
321 Q_ASSERT_SUCCEEDED(hr);
322 const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(), nullptr));
323 info.setAttribute(key, str);
324 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "STRING" << str;
325 } else if (type == TYPE_SEQUENCE) {
326 bool ok;
327 QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, &ok, nullptr);
328 if (ok) {
329 info.setAttribute(key, sequence);
330 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "SEQUENCE" << sequence;
331 } else {
332 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type << "SEQUENCE ERROR";
333 }
334 } else {
335 qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << hex << key << "TYPE" << dec << type;
336 }
337 hr = iterator->MoveNext(&current);
338 }
339 // Windows is only able to discover Rfcomm services but the according protocolDescriptor is
340 // not always set in the raw attribute map. If we encounter a service like that we should
341 // fill the protocol descriptor ourselves.
342 if (info.protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
343 QBluetoothServiceInfo::Sequence protocolDescriptorList;
344 QBluetoothServiceInfo::Sequence protocol;
345 protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
346 << QVariant::fromValue(0);
347 protocolDescriptorList.append(QVariant::fromValue(protocol));
348 info.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
349 }
350 emit serviceFound(address, info);
351 }
352 emit scanFinished(address);
353 deleteLater();
354}
355
356QBluetoothServiceInfo::Sequence QWinRTBluetoothServiceDiscoveryWorker::readSequence(ComPtr<IDataReader> dataReader, bool *ok, quint8 *bytesRead)
357{
358 if (ok)
359 *ok = false;
360 if (bytesRead)
361 *bytesRead = 0;
362 QBluetoothServiceInfo::Sequence result;
363 if (!dataReader)
364 return result;
365
366 quint8 remainingLength;
367 HRESULT hr = dataReader->ReadByte(&remainingLength);
368 Q_ASSERT_SUCCEEDED(hr);
369 if (bytesRead)
370 *bytesRead += 1;
371 BYTE type;
372 hr = dataReader->ReadByte(&type);
373 remainingLength -= 1;
374 if (bytesRead)
375 *bytesRead += 1;
376 Q_ASSERT_SUCCEEDED(hr);
377 while (true) {
378 switch (type) {
379 case TYPE_UINT8: {
380 quint8 value;
381 hr = dataReader->ReadByte(&value);
382 Q_ASSERT_SUCCEEDED(hr);
383 result.append(QVariant::fromValue(value));
384 remainingLength -= 1;
385 if (bytesRead)
386 *bytesRead += 1;
387 break;
388 }
389 case TYPE_UINT16: {
390 quint16 value;
391 hr = dataReader->ReadUInt16(&value);
392 Q_ASSERT_SUCCEEDED(hr);
393 result.append(QVariant::fromValue(value));
394 remainingLength -= 2;
395 if (bytesRead)
396 *bytesRead += 2;
397 break;
398 }
399 case TYPE_UINT32: {
400 quint32 value;
401 hr = dataReader->ReadUInt32(&value);
402 Q_ASSERT_SUCCEEDED(hr);
403 result.append(QVariant::fromValue(value));
404 remainingLength -= 4;
405 if (bytesRead)
406 *bytesRead += 4;
407 break;
408 }
409 case TYPE_SHORT_UUID: {
410 quint16 b;
411 hr = dataReader->ReadUInt16(&b);
412 Q_ASSERT_SUCCEEDED(hr);
413
414 const QBluetoothUuid uuid(b);
415 result.append(QVariant::fromValue(uuid));
416 remainingLength -= 2;
417 if (bytesRead)
418 *bytesRead += 2;
419 break;
420 }
421 case TYPE_LONG_UUID: {
422 GUID b;
423 hr = dataReader->ReadGuid(&b);
424 Q_ASSERT_SUCCEEDED(hr);
425
426 const QBluetoothUuid uuid(b);
427 result.append(QVariant::fromValue(uuid));
428 remainingLength -= sizeof(GUID);
429 if (bytesRead)
430 *bytesRead += sizeof(GUID);
431 break;
432 }
433 case TYPE_STRING: {
434 BYTE length;
435 hr = dataReader->ReadByte(&length);
436 Q_ASSERT_SUCCEEDED(hr);
437 remainingLength -= 1;
438 if (bytesRead)
439 *bytesRead += 1;
440 HString value;
441 hr = dataReader->ReadString(length, value.GetAddressOf());
442 Q_ASSERT_SUCCEEDED(hr);
443
444 const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(), nullptr));
445 result.append(QVariant::fromValue(str));
446 remainingLength -= length;
447 if (bytesRead)
448 *bytesRead += length;
449 break;
450 }
451 case TYPE_SEQUENCE: {
452 quint8 bytesR;
453 const QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, ok, &bytesR);
454 if (*ok)
455 result.append(QVariant::fromValue(sequence));
456 else
457 return result;
458 remainingLength -= bytesR;
459 if (bytesRead)
460 *bytesRead += bytesR;
461 break;
462 }
463 default:
464 qCDebug(QT_BT_WINRT) << "SEQUENCE ERROR" << type;
465 result.clear();
466 return result;
467 }
468 if (remainingLength == 0)
469 break;
470
471 hr = dataReader->ReadByte(&type);
472 Q_ASSERT_SUCCEEDED(hr);
473 remainingLength -= 1;
474 if (bytesRead)
475 *bytesRead += 1;
476 }
477
478 if (ok)
479 *ok = true;
480 return result;
481}
482
483QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
484 QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
485 : error(QBluetoothServiceDiscoveryAgent::NoError),
486 state(Inactive),
487 mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery),
488 singleDevice(false),
489 q_ptr(qp)
490{
491 // TODO: use local adapter for discovery. Possible?
492 Q_UNUSED(deviceAdapter);
493}
494
495QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
496{
497 stop();
498}
499
500void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
501{
502 if (worker)
503 return;
504
505 worker = new QWinRTBluetoothServiceDiscoveryWorker(address.toUInt64(), mode);
506
507 connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::serviceFound,
508 this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService, Qt::QueuedConnection);
509 connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
510 this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished, Qt::QueuedConnection);
511 connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanCanceled,
512 this, &QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled, Qt::QueuedConnection);
513 connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
514 this, &QBluetoothServiceDiscoveryAgentPrivate::onError, Qt::QueuedConnection);
515 worker->start();
516}
517
518void QBluetoothServiceDiscoveryAgentPrivate::stop()
519{
520 if (!worker)
521 return;
522
523 disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::serviceFound,
524 this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService);
525 disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
526 this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished);
527 disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanCanceled,
528 this, &QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled);
529 disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
530 this, &QBluetoothServiceDiscoveryAgentPrivate::onError);
531 // mWorker will delete itself as soon as it is done with its discovery
532 worker = nullptr;
533 setDiscoveryState(Inactive);
534}
535
536void QBluetoothServiceDiscoveryAgentPrivate::processFoundService(quint64 deviceAddress, const QBluetoothServiceInfo &info)
537{
538 Q_Q(QBluetoothServiceDiscoveryAgent);
539 //apply uuidFilter
540 if (!uuidFilter.isEmpty()) {
541 bool serviceNameMatched = uuidFilter.contains(info.serviceUuid());
542 bool serviceClassMatched = false;
543 const QList<QBluetoothUuid> serviceClassUuids
544 = info.serviceClassUuids();
545 for (const QBluetoothUuid &id : serviceClassUuids) {
546 if (uuidFilter.contains(id)) {
547 serviceClassMatched = true;
548 break;
549 }
550 }
551
552 if (!serviceNameMatched && !serviceClassMatched)
553 return;
554 }
555
556 if (!info.isValid())
557 return;
558
559 QBluetoothServiceInfo returnInfo(info);
560 bool deviceFound;
561 for (const QBluetoothDeviceInfo &deviceInfo : qAsConst(discoveredDevices)) {
562 if (deviceInfo.address().toUInt64() == deviceAddress) {
563 deviceFound = true;
564 returnInfo.setDevice(deviceInfo);
565 break;
566 }
567 }
568 Q_ASSERT(deviceFound);
569
570 if (!isDuplicatedService(returnInfo)) {
571 discoveredServices.append(returnInfo);
572 qCDebug(QT_BT_WINRT) << "Discovered services" << discoveredDevices.at(0).address().toString()
573 << returnInfo.serviceName() << returnInfo.serviceUuid()
574 << ">>>" << returnInfo.serviceClassUuids();
575
576 emit q->serviceDiscovered(returnInfo);
577 }
578}
579
580void QBluetoothServiceDiscoveryAgentPrivate::onScanFinished(quint64 deviceAddress)
581{
582 Q_Q(QBluetoothServiceDiscoveryAgent);
583 bool deviceFound;
584 for (const QBluetoothDeviceInfo &deviceInfo : qAsConst(discoveredDevices)) {
585 if (deviceInfo.address().toUInt64() == deviceAddress) {
586 deviceFound = true;
587 discoveredDevices.removeOne(deviceInfo);
588 if (discoveredDevices.isEmpty())
589 setDiscoveryState(Inactive);
590 break;
591 }
592 }
593 Q_ASSERT(deviceFound);
594 stop();
595 emit q->finished();
596}
597
598void QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled()
599{
600 Q_Q(QBluetoothServiceDiscoveryAgent);
601 emit q->canceled();
602}
603
604void QBluetoothServiceDiscoveryAgentPrivate::onError()
605{
606 Q_Q(QBluetoothServiceDiscoveryAgent);
607 discoveredDevices.clear();
608 error = QBluetoothServiceDiscoveryAgent::InputOutputError;
609 errorString = "errorDescription";
610 emit q->error(error);
611}
612
613QT_END_NAMESPACE
614
615#include <qbluetoothservicediscoveryagent_winrt.moc>
616

Warning: That file was not part of the compilation database. It may have many parsing errors.