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 "qbluetoothdevicediscoveryagent.h" |
41 | #include "qbluetoothdevicediscoveryagent_p.h" |
42 | #include "qbluetoothaddress.h" |
43 | #include "qbluetoothuuid.h" |
44 | |
45 | #ifdef CLASSIC_APP_BUILD |
46 | #define Q_OS_WINRT |
47 | #endif |
48 | #include "qfunctions_winrt.h" |
49 | |
50 | #include <QtBluetooth/private/qtbluetoothglobal_p.h> |
51 | #include <QtBluetooth/private/qbluetoothutils_winrt_p.h> |
52 | #include <QtCore/QLoggingCategory> |
53 | #include <QtCore/private/qeventdispatcher_winrt_p.h> |
54 | |
55 | #include <robuffer.h> |
56 | #include <wrl.h> |
57 | #include <windows.devices.enumeration.h> |
58 | #include <windows.devices.bluetooth.h> |
59 | #include <windows.foundation.collections.h> |
60 | #include <windows.storage.streams.h> |
61 | |
62 | #include <windows.devices.bluetooth.advertisement.h> |
63 | |
64 | using namespace Microsoft::WRL; |
65 | using namespace Microsoft::WRL::Wrappers; |
66 | using namespace ABI::Windows::Foundation; |
67 | using namespace ABI::Windows::Foundation::Collections; |
68 | using namespace ABI::Windows::Devices; |
69 | using namespace ABI::Windows::Devices::Bluetooth; |
70 | using namespace ABI::Windows::Devices::Bluetooth::Advertisement; |
71 | using namespace ABI::Windows::Devices::Enumeration; |
72 | using namespace ABI::Windows::Storage::Streams; |
73 | |
74 | QT_BEGIN_NAMESPACE |
75 | |
76 | Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT) |
77 | |
78 | #define WARN_AND_RETURN_IF_FAILED(msg, ret) \ |
79 | if (FAILED(hr)) { \ |
80 | qCWarning(QT_BT_WINRT) << msg; \ |
81 | ret; \ |
82 | } |
83 | |
84 | #define WARN_AND_CONTINUE_IF_FAILED(msg) \ |
85 | if (FAILED(hr)) { \ |
86 | qCWarning(QT_BT_WINRT) << msg; \ |
87 | continue; \ |
88 | } |
89 | |
90 | static ManufacturerData extractManufacturerData(ComPtr<IBluetoothLEAdvertisement> ad) |
91 | { |
92 | ManufacturerData ret; |
93 | ComPtr<IVector<BluetoothLEManufacturerData*>> data; |
94 | HRESULT hr = ad->get_ManufacturerData(&data); |
95 | WARN_AND_RETURN_IF_FAILED("Could not obtain list of manufacturer data.", return ret); |
96 | quint32 size; |
97 | hr = data->get_Size(&size); |
98 | WARN_AND_RETURN_IF_FAILED("Could not obtain manufacturer data's list size.", return ret); |
99 | for (quint32 i = 0; i < size; ++i) { |
100 | ComPtr<IBluetoothLEManufacturerData> d; |
101 | hr = data->GetAt(i, &d); |
102 | WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data."); |
103 | quint16 id; |
104 | hr = d->get_CompanyId(&id); |
105 | WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data company id."); |
106 | ComPtr<IBuffer> buffer; |
107 | hr = d->get_Data(&buffer); |
108 | WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data set."); |
109 | const QByteArray bufferData = byteArrayFromBuffer(buffer); |
110 | if (ret.contains(id)) |
111 | qCWarning(QT_BT_WINRT) << "Company ID already present in manufacturer data."; |
112 | ret.insert(id, bufferData); |
113 | } |
114 | return ret; |
115 | } |
116 | |
117 | class QWinRTBluetoothDeviceDiscoveryWorker : public QObject |
118 | { |
119 | Q_OBJECT |
120 | public: |
121 | explicit QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods); |
122 | ~QWinRTBluetoothDeviceDiscoveryWorker(); |
123 | void start(); |
124 | void stopLEWatcher(); |
125 | |
126 | private: |
127 | void startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode); |
128 | void onDeviceDiscoveryFinished(IAsyncOperation<DeviceInformationCollection *> *op, |
129 | QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode); |
130 | void gatherDeviceInformation(IDeviceInformation *deviceInfo, |
131 | QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode); |
132 | void gatherMultipleDeviceInformation(quint32 deviceCount, IVectorView<DeviceInformation *> *devices, |
133 | QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode); |
134 | void setupLEDeviceWatcher(); |
135 | void classicBluetoothInfoFromDeviceIdAsync(HSTRING deviceId); |
136 | void leBluetoothInfoFromDeviceIdAsync(HSTRING deviceId); |
137 | void leBluetoothInfoFromAddressAsync(quint64 address); |
138 | HRESULT onPairedClassicBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status ); |
139 | HRESULT onPairedBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status); |
140 | HRESULT onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status); |
141 | enum PairingCheck { |
142 | CheckForPairing, |
143 | OmitPairingCheck |
144 | }; |
145 | HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device, PairingCheck pairingCheck); |
146 | #if QT_CONFIG(winrt_btle_no_pairing) |
147 | HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device); |
148 | #endif |
149 | |
150 | public slots: |
151 | void finishDiscovery(); |
152 | |
153 | Q_SIGNALS: |
154 | void deviceFound(const QBluetoothDeviceInfo &info); |
155 | void deviceDataChanged(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields, |
156 | qint16 rssi, ManufacturerData manufacturerData); |
157 | void scanFinished(); |
158 | |
159 | public: |
160 | quint8 requestedModes; |
161 | |
162 | private: |
163 | ComPtr<IBluetoothLEAdvertisementWatcher> m_leWatcher; |
164 | EventRegistrationToken m_leDeviceAddedToken; |
165 | #if QT_CONFIG(winrt_btle_no_pairing) |
166 | QMutex m_foundDevicesMutex; |
167 | struct LEAdvertisingInfo { |
168 | QVector<QBluetoothUuid> services; |
169 | qint16 rssi = 0; |
170 | }; |
171 | |
172 | QMap<quint64, LEAdvertisingInfo> m_foundLEDevicesMap; |
173 | #endif |
174 | QMap<quint64, qint16> m_foundLEDevices; |
175 | QMap<quint64, ManufacturerData> m_foundLEManufacturerData; |
176 | int m_pendingPairedDevices; |
177 | |
178 | ComPtr<IBluetoothDeviceStatics> m_deviceStatics; |
179 | ComPtr<IBluetoothLEDeviceStatics> m_leDeviceStatics; |
180 | }; |
181 | |
182 | QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods) |
183 | : requestedModes(methods) |
184 | , m_pendingPairedDevices(0) |
185 | { |
186 | qRegisterMetaType<QBluetoothDeviceInfo>(); |
187 | qRegisterMetaType<QBluetoothDeviceInfo::Fields>(); |
188 | qRegisterMetaType<ManufacturerData>(); |
189 | |
190 | #ifdef CLASSIC_APP_BUILD |
191 | CoInitialize(NULL); |
192 | #endif |
193 | HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &m_deviceStatics); |
194 | Q_ASSERT_SUCCEEDED(hr); |
195 | hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &m_leDeviceStatics); |
196 | Q_ASSERT_SUCCEEDED(hr); |
197 | } |
198 | |
199 | QWinRTBluetoothDeviceDiscoveryWorker::~QWinRTBluetoothDeviceDiscoveryWorker() |
200 | { |
201 | stopLEWatcher(); |
202 | #ifdef CLASSIC_APP_BUILD |
203 | CoUninitialize(); |
204 | #endif |
205 | } |
206 | |
207 | void QWinRTBluetoothDeviceDiscoveryWorker::start() |
208 | { |
209 | QEventDispatcherWinRT::runOnXamlThread([this]() { |
210 | if (requestedModes & QBluetoothDeviceDiscoveryAgent::ClassicMethod) |
211 | startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::ClassicMethod); |
212 | |
213 | if (requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) { |
214 | startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); |
215 | setupLEDeviceWatcher(); |
216 | } |
217 | return S_OK; |
218 | }); |
219 | |
220 | qCDebug(QT_BT_WINRT) << "Worker started"; |
221 | } |
222 | |
223 | void QWinRTBluetoothDeviceDiscoveryWorker::stopLEWatcher() |
224 | { |
225 | if (m_leWatcher) { |
226 | HRESULT hr = m_leWatcher->Stop(); |
227 | Q_ASSERT_SUCCEEDED(hr); |
228 | if (m_leDeviceAddedToken.value) { |
229 | hr = m_leWatcher->remove_Received(m_leDeviceAddedToken); |
230 | Q_ASSERT_SUCCEEDED(hr); |
231 | } |
232 | } |
233 | } |
234 | |
235 | void QWinRTBluetoothDeviceDiscoveryWorker::startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode) |
236 | { |
237 | HString deviceSelector; |
238 | ComPtr<IDeviceInformationStatics> deviceInformationStatics; |
239 | HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &deviceInformationStatics); |
240 | WARN_AND_RETURN_IF_FAILED("Could not obtain device information statics", return); |
241 | if (mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) |
242 | m_leDeviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf()); |
243 | else |
244 | m_deviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf()); |
245 | ComPtr<IAsyncOperation<DeviceInformationCollection *>> op; |
246 | hr = deviceInformationStatics->FindAllAsyncAqsFilter(deviceSelector.Get(), &op); |
247 | WARN_AND_RETURN_IF_FAILED("Could not start bluetooth device discovery operation", return); |
248 | QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this); |
249 | hr = op->put_Completed( |
250 | Callback<IAsyncOperationCompletedHandler<DeviceInformationCollection *>>([thisPointer, mode](IAsyncOperation<DeviceInformationCollection *> *op, AsyncStatus status) { |
251 | if (status == Completed && thisPointer) |
252 | thisPointer->onDeviceDiscoveryFinished(op, mode); |
253 | return S_OK; |
254 | }).Get()); |
255 | WARN_AND_RETURN_IF_FAILED("Could not add callback to bluetooth device discovery operation", return); |
256 | } |
257 | |
258 | void QWinRTBluetoothDeviceDiscoveryWorker::onDeviceDiscoveryFinished(IAsyncOperation<DeviceInformationCollection *> *op, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode) |
259 | { |
260 | qCDebug(QT_BT_WINRT) << (mode == QBluetoothDeviceDiscoveryAgent::ClassicMethod ? "BT": "BTLE") |
261 | << " scan completed"; |
262 | ComPtr<IVectorView<DeviceInformation *>> devices; |
263 | HRESULT hr; |
264 | hr = op->GetResults(&devices); |
265 | Q_ASSERT_SUCCEEDED(hr); |
266 | quint32 deviceCount; |
267 | hr = devices->get_Size(&deviceCount); |
268 | Q_ASSERT_SUCCEEDED(hr); |
269 | |
270 | // For classic discovery only paired devices will be found. If we only do classic disovery and |
271 | // no device is found, the scan is finished. |
272 | if (requestedModes == QBluetoothDeviceDiscoveryAgent::ClassicMethod && |
273 | deviceCount == 0) { |
274 | finishDiscovery(); |
275 | return; |
276 | } |
277 | |
278 | m_pendingPairedDevices += deviceCount; |
279 | gatherMultipleDeviceInformation(deviceCount, devices.Get(), mode); |
280 | } |
281 | |
282 | void QWinRTBluetoothDeviceDiscoveryWorker::gatherDeviceInformation(IDeviceInformation *deviceInfo, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode) |
283 | { |
284 | HString deviceId; |
285 | HRESULT hr; |
286 | hr = deviceInfo->get_Id(deviceId.GetAddressOf()); |
287 | Q_ASSERT_SUCCEEDED(hr); |
288 | if (mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) |
289 | leBluetoothInfoFromDeviceIdAsync(deviceId.Get()); |
290 | else |
291 | classicBluetoothInfoFromDeviceIdAsync(deviceId.Get()); |
292 | } |
293 | |
294 | void QWinRTBluetoothDeviceDiscoveryWorker::gatherMultipleDeviceInformation(quint32 deviceCount, IVectorView<DeviceInformation *> *devices, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode) |
295 | { |
296 | for (quint32 i = 0; i < deviceCount; ++i) { |
297 | ComPtr<IDeviceInformation> device; |
298 | HRESULT hr; |
299 | hr = devices->GetAt(i, &device); |
300 | Q_ASSERT_SUCCEEDED(hr); |
301 | gatherDeviceInformation(device.Get(), mode); |
302 | } |
303 | } |
304 | |
305 | void QWinRTBluetoothDeviceDiscoveryWorker::setupLEDeviceWatcher() |
306 | { |
307 | HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_Advertisement_BluetoothLEAdvertisementWatcher).Get(), &m_leWatcher); |
308 | Q_ASSERT_SUCCEEDED(hr); |
309 | #if QT_CONFIG(winrt_btle_no_pairing) |
310 | if (supportsNewLEApi()) { |
311 | hr = m_leWatcher->put_ScanningMode(BluetoothLEScanningMode_Active); |
312 | Q_ASSERT_SUCCEEDED(hr); |
313 | } |
314 | #endif // winrt_btle_no_pairing |
315 | hr = m_leWatcher->add_Received(Callback<ITypedEventHandler<BluetoothLEAdvertisementWatcher *, BluetoothLEAdvertisementReceivedEventArgs *>>([this](IBluetoothLEAdvertisementWatcher *, IBluetoothLEAdvertisementReceivedEventArgs *args) { |
316 | quint64 address; |
317 | HRESULT hr; |
318 | hr = args->get_BluetoothAddress(&address); |
319 | Q_ASSERT_SUCCEEDED(hr); |
320 | qint16 rssi; |
321 | hr = args->get_RawSignalStrengthInDBm(&rssi); |
322 | Q_ASSERT_SUCCEEDED(hr); |
323 | ComPtr<IBluetoothLEAdvertisement> ad; |
324 | hr = args->get_Advertisement(&ad); |
325 | Q_ASSERT_SUCCEEDED(hr); |
326 | const ManufacturerData manufacturerData = extractManufacturerData(ad); |
327 | QBluetoothDeviceInfo::Fields changedFields = QBluetoothDeviceInfo::Field::None; |
328 | if (!m_foundLEManufacturerData.contains(address)) { |
329 | m_foundLEManufacturerData.insert(address, manufacturerData); |
330 | changedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData); |
331 | } else if (m_foundLEManufacturerData.value(address) != manufacturerData) { |
332 | m_foundLEManufacturerData[address] = manufacturerData; |
333 | changedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData); |
334 | } |
335 | #if QT_CONFIG(winrt_btle_no_pairing) |
336 | if (supportsNewLEApi()) { |
337 | ComPtr<IVector<GUID>> guids; |
338 | hr = ad->get_ServiceUuids(&guids); |
339 | Q_ASSERT_SUCCEEDED(hr); |
340 | quint32 size; |
341 | hr = guids->get_Size(&size); |
342 | Q_ASSERT_SUCCEEDED(hr); |
343 | QVector<QBluetoothUuid> serviceUuids; |
344 | for (quint32 i = 0; i < size; ++i) { |
345 | GUID guid; |
346 | hr = guids->GetAt(i, &guid); |
347 | Q_ASSERT_SUCCEEDED(hr); |
348 | QBluetoothUuid uuid(guid); |
349 | serviceUuids.append(uuid); |
350 | } |
351 | QMutexLocker locker(&m_foundDevicesMutex); |
352 | // Merge newly found services with list of currently found ones |
353 | if (m_foundLEDevicesMap.contains(address)) { |
354 | if (size == 0) |
355 | return S_OK; |
356 | const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.value(address); |
357 | QVector<QBluetoothUuid> foundServices = adInfo.services; |
358 | if (adInfo.rssi != rssi) { |
359 | m_foundLEDevicesMap[address].rssi = rssi; |
360 | changedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI); |
361 | } |
362 | bool newServiceAdded = false; |
363 | for (const QBluetoothUuid &uuid : qAsConst(serviceUuids)) { |
364 | if (!foundServices.contains(uuid)) { |
365 | foundServices.append(uuid); |
366 | newServiceAdded = true; |
367 | } |
368 | } |
369 | if (!newServiceAdded) { |
370 | if (!changedFields.testFlag(QBluetoothDeviceInfo::Field::None)) { |
371 | QMetaObject::invokeMethod(this, "deviceDataChanged", Qt::AutoConnection, |
372 | Q_ARG(QBluetoothAddress, QBluetoothAddress(address)), |
373 | Q_ARG(QBluetoothDeviceInfo::Fields, changedFields), |
374 | Q_ARG(qint16, rssi), |
375 | Q_ARG(ManufacturerData, manufacturerData)); |
376 | } |
377 | return S_OK; |
378 | } |
379 | m_foundLEDevicesMap[address].services = foundServices; |
380 | } else { |
381 | LEAdvertisingInfo info; |
382 | info.services = std::move(serviceUuids); |
383 | info.rssi = rssi; |
384 | m_foundLEDevicesMap.insert(address, info); |
385 | } |
386 | |
387 | locker.unlock(); |
388 | } else |
389 | #endif |
390 | { |
391 | if (m_foundLEDevices.contains(address)) { |
392 | if (m_foundLEDevices.value(address) != rssi) { |
393 | m_foundLEDevices[address] = rssi; |
394 | changedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI); |
395 | } |
396 | if (!changedFields.testFlag(QBluetoothDeviceInfo::Field::None)) { |
397 | QMetaObject::invokeMethod(this, "deviceDataChanged", Qt::AutoConnection, |
398 | Q_ARG(QBluetoothAddress, QBluetoothAddress(address)), |
399 | Q_ARG(QBluetoothDeviceInfo::Fields, changedFields), |
400 | Q_ARG(qint16, rssi), |
401 | Q_ARG(ManufacturerData, manufacturerData)); |
402 | } |
403 | return S_OK; |
404 | } |
405 | m_foundLEDevices.insert(address, rssi); |
406 | } |
407 | leBluetoothInfoFromAddressAsync(address); |
408 | return S_OK; |
409 | }).Get(), &m_leDeviceAddedToken); |
410 | Q_ASSERT_SUCCEEDED(hr); |
411 | hr = m_leWatcher->Start(); |
412 | Q_ASSERT_SUCCEEDED(hr); |
413 | } |
414 | |
415 | void QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery() |
416 | { |
417 | emit scanFinished(); |
418 | stopLEWatcher(); |
419 | deleteLater(); |
420 | } |
421 | |
422 | // "deviceFound" will be emitted at the end of the deviceFromIdOperation callback |
423 | void QWinRTBluetoothDeviceDiscoveryWorker::classicBluetoothInfoFromDeviceIdAsync(HSTRING deviceId) |
424 | { |
425 | HRESULT hr; |
426 | hr = QEventDispatcherWinRT::runOnXamlThread([deviceId, this]() { |
427 | ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromIdOperation; |
428 | // on Windows 10 FromIdAsync might ask for device permission. We cannot wait here but have to handle that asynchronously |
429 | HRESULT hr = m_deviceStatics->FromIdAsync(deviceId, &deviceFromIdOperation); |
430 | if (FAILED(hr)) { |
431 | --m_pendingPairedDevices; |
432 | if (!m_pendingPairedDevices |
433 | && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)) |
434 | finishDiscovery(); |
435 | qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from id"; |
436 | return S_OK; |
437 | } |
438 | QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this); |
439 | hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>> |
440 | ([thisPointer](IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status) |
441 | { |
442 | if (status == Completed && thisPointer) |
443 | thisPointer->onPairedClassicBluetoothDeviceFoundAsync(op, status); |
444 | return S_OK; |
445 | }).Get()); |
446 | if (FAILED(hr)) { |
447 | --m_pendingPairedDevices; |
448 | if (!m_pendingPairedDevices |
449 | && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)) |
450 | finishDiscovery(); |
451 | qCWarning(QT_BT_WINRT) << "Could not register device found callback"; |
452 | return S_OK; |
453 | } |
454 | return S_OK; |
455 | }); |
456 | Q_ASSERT_SUCCEEDED(hr); |
457 | } |
458 | |
459 | // "deviceFound" will be emitted at the end of the deviceFromIdOperation callback |
460 | void QWinRTBluetoothDeviceDiscoveryWorker::leBluetoothInfoFromDeviceIdAsync(HSTRING deviceId) |
461 | { |
462 | HRESULT hr; |
463 | hr = QEventDispatcherWinRT::runOnXamlThread([deviceId, this]() { |
464 | ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromIdOperation; |
465 | // on Windows 10 FromIdAsync might ask for device permission. We cannot wait here but have to handle that asynchronously |
466 | HRESULT hr = m_leDeviceStatics->FromIdAsync(deviceId, &deviceFromIdOperation); |
467 | if (FAILED(hr)) { |
468 | --m_pendingPairedDevices; |
469 | qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from id"; |
470 | return S_OK; |
471 | } |
472 | QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this); |
473 | hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothLEDevice *>> |
474 | ([thisPointer] (IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status) |
475 | { |
476 | if (status == Completed && thisPointer) |
477 | thisPointer->onPairedBluetoothLEDeviceFoundAsync(op, status); |
478 | return S_OK; |
479 | }).Get()); |
480 | if (FAILED(hr)) { |
481 | --m_pendingPairedDevices; |
482 | qCWarning(QT_BT_WINRT) << "Could not register device found callback"; |
483 | return S_OK; |
484 | } |
485 | return S_OK; |
486 | }); |
487 | Q_ASSERT_SUCCEEDED(hr); |
488 | } |
489 | |
490 | // "deviceFound" will be emitted at the end of the deviceFromAdressOperation callback |
491 | void QWinRTBluetoothDeviceDiscoveryWorker::leBluetoothInfoFromAddressAsync(quint64 address) |
492 | { |
493 | HRESULT hr; |
494 | hr = QEventDispatcherWinRT::runOnXamlThread([address, this]() { |
495 | ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromAddressOperation; |
496 | // on Windows 10 FromBluetoothAddressAsync might ask for device permission. We cannot wait |
497 | // here but have to handle that asynchronously |
498 | HRESULT hr = m_leDeviceStatics->FromBluetoothAddressAsync(address, &deviceFromAddressOperation); |
499 | if (FAILED(hr)) { |
500 | qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from address"; |
501 | return S_OK; |
502 | } |
503 | QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this); |
504 | hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothLEDevice *>> |
505 | ([thisPointer](IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status) |
506 | { |
507 | if (status == Completed && thisPointer) |
508 | thisPointer->onBluetoothLEDeviceFoundAsync(op, status); |
509 | return S_OK; |
510 | }).Get()); |
511 | if (FAILED(hr)) { |
512 | qCWarning(QT_BT_WINRT) << "Could not register device found callback"; |
513 | return S_OK; |
514 | } |
515 | return S_OK; |
516 | }); |
517 | Q_ASSERT_SUCCEEDED(hr); |
518 | } |
519 | |
520 | HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedClassicBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status) |
521 | { |
522 | --m_pendingPairedDevices; |
523 | if (status != AsyncStatus::Completed) |
524 | return S_OK; |
525 | |
526 | ComPtr<IBluetoothDevice> device; |
527 | HRESULT hr = op->GetResults(&device); |
528 | Q_ASSERT_SUCCEEDED(hr); |
529 | |
530 | if (!device) |
531 | return S_OK; |
532 | |
533 | UINT64 address; |
534 | HString name; |
535 | ComPtr<IBluetoothClassOfDevice> classOfDevice; |
536 | UINT32 classOfDeviceInt; |
537 | hr = device->get_BluetoothAddress(&address); |
538 | Q_ASSERT_SUCCEEDED(hr); |
539 | hr = device->get_Name(name.GetAddressOf()); |
540 | Q_ASSERT_SUCCEEDED(hr); |
541 | const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr)); |
542 | hr = device->get_ClassOfDevice(&classOfDevice); |
543 | Q_ASSERT_SUCCEEDED(hr); |
544 | hr = classOfDevice->get_RawValue(&classOfDeviceInt); |
545 | Q_ASSERT_SUCCEEDED(hr); |
546 | IVectorView <Rfcomm::RfcommDeviceService *> *deviceServices; |
547 | hr = device->get_RfcommServices(&deviceServices); |
548 | if (hr == E_ACCESSDENIED) { |
549 | qCWarning(QT_BT_WINRT) << "Could not obtain device services. Please check you have " |
550 | "permission to access the device."; |
551 | } else { |
552 | Q_ASSERT_SUCCEEDED(hr); |
553 | uint serviceCount; |
554 | hr = deviceServices->get_Size(&serviceCount); |
555 | Q_ASSERT_SUCCEEDED(hr); |
556 | QVector<QBluetoothUuid> uuids; |
557 | for (uint i = 0; i < serviceCount; ++i) { |
558 | ComPtr<Rfcomm::IRfcommDeviceService> service; |
559 | hr = deviceServices->GetAt(i, &service); |
560 | Q_ASSERT_SUCCEEDED(hr); |
561 | ComPtr<Rfcomm::IRfcommServiceId> id; |
562 | hr = service->get_ServiceId(&id); |
563 | Q_ASSERT_SUCCEEDED(hr); |
564 | GUID uuid; |
565 | hr = id->get_Uuid(&uuid); |
566 | Q_ASSERT_SUCCEEDED(hr); |
567 | uuids.append(QBluetoothUuid(uuid)); |
568 | } |
569 | |
570 | qCDebug(QT_BT_WINRT) << "Discovered BT device: "<< QString::number(address) << btName |
571 | << "Num UUIDs"<< uuids.count(); |
572 | |
573 | QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, classOfDeviceInt); |
574 | info.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration); |
575 | info.setServiceUuids(uuids); |
576 | info.setCached(true); |
577 | |
578 | QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection, |
579 | Q_ARG(QBluetoothDeviceInfo, info)); |
580 | } |
581 | if (!m_pendingPairedDevices && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)) |
582 | finishDiscovery(); |
583 | return S_OK; |
584 | } |
585 | |
586 | HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status) |
587 | { |
588 | --m_pendingPairedDevices; |
589 | if (status != AsyncStatus::Completed) |
590 | return S_OK; |
591 | |
592 | ComPtr<IBluetoothLEDevice> device; |
593 | HRESULT hr; |
594 | hr = op->GetResults(&device); |
595 | Q_ASSERT_SUCCEEDED(hr); |
596 | #if QT_CONFIG(winrt_btle_no_pairing) |
597 | if (supportsNewLEApi()) |
598 | return onBluetoothLEDeviceFound(device); |
599 | else |
600 | #endif |
601 | return onBluetoothLEDeviceFound(device, OmitPairingCheck); |
602 | } |
603 | |
604 | HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status) |
605 | { |
606 | if (status != AsyncStatus::Completed) |
607 | return S_OK; |
608 | |
609 | ComPtr<IBluetoothLEDevice> device; |
610 | HRESULT hr; |
611 | hr = op->GetResults(&device); |
612 | Q_ASSERT_SUCCEEDED(hr); |
613 | #if QT_CONFIG(winrt_btle_no_pairing) |
614 | if (supportsNewLEApi()) |
615 | return onBluetoothLEDeviceFound(device); |
616 | else |
617 | #endif |
618 | return onBluetoothLEDeviceFound(device, PairingCheck::CheckForPairing); |
619 | } |
620 | |
621 | HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device, PairingCheck pairingCheck) |
622 | { |
623 | if (!device) { |
624 | qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: No device given"; |
625 | return S_OK; |
626 | } |
627 | |
628 | if (pairingCheck == CheckForPairing) { |
629 | ComPtr<IBluetoothLEDevice2> device2; |
630 | HRESULT hr = device.As(&device2); |
631 | Q_ASSERT_SUCCEEDED(hr); |
632 | ComPtr<IDeviceInformation> deviceInfo; |
633 | hr = device2->get_DeviceInformation(&deviceInfo); |
634 | Q_ASSERT_SUCCEEDED(hr); |
635 | if (!deviceInfo) { |
636 | qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: Could not obtain device information"; |
637 | return S_OK; |
638 | } |
639 | ComPtr<IDeviceInformation2> deviceInfo2; |
640 | hr = deviceInfo.As(&deviceInfo2); |
641 | Q_ASSERT_SUCCEEDED(hr); |
642 | ComPtr<IDeviceInformationPairing> pairing; |
643 | hr = deviceInfo2->get_Pairing(&pairing); |
644 | Q_ASSERT_SUCCEEDED(hr); |
645 | boolean isPaired; |
646 | hr = pairing->get_IsPaired(&isPaired); |
647 | Q_ASSERT_SUCCEEDED(hr); |
648 | // We need a paired device in order to be able to obtain its information |
649 | if (!isPaired) { |
650 | ComPtr<IAsyncOperation<DevicePairingResult *>> pairingOp; |
651 | QPointer<QWinRTBluetoothDeviceDiscoveryWorker> tPointer(this); |
652 | hr = pairing.Get()->PairAsync(&pairingOp); |
653 | Q_ASSERT_SUCCEEDED(hr); |
654 | pairingOp->put_Completed( |
655 | Callback<IAsyncOperationCompletedHandler<DevicePairingResult *>>([device, tPointer](IAsyncOperation<DevicePairingResult *> *op, AsyncStatus status) { |
656 | if (!tPointer) |
657 | return S_OK; |
658 | |
659 | if (status != AsyncStatus::Completed) { |
660 | qCDebug(QT_BT_WINRT) << "Could not pair device"; |
661 | return S_OK; |
662 | } |
663 | |
664 | ComPtr<IDevicePairingResult> result; |
665 | op->GetResults(&result); |
666 | |
667 | DevicePairingResultStatus pairingStatus; |
668 | result.Get()->get_Status(&pairingStatus); |
669 | |
670 | if (pairingStatus != DevicePairingResultStatus_Paired) { |
671 | qCDebug(QT_BT_WINRT) << "Could not pair device"; |
672 | return S_OK; |
673 | } |
674 | |
675 | tPointer->onBluetoothLEDeviceFound(device, OmitPairingCheck); |
676 | return S_OK; |
677 | }).Get()); |
678 | return S_OK; |
679 | } |
680 | } |
681 | |
682 | UINT64 address; |
683 | HString name; |
684 | HRESULT hr = device->get_BluetoothAddress(&address); |
685 | Q_ASSERT_SUCCEEDED(hr); |
686 | hr = device->get_Name(name.GetAddressOf()); |
687 | Q_ASSERT_SUCCEEDED(hr); |
688 | const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr)); |
689 | IVectorView <GenericAttributeProfile::GattDeviceService *> *deviceServices; |
690 | hr = device->get_GattServices(&deviceServices); |
691 | Q_ASSERT_SUCCEEDED(hr); |
692 | uint serviceCount; |
693 | hr = deviceServices->get_Size(&serviceCount); |
694 | Q_ASSERT_SUCCEEDED(hr); |
695 | QVector<QBluetoothUuid> uuids; |
696 | for (uint i = 0; i < serviceCount; ++i) { |
697 | ComPtr<GenericAttributeProfile::IGattDeviceService> service; |
698 | hr = deviceServices->GetAt(i, &service); |
699 | Q_ASSERT_SUCCEEDED(hr); |
700 | ComPtr<Rfcomm::IRfcommServiceId> id; |
701 | GUID uuid; |
702 | hr = service->get_Uuid(&uuid); |
703 | Q_ASSERT_SUCCEEDED(hr); |
704 | uuids.append(QBluetoothUuid(uuid)); |
705 | } |
706 | const qint16 rssi = m_foundLEDevices.value(address); |
707 | const ManufacturerData manufacturerData = m_foundLEManufacturerData.value(address); |
708 | |
709 | qCDebug(QT_BT_WINRT) << "Discovered BTLE device: "<< QString::number(address) << btName |
710 | << "Num UUIDs"<< uuids.count() << "RSSI:"<< rssi |
711 | << "Num manufacturer data"<< manufacturerData.count(); |
712 | |
713 | QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, 0); |
714 | info.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); |
715 | info.setServiceUuids(uuids); |
716 | info.setRssi(rssi); |
717 | for (const quint16 key : manufacturerData.keys()) |
718 | info.setManufacturerData(key, manufacturerData.value(key)); |
719 | info.setCached(true); |
720 | |
721 | QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection, |
722 | Q_ARG(QBluetoothDeviceInfo, info)); |
723 | return S_OK; |
724 | } |
725 | |
726 | #if QT_CONFIG(winrt_btle_no_pairing) |
727 | HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device) |
728 | { |
729 | if (!device) { |
730 | qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: No device given"; |
731 | return S_OK; |
732 | } |
733 | |
734 | UINT64 address; |
735 | HString name; |
736 | HRESULT hr = device->get_BluetoothAddress(&address); |
737 | Q_ASSERT_SUCCEEDED(hr); |
738 | hr = device->get_Name(name.GetAddressOf()); |
739 | Q_ASSERT_SUCCEEDED(hr); |
740 | const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr)); |
741 | |
742 | ComPtr<IBluetoothLEDevice2> device2; |
743 | hr = device.As(&device2); |
744 | Q_ASSERT_SUCCEEDED(hr); |
745 | ComPtr<IDeviceInformation> deviceInfo; |
746 | hr = device2->get_DeviceInformation(&deviceInfo); |
747 | Q_ASSERT_SUCCEEDED(hr); |
748 | if (!deviceInfo) { |
749 | qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: Could not obtain device information"; |
750 | return S_OK; |
751 | } |
752 | ComPtr<IDeviceInformation2> deviceInfo2; |
753 | hr = deviceInfo.As(&deviceInfo2); |
754 | Q_ASSERT_SUCCEEDED(hr); |
755 | ComPtr<IDeviceInformationPairing> pairing; |
756 | hr = deviceInfo2->get_Pairing(&pairing); |
757 | Q_ASSERT_SUCCEEDED(hr); |
758 | boolean isPaired; |
759 | hr = pairing->get_IsPaired(&isPaired); |
760 | Q_ASSERT_SUCCEEDED(hr); |
761 | QVector<QBluetoothUuid> uuids; |
762 | |
763 | const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.value(address); |
764 | const qint16 rssi = adInfo.rssi; |
765 | // Use the services obtained from the advertisement data if the device is not paired |
766 | if (!isPaired) { |
767 | uuids = adInfo.services; |
768 | } else { |
769 | IVectorView <GenericAttributeProfile::GattDeviceService *> *deviceServices; |
770 | hr = device->get_GattServices(&deviceServices); |
771 | Q_ASSERT_SUCCEEDED(hr); |
772 | uint serviceCount; |
773 | hr = deviceServices->get_Size(&serviceCount); |
774 | Q_ASSERT_SUCCEEDED(hr); |
775 | for (uint i = 0; i < serviceCount; ++i) { |
776 | ComPtr<GenericAttributeProfile::IGattDeviceService> service; |
777 | hr = deviceServices->GetAt(i, &service); |
778 | Q_ASSERT_SUCCEEDED(hr); |
779 | GUID uuid; |
780 | hr = service->get_Uuid(&uuid); |
781 | Q_ASSERT_SUCCEEDED(hr); |
782 | uuids.append(QBluetoothUuid(uuid)); |
783 | } |
784 | } |
785 | const ManufacturerData manufacturerData = m_foundLEManufacturerData.value(address); |
786 | |
787 | qCDebug(QT_BT_WINRT) << "Discovered BTLE device: "<< QString::number(address) << btName |
788 | << "Num UUIDs"<< uuids.count() << "RSSI:"<< rssi |
789 | << "Num manufacturer data"<< manufacturerData.count(); |
790 | |
791 | QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, 0); |
792 | info.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); |
793 | info.setServiceUuids(uuids); |
794 | info.setRssi(rssi); |
795 | for (quint16 key : manufacturerData.keys()) |
796 | info.setManufacturerData(key, manufacturerData.value(key)); |
797 | info.setCached(true); |
798 | |
799 | QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection, |
800 | Q_ARG(QBluetoothDeviceInfo, info)); |
801 | return S_OK; |
802 | } |
803 | #endif // QT_CONFIG(winrt_btle_no_pairing) |
804 | |
805 | QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate( |
806 | const QBluetoothAddress &deviceAdapter, |
807 | QBluetoothDeviceDiscoveryAgent *parent) |
808 | |
809 | : inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry), |
810 | lastError(QBluetoothDeviceDiscoveryAgent::NoError), |
811 | lowEnergySearchTimeout(25000), |
812 | q_ptr(parent), |
813 | leScanTimer(0) |
814 | { |
815 | Q_UNUSED(deviceAdapter); |
816 | } |
817 | |
818 | QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() |
819 | { |
820 | disconnectAndClearWorker(); |
821 | } |
822 | |
823 | bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const |
824 | { |
825 | return worker; |
826 | } |
827 | |
828 | QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods() |
829 | { |
830 | return (ClassicMethod | LowEnergyMethod); |
831 | } |
832 | |
833 | void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods) |
834 | { |
835 | if (worker) |
836 | return; |
837 | |
838 | worker = new QWinRTBluetoothDeviceDiscoveryWorker(methods); |
839 | discoveredDevices.clear(); |
840 | connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound, |
841 | this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice); |
842 | connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged, |
843 | this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData); |
844 | connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished, |
845 | this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished); |
846 | worker->start(); |
847 | |
848 | if (lowEnergySearchTimeout > 0 && methods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) { // otherwise no timeout and stop() required |
849 | if (!leScanTimer) { |
850 | leScanTimer = new QTimer(this); |
851 | leScanTimer->setSingleShot(true); |
852 | } |
853 | connect(leScanTimer, &QTimer::timeout, |
854 | worker, &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery); |
855 | leScanTimer->setInterval(lowEnergySearchTimeout); |
856 | leScanTimer->start(); |
857 | } |
858 | } |
859 | |
860 | void QBluetoothDeviceDiscoveryAgentPrivate::stop() |
861 | { |
862 | Q_Q(QBluetoothDeviceDiscoveryAgent); |
863 | if (worker) { |
864 | worker->stopLEWatcher(); |
865 | disconnectAndClearWorker(); |
866 | emit q->canceled(); |
867 | } |
868 | if (leScanTimer) { |
869 | leScanTimer->stop(); |
870 | worker->deleteLater(); |
871 | } |
872 | } |
873 | |
874 | void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDeviceInfo &info) |
875 | { |
876 | Q_Q(QBluetoothDeviceDiscoveryAgent); |
877 | |
878 | for (QList<QBluetoothDeviceInfo>::iterator iter = discoveredDevices.begin(); |
879 | iter != discoveredDevices.end(); ++iter) { |
880 | if (iter->address() == info.address()) { |
881 | qCDebug(QT_BT_WINRT) << "Updating device"<< iter->name() << iter->address(); |
882 | // merge service uuids |
883 | QList<QBluetoothUuid> uuids = iter->serviceUuids(); |
884 | uuids.append(info.serviceUuids()); |
885 | const QSet<QBluetoothUuid> uuidSet = uuids.toSet(); |
886 | if (iter->serviceUuids().count() != uuidSet.count()) |
887 | iter->setServiceUuids(uuidSet.toList().toVector()); |
888 | if (iter->coreConfigurations() != info.coreConfigurations()) |
889 | iter->setCoreConfigurations(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration); |
890 | return; |
891 | } |
892 | } |
893 | |
894 | discoveredDevices << info; |
895 | emit q->deviceDiscovered(info); |
896 | } |
897 | |
898 | void QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData(const QBluetoothAddress &address, |
899 | QBluetoothDeviceInfo::Fields fields, |
900 | qint16 rssi, |
901 | ManufacturerData manufacturerData) |
902 | { |
903 | if (fields.testFlag(QBluetoothDeviceInfo::Field::None)) |
904 | return; |
905 | |
906 | Q_Q(QBluetoothDeviceDiscoveryAgent); |
907 | for (QList<QBluetoothDeviceInfo>::iterator iter = discoveredDevices.begin(); |
908 | iter != discoveredDevices.end(); ++iter) { |
909 | if (iter->address() == address) { |
910 | qCDebug(QT_BT_WINRT) << "Updating data for device"<< iter->name() << iter->address(); |
911 | if (fields.testFlag(QBluetoothDeviceInfo::Field::RSSI)) |
912 | iter->setRssi(rssi); |
913 | if (fields.testFlag(QBluetoothDeviceInfo::Field::ManufacturerData)) |
914 | for (quint16 key : manufacturerData.keys()) |
915 | iter->setManufacturerData(key, manufacturerData.value(key)); |
916 | emit q->deviceUpdated(*iter, fields); |
917 | return; |
918 | } |
919 | } |
920 | } |
921 | |
922 | void QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished() |
923 | { |
924 | Q_Q(QBluetoothDeviceDiscoveryAgent); |
925 | disconnectAndClearWorker(); |
926 | emit q->finished(); |
927 | } |
928 | |
929 | void QBluetoothDeviceDiscoveryAgentPrivate::disconnectAndClearWorker() |
930 | { |
931 | if (!worker) |
932 | return; |
933 | |
934 | disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished, |
935 | this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished); |
936 | disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound, |
937 | this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice); |
938 | disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged, |
939 | this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData); |
940 | if (leScanTimer) { |
941 | disconnect(leScanTimer, &QTimer::timeout, |
942 | worker, &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery); |
943 | } |
944 | worker.clear(); |
945 | } |
946 | |
947 | QT_END_NAMESPACE |
948 | |
949 | #include <qbluetoothdevicediscoveryagent_winrt.moc> |
950 |
Warning: That file was not part of the compilation database. It may have many parsing errors.