summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp')
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp530
1 files changed, 297 insertions, 233 deletions
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
index 3ff53c89..2b44c7c8 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
@@ -63,35 +63,266 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
ret; \
}
-QBluetoothDeviceInfo bluetoothInfoFromDeviceId(HSTRING deviceId)
+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;
- ComPtr<IBluetoothDevice> device;
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics);
- WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth device statics", return QBluetoothDeviceInfo());
+ 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);
- WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth device from id", return QBluetoothDeviceInfo());
- hr = QWinRTFunctions::await(deviceFromIdOperation, device.GetAddressOf());
- WARN_AND_RETURN_IF_FAILED("Could not wait for bluetooth device operation to finish", return QBluetoothDeviceInfo());
- if (!device)
- return QBluetoothDeviceInfo();
+ 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);
- WARN_AND_RETURN_IF_FAILED("Could not obtain device's bluetooth address", return QBluetoothDeviceInfo());
+ Q_ASSERT_SUCCEEDED(hr);
hr = device->get_Name(name.GetAddressOf());
- WARN_AND_RETURN_IF_FAILED("Could not obtain device's name", return QBluetoothDeviceInfo());
+ Q_ASSERT_SUCCEEDED(hr);
const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
hr = device->get_ClassOfDevice(&classOfDevice);
- WARN_AND_RETURN_IF_FAILED("Could not obtain device's ckass", return QBluetoothDeviceInfo());
+ Q_ASSERT_SUCCEEDED(hr);
hr = classOfDevice->get_RawValue(&classOfDeviceInt);
- WARN_AND_RETURN_IF_FAILED("Could not obtain raw device value", return QBluetoothDeviceInfo());
+ Q_ASSERT_SUCCEEDED(hr);
IVectorView <Rfcomm::RfcommDeviceService *> *deviceServices;
hr = device->get_RfcommServices(&deviceServices);
- WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth device services", return QBluetoothDeviceInfo());
+ Q_ASSERT_SUCCEEDED(hr);
uint serviceCount;
hr = deviceServices->get_Size(&serviceCount);
Q_ASSERT_SUCCEEDED(hr);
@@ -117,32 +348,37 @@ QBluetoothDeviceInfo bluetoothInfoFromDeviceId(HSTRING deviceId)
info.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete);
info.setCached(true);
- return info;
+ QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
+ Q_ARG(QBluetoothDeviceInfo, info));
+ decreaseAndCheckPendingDevices();
+ return S_OK;
}
-QBluetoothDeviceInfo bluetoothInfoFromLeDeviceId(HSTRING deviceId)
+HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
{
- ComPtr<IBluetoothLEDeviceStatics> deviceStatics;
+ if (status != AsyncStatus::Completed) {
+ decreaseAndCheckPendingDevices();
+ return S_OK;
+ }
+
ComPtr<IBluetoothLEDevice> device;
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &deviceStatics);
- WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth LE device statics", return QBluetoothDeviceInfo());
- ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromIdOperation;
- hr = deviceStatics->FromIdAsync(deviceId, &deviceFromIdOperation);
- WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth LE device from id", return QBluetoothDeviceInfo());
- hr = QWinRTFunctions::await(deviceFromIdOperation, device.GetAddressOf());
- WARN_AND_RETURN_IF_FAILED("Could not wait for bluetooth LE device operation to finish", return QBluetoothDeviceInfo());
- if (!device)
- return QBluetoothDeviceInfo();
+ HRESULT hr = op->GetResults(&device);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ if (!device) {
+ decreaseAndCheckPendingDevices();
+ return S_OK;
+ }
UINT64 address;
HString name;
hr = device->get_BluetoothAddress(&address);
- WARN_AND_RETURN_IF_FAILED("Could not obtain device's bluetooth address", return QBluetoothDeviceInfo());
+ Q_ASSERT_SUCCEEDED(hr);
hr = device->get_Name(name.GetAddressOf());
- WARN_AND_RETURN_IF_FAILED("Could not obtain device's name", return QBluetoothDeviceInfo());
+ Q_ASSERT_SUCCEEDED(hr);
const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
IVectorView <GenericAttributeProfile::GattDeviceService *> *deviceServices;
hr = device->get_GattServices(&deviceServices);
- WARN_AND_RETURN_IF_FAILED("Could not obtain bluetooth LE device services", return QBluetoothDeviceInfo());
+ Q_ASSERT_SUCCEEDED(hr);
uint serviceCount;
hr = deviceServices->get_Size(&serviceCount);
Q_ASSERT_SUCCEEDED(hr);
@@ -166,191 +402,18 @@ QBluetoothDeviceInfo bluetoothInfoFromLeDeviceId(HSTRING deviceId)
info.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete);
info.setCached(true);
- return info;
+ QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
+ Q_ARG(QBluetoothDeviceInfo, info));
+ decreaseAndCheckPendingDevices();
+ return S_OK;
}
-class QWinRTBluetoothDeviceDiscoveryWorker : public QObject
+void QWinRTBluetoothDeviceDiscoveryWorker::decreaseAndCheckPendingDevices()
{
- Q_OBJECT
-public:
- QWinRTBluetoothDeviceDiscoveryWorker() : requestedModes(0), initializedModes(0)
- {
- }
-
- void 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";
- }
-
- ~QWinRTBluetoothDeviceDiscoveryWorker()
- {
- if (leDeviceWatcher && leDeviceAddedToken.value) {
- HRESULT hr;
- hr = leDeviceWatcher->remove_Added(leDeviceAddedToken);
- Q_ASSERT_SUCCEEDED(hr);
- }
- }
-
-private:
- void 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 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);
- onDevicesFound(devices.Get(), mode);
- initializedModes |= mode;
- if (initializedModes == requestedModes) {
- qCDebug(QT_BT_WINRT) << "All scans completed";
- emit initializationCompleted();
- setupLEDeviceWatcher();
- }
- }
-
- void onDeviceAdded(IDeviceInformation *deviceInfo, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode)
- {
- HString deviceId;
- HRESULT hr;
- hr = deviceInfo->get_Id(deviceId.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- const QBluetoothDeviceInfo info = mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod
- ? bluetoothInfoFromLeDeviceId(deviceId.Get())
- : bluetoothInfoFromDeviceId(deviceId.Get());
- if (!info.isValid())
- return;
-
- for (QVector<QBluetoothDeviceInfo>::iterator iter = deviceList.begin();
- iter != deviceList.end(); ++iter) {
- // one of them has to be the traditional device, the other one the BTLE version (found in both scans)
- 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);
-
- iter->setCoreConfigurations(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration);
- return;
- }
- }
- qCDebug(QT_BT_WINRT) << "Adding device" << info.name() << info.address();
- deviceList.append(info);
- }
-
- void onDevicesFound(IVectorView<DeviceInformation *> *devices, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode)
- {
- quint32 deviceCount;
- HRESULT hr = devices->get_Size(&deviceCount);
- Q_ASSERT_SUCCEEDED(hr);
- deviceList.reserve(deviceList.length() + deviceCount);
- for (quint32 i = 0; i < deviceCount; ++i) {
- ComPtr<IDeviceInformation> device;
- hr = devices->GetAt(i, &device);
- Q_ASSERT_SUCCEEDED(hr);
- onDeviceAdded(device.Get(), mode);
- }
- }
-
- void 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(), &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);
- const QBluetoothDeviceInfo info = bluetoothInfoFromLeDeviceId(deviceId.Get());
- if (!info.isValid())
- return S_OK;
-
- qCDebug(QT_BT_WINRT) << "Found device" << info.name() << info.address();
- emit leDeviceFound(info);
- return S_OK;
- });
- hr = leDeviceWatcher->add_Added(deviceAddedCallback.Get(), &leDeviceAddedToken);
- WARN_AND_RETURN_IF_FAILED("Could not add \"device added\" callback", return);
- hr = leDeviceWatcher->Start();
- WARN_AND_RETURN_IF_FAILED("Could not start device watcher", return);
- }
-
-public slots:
- void onLeTimeout()
- {
- if (initializedModes == requestedModes)
- emit scanFinished();
- else
- emit scanCanceled();
- deleteLater();
- }
-
-Q_SIGNALS:
- void initializationCompleted();
- void leDeviceFound(const QBluetoothDeviceInfo &info);
- void scanFinished();
- void scanCanceled();
-
-public:
- QVector<QBluetoothDeviceInfo> deviceList;
- quint8 requestedModes;
-
-private:
- quint8 initializedModes;
- ComPtr<IDeviceWatcher> leDeviceWatcher;
- EventRegistrationToken leDeviceAddedToken;
-};
+ --m_pendingDevices;
+ if (m_pendingDevices == 0)
+ setupLEDeviceWatcher();
+}
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
const QBluetoothAddress &deviceAdapter,
@@ -385,13 +448,10 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
if (worker)
return;
- worker = new QWinRTBluetoothDeviceDiscoveryWorker();
- worker->requestedModes = methods;
+ worker = new QWinRTBluetoothDeviceDiscoveryWorker(methods);
discoveredDevices.clear();
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::initializationCompleted,
- this, &QBluetoothDeviceDiscoveryAgentPrivate::onListInitializationCompleted);
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::leDeviceFound,
- this, &QBluetoothDeviceDiscoveryAgentPrivate::onLeDeviceFound);
+ connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanCanceled,
@@ -404,7 +464,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
leScanTimer->setSingleShot(true);
}
connect(leScanTimer, &QTimer::timeout,
- worker, &QWinRTBluetoothDeviceDiscoveryWorker::onLeTimeout);
+ worker, &QWinRTBluetoothDeviceDiscoveryWorker::handleLeTimeout);
leScanTimer->setInterval(lowEnergySearchTimeout);
leScanTimer->start();
}
@@ -417,24 +477,31 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
disconnectAndClearWorker();
emit q->canceled();
}
- if (leScanTimer)
+ if (leScanTimer) {
leScanTimer->stop();
+ worker->deleteLater();
+ }
}
-void QBluetoothDeviceDiscoveryAgentPrivate::onListInitializationCompleted()
+void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDeviceInfo &info)
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
- discoveredDevices = worker->deviceList.toList();
- foreach (const QBluetoothDeviceInfo &info, worker->deviceList)
- emit q->deviceDiscovered(info);
-}
-void QBluetoothDeviceDiscoveryAgentPrivate::onLeDeviceFound(const QBluetoothDeviceInfo &info)
-{
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- for (auto discoveredInfo : discoveredDevices)
- if (discoveredInfo.address() == info.address())
+ 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);
@@ -460,19 +527,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::disconnectAndClearWorker()
if (!worker)
return;
- disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::initializationCompleted,
- this, &QBluetoothDeviceDiscoveryAgentPrivate::onListInitializationCompleted);
disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanCanceled,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanCanceled);
disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
- disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::leDeviceFound,
+ disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
q, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered);
if (leScanTimer) {
disconnect(leScanTimer, &QTimer::timeout,
- worker, &QWinRTBluetoothDeviceDiscoveryWorker::onLeTimeout);
+ worker, &QWinRTBluetoothDeviceDiscoveryWorker::handleLeTimeout);
}
- worker->deleteLater();
worker.clear();
}