diff options
Diffstat (limited to 'src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp')
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp new file mode 100644 index 00000000..2b44c7c8 --- /dev/null +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp @@ -0,0 +1,545 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbluetoothdevicediscoveryagent.h" +#include "qbluetoothdevicediscoveryagent_p.h" +#include "qbluetoothaddress.h" +#include "qbluetoothuuid.h" +#include "qfunctions_winrt.h" + +#include <QtCore/QLoggingCategory> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +#include <wrl.h> +#include <windows.devices.enumeration.h> +#include <windows.devices.bluetooth.h> +#include <windows.foundation.collections.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::Enumeration; + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT) + +#define WARN_AND_RETURN_IF_FAILED(msg, ret) \ + if (FAILED(hr)) { \ + qCWarning(QT_BT_WINRT) << msg; \ + ret; \ + } + +class QWinRTBluetoothDeviceDiscoveryWorker : public QObject +{ + Q_OBJECT +public: + explicit QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods); + ~QWinRTBluetoothDeviceDiscoveryWorker(); + void start(); + +private: + void startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode); + void onDeviceDiscoveryFinished(IAsyncOperation<DeviceInformationCollection *> *op, + QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode); + void gatherDeviceInformation(IDeviceInformation *deviceInfo, + QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode); + void gatherMultipleDeviceInformation(IVectorView<DeviceInformation *> *devices, + QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode); + void setupLEDeviceWatcher(); + void bluetoothInfoFromDeviceIdAsync(HSTRING deviceId); + void bluetoothInfoFromLeDeviceIdAsync(HSTRING deviceId); + HRESULT onClassicBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *, AsyncStatus); + HRESULT onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status); + void decreaseAndCheckPendingDevices(); + +public slots: + void handleLeTimeout(); + +Q_SIGNALS: + void deviceFound(const QBluetoothDeviceInfo &info); + void scanFinished(); + void scanCanceled(); + +public: + quint8 requestedModes; + +private: + ComPtr<IDeviceWatcher> m_leDeviceWatcher; + EventRegistrationToken m_leDeviceAddedToken; + int m_pendingDevices; +}; + +QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods) + : requestedModes(methods) + , m_pendingDevices(0) +{ + qRegisterMetaType<QBluetoothDeviceInfo>(); +} + +QWinRTBluetoothDeviceDiscoveryWorker::~QWinRTBluetoothDeviceDiscoveryWorker() +{ + if (m_leDeviceWatcher && m_leDeviceAddedToken.value) { + HRESULT hr; + hr = m_leDeviceWatcher->remove_Added(m_leDeviceAddedToken); + Q_ASSERT_SUCCEEDED(hr); + } +} + +void QWinRTBluetoothDeviceDiscoveryWorker::start() +{ + QEventDispatcherWinRT::runOnXamlThread([this]() { + if (requestedModes & QBluetoothDeviceDiscoveryAgent::ClassicMethod) + startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::ClassicMethod); + + if (requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) + startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); + return S_OK; + }); + + qCDebug(QT_BT_WINRT) << "Worker started"; +} + +void QWinRTBluetoothDeviceDiscoveryWorker::startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode) +{ + HString deviceSelector; + ComPtr<IDeviceInformationStatics> deviceInformationStatics; + HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &deviceInformationStatics); + WARN_AND_RETURN_IF_FAILED("Could not obtain device information statics", return); + if (mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) { + ComPtr<IBluetoothLEDeviceStatics> bluetoothLeDeviceStatics; + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &bluetoothLeDeviceStatics); + WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth LE device statics", return); + bluetoothLeDeviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf()); + } else { + ComPtr<IBluetoothDeviceStatics> bluetoothDeviceStatics; + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &bluetoothDeviceStatics); + WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth device statics", return); + bluetoothDeviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf()); + } + ComPtr<IAsyncOperation<DeviceInformationCollection *>> op; + hr = deviceInformationStatics->FindAllAsyncAqsFilter(deviceSelector.Get(), &op); + WARN_AND_RETURN_IF_FAILED("Could not start bluetooth device discovery operation", return); + hr = op->put_Completed( + Callback<IAsyncOperationCompletedHandler<DeviceInformationCollection *>>([this, mode](IAsyncOperation<DeviceInformationCollection *> *op, AsyncStatus) { + onDeviceDiscoveryFinished(op, mode); + return S_OK; + }).Get()); + WARN_AND_RETURN_IF_FAILED("Could not add callback to bluetooth device discovery operation", return); +} + +void QWinRTBluetoothDeviceDiscoveryWorker::onDeviceDiscoveryFinished(IAsyncOperation<DeviceInformationCollection *> *op, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode) +{ + qCDebug(QT_BT_WINRT) << (mode == QBluetoothDeviceDiscoveryAgent::ClassicMethod ? "BT" : "BTLE") + << " scan completed"; + ComPtr<IVectorView<DeviceInformation *>> devices; + HRESULT hr; + hr = op->GetResults(&devices); + Q_ASSERT_SUCCEEDED(hr); + gatherMultipleDeviceInformation(devices.Get(), mode); +} + +void QWinRTBluetoothDeviceDiscoveryWorker::gatherDeviceInformation(IDeviceInformation *deviceInfo, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode) +{ + HString deviceId; + HRESULT hr; + hr = deviceInfo->get_Id(deviceId.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + if (mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) + bluetoothInfoFromLeDeviceIdAsync(deviceId.Get()); + else + bluetoothInfoFromDeviceIdAsync(deviceId.Get()); +} + +void QWinRTBluetoothDeviceDiscoveryWorker::gatherMultipleDeviceInformation(IVectorView<DeviceInformation *> *devices, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode) +{ + quint32 deviceCount; + HRESULT hr = devices->get_Size(&deviceCount); + Q_ASSERT_SUCCEEDED(hr); + m_pendingDevices += deviceCount; + for (quint32 i = 0; i < deviceCount; ++i) { + ComPtr<IDeviceInformation> device; + hr = devices->GetAt(i, &device); + Q_ASSERT_SUCCEEDED(hr); + gatherDeviceInformation(device.Get(), mode); + } +} + +void QWinRTBluetoothDeviceDiscoveryWorker::setupLEDeviceWatcher() +{ + HString deviceSelector; + ComPtr<IDeviceInformationStatics> deviceInformationStatics; + HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &deviceInformationStatics); + WARN_AND_RETURN_IF_FAILED("Could not obtain device information statics", return); + ComPtr<IBluetoothLEDeviceStatics> bluetoothLeDeviceStatics; + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &bluetoothLeDeviceStatics); + WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth LE device statics", return); + hr = bluetoothLeDeviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf()); + WARN_AND_RETURN_IF_FAILED("Could not obtain device selector string", return); + hr = deviceInformationStatics->CreateWatcherAqsFilter(deviceSelector.Get(), &m_leDeviceWatcher); + WARN_AND_RETURN_IF_FAILED("Could not create le device watcher", return); + auto deviceAddedCallback = + Callback<ITypedEventHandler<DeviceWatcher *, DeviceInformation *>>([this](IDeviceWatcher *, IDeviceInformation *deviceInfo) + { + HString deviceId; + HRESULT hr; + hr = deviceInfo->get_Id(deviceId.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + bluetoothInfoFromLeDeviceIdAsync(deviceId.Get()); + return S_OK; + }); + hr = m_leDeviceWatcher->add_Added(deviceAddedCallback.Get(), &m_leDeviceAddedToken); + WARN_AND_RETURN_IF_FAILED("Could not add \"device added\" callback", return); + hr = m_leDeviceWatcher->Start(); + WARN_AND_RETURN_IF_FAILED("Could not start device watcher", return); +} + +void QWinRTBluetoothDeviceDiscoveryWorker::handleLeTimeout() +{ + // pendingDevices might be <0 if devices were added after the intitial scan was completed + if (m_pendingDevices <= 0) + emit scanFinished(); + else + emit scanCanceled(); + deleteLater(); +} + +// "deviceFound" will be emitted at the end of the deviceFromIdOperation callback +void QWinRTBluetoothDeviceDiscoveryWorker::bluetoothInfoFromDeviceIdAsync(HSTRING deviceId) +{ + ComPtr<IBluetoothDeviceStatics> deviceStatics; + HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromIdOperation; + // on Windows 10 FromIdAsync might ask for device permission. We cannot wait here but have to handle that asynchronously + hr = deviceStatics->FromIdAsync(deviceId, &deviceFromIdOperation); + if (FAILED(hr)) { + decreaseAndCheckPendingDevices(); + qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from id"; + return; + } + QEventDispatcherWinRT::runOnXamlThread([deviceFromIdOperation, this]() { + HRESULT hr; + hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>> + (this, &QWinRTBluetoothDeviceDiscoveryWorker::onClassicBluetoothDeviceFoundAsync).Get()); + if (FAILED(hr)) { + decreaseAndCheckPendingDevices(); + qCWarning(QT_BT_WINRT) << "Could not register device found callback"; + return S_OK; + } + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); +} + +// "deviceFound" will be emitted at the end of the deviceFromIdOperation callback +void QWinRTBluetoothDeviceDiscoveryWorker::bluetoothInfoFromLeDeviceIdAsync(HSTRING deviceId) +{ + ComPtr<IBluetoothLEDeviceStatics> deviceStatics; + HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &deviceStatics); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromIdOperation; + // on Windows 10 FromIdAsync might ask for device permission. We cannot wait here but have to handle that asynchronously + hr = deviceStatics->FromIdAsync(deviceId, &deviceFromIdOperation); + if (FAILED(hr)) { + decreaseAndCheckPendingDevices(); + qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from id"; + return; + } + QEventDispatcherWinRT::runOnXamlThread([deviceFromIdOperation, this]() { + HRESULT hr; + hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothLEDevice *>> + (this, &QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFoundAsync).Get()); + if (FAILED(hr)) { + decreaseAndCheckPendingDevices(); + qCWarning(QT_BT_WINRT) << "Could not register device found callback"; + return S_OK; + } + return S_OK; + }); +} + +HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onClassicBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status) +{ + if (status != AsyncStatus::Completed) { + decreaseAndCheckPendingDevices(); + return S_OK; + } + + ComPtr<IBluetoothDevice> device; + HRESULT hr = op->GetResults(&device); + Q_ASSERT_SUCCEEDED(hr); + + if (!device) { + decreaseAndCheckPendingDevices(); + return S_OK; + } + UINT64 address; + HString name; + ComPtr<IBluetoothClassOfDevice> classOfDevice; + UINT32 classOfDeviceInt; + hr = device->get_BluetoothAddress(&address); + Q_ASSERT_SUCCEEDED(hr); + hr = device->get_Name(name.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr)); + hr = device->get_ClassOfDevice(&classOfDevice); + Q_ASSERT_SUCCEEDED(hr); + hr = classOfDevice->get_RawValue(&classOfDeviceInt); + Q_ASSERT_SUCCEEDED(hr); + IVectorView <Rfcomm::RfcommDeviceService *> *deviceServices; + hr = device->get_RfcommServices(&deviceServices); + Q_ASSERT_SUCCEEDED(hr); + uint serviceCount; + hr = deviceServices->get_Size(&serviceCount); + Q_ASSERT_SUCCEEDED(hr); + QList<QBluetoothUuid> uuids; + for (uint i = 0; i < serviceCount; ++i) { + ComPtr<Rfcomm::IRfcommDeviceService> service; + hr = deviceServices->GetAt(i, &service); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<Rfcomm::IRfcommServiceId> id; + hr = service->get_ServiceId(&id); + Q_ASSERT_SUCCEEDED(hr); + GUID uuid; + hr = id->get_Uuid(&uuid); + Q_ASSERT_SUCCEEDED(hr); + uuids.append(QBluetoothUuid(uuid)); + } + + qCDebug(QT_BT_WINRT) << "Discovered BT device: " << QString::number(address) << btName + << "Num UUIDs" << uuids.count(); + + QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, classOfDeviceInt); + info.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration); + info.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete); + info.setCached(true); + + QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection, + Q_ARG(QBluetoothDeviceInfo, info)); + decreaseAndCheckPendingDevices(); + return S_OK; +} + +HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status) +{ + if (status != AsyncStatus::Completed) { + decreaseAndCheckPendingDevices(); + return S_OK; + } + + ComPtr<IBluetoothLEDevice> device; + HRESULT hr = op->GetResults(&device); + Q_ASSERT_SUCCEEDED(hr); + + if (!device) { + decreaseAndCheckPendingDevices(); + return S_OK; + } + UINT64 address; + HString name; + hr = device->get_BluetoothAddress(&address); + Q_ASSERT_SUCCEEDED(hr); + hr = device->get_Name(name.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr)); + IVectorView <GenericAttributeProfile::GattDeviceService *> *deviceServices; + hr = device->get_GattServices(&deviceServices); + Q_ASSERT_SUCCEEDED(hr); + uint serviceCount; + hr = deviceServices->get_Size(&serviceCount); + Q_ASSERT_SUCCEEDED(hr); + QList<QBluetoothUuid> uuids; + for (uint i = 0; i < serviceCount; ++i) { + ComPtr<GenericAttributeProfile::IGattDeviceService> service; + hr = deviceServices->GetAt(i, &service); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<Rfcomm::IRfcommServiceId> id; + GUID uuid; + hr = service->get_Uuid(&uuid); + Q_ASSERT_SUCCEEDED(hr); + uuids.append(QBluetoothUuid(uuid)); + } + + qCDebug(QT_BT_WINRT) << "Discovered BTLE device: " << QString::number(address) << btName + << "Num UUIDs" << uuids.count(); + + QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, 0); + info.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); + info.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete); + info.setCached(true); + + QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection, + Q_ARG(QBluetoothDeviceInfo, info)); + decreaseAndCheckPendingDevices(); + return S_OK; +} + +void QWinRTBluetoothDeviceDiscoveryWorker::decreaseAndCheckPendingDevices() +{ + --m_pendingDevices; + if (m_pendingDevices == 0) + setupLEDeviceWatcher(); +} + +QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate( + const QBluetoothAddress &deviceAdapter, + QBluetoothDeviceDiscoveryAgent *parent) + + : inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry), + lastError(QBluetoothDeviceDiscoveryAgent::NoError), + lowEnergySearchTimeout(25000), + q_ptr(parent), + leScanTimer(0) +{ + Q_UNUSED(deviceAdapter); +} + +QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate() +{ + disconnectAndClearWorker(); +} + +bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const +{ + return worker; +} + +QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods() +{ + return (ClassicMethod | LowEnergyMethod); +} + +void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods) +{ + if (worker) + return; + + worker = new QWinRTBluetoothDeviceDiscoveryWorker(methods); + discoveredDevices.clear(); + connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound, + this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice); + connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished, + this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished); + connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanCanceled, + this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanCanceled); + worker->start(); + + if (lowEnergySearchTimeout > 0 && methods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) { // otherwise no timeout and stop() required + if (!leScanTimer) { + leScanTimer = new QTimer(this); + leScanTimer->setSingleShot(true); + } + connect(leScanTimer, &QTimer::timeout, + worker, &QWinRTBluetoothDeviceDiscoveryWorker::handleLeTimeout); + leScanTimer->setInterval(lowEnergySearchTimeout); + leScanTimer->start(); + } +} + +void QBluetoothDeviceDiscoveryAgentPrivate::stop() +{ + Q_Q(QBluetoothDeviceDiscoveryAgent); + if (worker) { + disconnectAndClearWorker(); + emit q->canceled(); + } + if (leScanTimer) { + leScanTimer->stop(); + worker->deleteLater(); + } +} + +void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDeviceInfo &info) +{ + Q_Q(QBluetoothDeviceDiscoveryAgent); + + for (QList<QBluetoothDeviceInfo>::iterator iter = discoveredDevices.begin(); + iter != discoveredDevices.end(); ++iter) { + if (iter->address() == info.address()) { + qCDebug(QT_BT_WINRT) << "Updating device" << iter->name() << iter->address(); + // merge service uuids + QList<QBluetoothUuid> uuids = iter->serviceUuids(); + uuids.append(info.serviceUuids()); + const QSet<QBluetoothUuid> uuidSet = uuids.toSet(); + if (iter->serviceUuids().count() != uuidSet.count()) + iter->setServiceUuids(uuidSet.toList(), QBluetoothDeviceInfo::DataIncomplete); + if (iter->coreConfigurations() != info.coreConfigurations()) + iter->setCoreConfigurations(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration); + return; + } + } + + discoveredDevices << info; + emit q->deviceDiscovered(info); +} + +void QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished() +{ + Q_Q(QBluetoothDeviceDiscoveryAgent); + disconnectAndClearWorker(); + emit q->finished(); +} + +void QBluetoothDeviceDiscoveryAgentPrivate::onScanCanceled() +{ + Q_Q(QBluetoothDeviceDiscoveryAgent); + disconnectAndClearWorker(); + emit q->canceled(); +} + +void QBluetoothDeviceDiscoveryAgentPrivate::disconnectAndClearWorker() +{ + Q_Q(QBluetoothDeviceDiscoveryAgent); + if (!worker) + return; + + disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanCanceled, + this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanCanceled); + disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished, + this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished); + disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound, + q, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered); + if (leScanTimer) { + disconnect(leScanTimer, &QTimer::timeout, + worker, &QWinRTBluetoothDeviceDiscoveryWorker::handleLeTimeout); + } + worker.clear(); +} + +QT_END_NAMESPACE + +#include <qbluetoothdevicediscoveryagent_winrt.moc> |