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.cpp545
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>