summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--config.tests/winrt_btle_no_pairing/main.cpp40
-rw-r--r--config.tests/winrt_btle_no_pairing/winrt.pro3
-rw-r--r--examples/bluetooth/btscanner/device.cpp8
-rw-r--r--src/bluetooth/bluetooth.pro9
-rw-r--r--src/bluetooth/configure.json13
-rw-r--r--src/bluetooth/osx/osxbtledeviceinquiry.mm8
-rw-r--r--src/bluetooth/osx/osxbtsdpinquiry.mm6
-rw-r--r--src/bluetooth/osx/osxbtsdpinquiry_p.h3
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent.cpp8
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp8
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm31
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm55
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_p.h5
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp361
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo.cpp42
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo.h26
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo_p.h2
-rw-r--r--src/bluetooth/qbluetoothlocaldevice.cpp4
-rw-r--r--src/bluetooth/qbluetoothserver.cpp4
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.cpp4
-rw-r--r--src/bluetooth/qbluetoothsocket.cpp4
-rw-r--r--src/bluetooth/qbluetoothtransfermanager.cpp3
-rw-r--r--src/bluetooth/qbluetoothtransferreply.cpp4
-rw-r--r--src/bluetooth/qbluetoothutils_winrt.cpp79
-rw-r--r--src/bluetooth/qbluetoothutils_winrt_p.h62
-rw-r--r--src/bluetooth/qlowenergycharacteristic.h1
-rw-r--r--src/bluetooth/qlowenergycontroller.cpp10
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt.cpp34
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new.cpp1322
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new_p.h152
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_p.h1
-rw-r--r--src/bluetooth/qlowenergydescriptor.h1
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp16
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h10
-rw-r--r--src/nfc/qnearfieldmanager.h2
-rw-r--r--tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp5
37 files changed, 2241 insertions, 107 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 1bf9543a..f8cda0e7 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,3 @@
load(qt_build_config)
-MODULE_VERSION = 5.12.3
+MODULE_VERSION = 5.13.0
diff --git a/config.tests/winrt_btle_no_pairing/main.cpp b/config.tests/winrt_btle_no_pairing/main.cpp
new file mode 100644
index 00000000..665e357a
--- /dev/null
+++ b/config.tests/winrt_btle_no_pairing/main.cpp
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtConnectivity module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <wrl.h>
+#include <windows.devices.bluetooth.h>
+
+#if defined(_WIN32) && defined(__INTEL_COMPILER)
+#error "Windows ICC fails to build the WinRT backend (QTBUG-68026)."
+#endif
+
+int main()
+{
+ (void)Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService3>().Get();
+ return 0;
+}
diff --git a/config.tests/winrt_btle_no_pairing/winrt.pro b/config.tests/winrt_btle_no_pairing/winrt.pro
new file mode 100644
index 00000000..d60fd242
--- /dev/null
+++ b/config.tests/winrt_btle_no_pairing/winrt.pro
@@ -0,0 +1,3 @@
+SOURCES += main.cpp
+
+!winrt: LIBS += runtimeobject.lib
diff --git a/examples/bluetooth/btscanner/device.cpp b/examples/bluetooth/btscanner/device.cpp
index e97c0637..b6a07db4 100644
--- a/examples/bluetooth/btscanner/device.cpp
+++ b/examples/bluetooth/btscanner/device.cpp
@@ -109,9 +109,9 @@ void DeviceDiscoveryDialog::addDevice(const QBluetoothDeviceInfo &info)
QListWidgetItem *item = new QListWidgetItem(label);
QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(info.address());
if (pairingStatus == QBluetoothLocalDevice::Paired || pairingStatus == QBluetoothLocalDevice::AuthorizedPaired )
- item->setTextColor(QColor(Qt::green));
+ item->setForeground(QColor(Qt::green));
else
- item->setTextColor(QColor(Qt::black));
+ item->setForeground(QColor(Qt::black));
ui->list->addItem(item);
}
@@ -218,12 +218,12 @@ void DeviceDiscoveryDialog::pairingDone(const QBluetoothAddress &address, QBluet
if (pairing == QBluetoothLocalDevice::Paired || pairing == QBluetoothLocalDevice::AuthorizedPaired ) {
for (int var = 0; var < items.count(); ++var) {
QListWidgetItem *item = items.at(var);
- item->setTextColor(QColor(Qt::green));
+ item->setForeground(QColor(Qt::green));
}
} else {
for (int var = 0; var < items.count(); ++var) {
QListWidgetItem *item = items.at(var);
- item->setTextColor(QColor(Qt::red));
+ item->setForeground(QColor(Qt::red));
}
}
}
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
index 193ed217..2bcdee12 100644
--- a/src/bluetooth/bluetooth.pro
+++ b/src/bluetooth/bluetooth.pro
@@ -229,10 +229,17 @@ qtConfig(bluez) {
qbluetoothservicediscoveryagent_winrt.cpp \
qbluetoothserviceinfo_winrt.cpp \
qbluetoothsocket_winrt.cpp \
+ qbluetoothutils_winrt.cpp \
qlowenergycontroller_winrt.cpp
PRIVATE_HEADERS += qlowenergycontroller_winrt_p.h \
- qbluetoothsocket_winrt_p.h
+ qbluetoothsocket_winrt_p.h \
+ qbluetoothutils_winrt_p.h
+
+ qtConfig(winrt_btle_no_pairing) {
+ SOURCES += qlowenergycontroller_winrt_new.cpp
+ PRIVATE_HEADERS += qlowenergycontroller_winrt_new_p.h
+ }
lessThan(WINDOWS_SDK_VERSION, 14393) {
DEFINES += QT_WINRT_LIMITED_SERVICEDISCOVERY
diff --git a/src/bluetooth/configure.json b/src/bluetooth/configure.json
index 3153aca6..53923e12 100644
--- a/src/bluetooth/configure.json
+++ b/src/bluetooth/configure.json
@@ -28,6 +28,11 @@
"label": "WinRT Bluetooth API",
"type": "compile",
"test": "winrt_bt"
+ },
+ "winrt_btle_no_pairing": {
+ "label": "WinRT extended bluetooth low energy API",
+ "type": "compile",
+ "test": "winrt_btle_no_pairing"
}
},
@@ -51,6 +56,11 @@
"label": "WinRT Bluetooth API (desktop & UWP)",
"condition": "config.win32 && tests.winrt_bt",
"output": [ "privateFeature" ]
+ },
+ "winrt_btle_no_pairing": {
+ "label": "WinRT advanced bluetooth low energy API (desktop & UWP)",
+ "condition": "config.win32 && features.winrt_bt && tests.winrt_btle_no_pairing",
+ "output": [ "privateFeature" ]
}
},
@@ -75,7 +85,8 @@ Only classic Bluetooth will be available."
"bluez",
"bluez_le",
"linux_crypto_api",
- "winrt_bt"
+ "winrt_bt",
+ "winrt_btle_no_pairing"
]
}
]
diff --git a/src/bluetooth/osx/osxbtledeviceinquiry.mm b/src/bluetooth/osx/osxbtledeviceinquiry.mm
index df0c26ad..70b96ab7 100644
--- a/src/bluetooth/osx/osxbtledeviceinquiry.mm
+++ b/src/bluetooth/osx/osxbtledeviceinquiry.mm
@@ -81,7 +81,7 @@ struct AdvertisementData {
// For now, we "parse":
QString localName;
- QList<QBluetoothUuid> serviceUuids;
+ QVector<QBluetoothUuid> serviceUuids;
QHash<quint16, QByteArray> manufacturerData;
// TODO: other keys probably?
AdvertisementData(NSDictionary *AdvertisementData);
@@ -363,10 +363,8 @@ QT_USE_NAMESPACE
if (RSSI)
newDeviceInfo.setRssi([RSSI shortValue]);
- if (qtAdvData.serviceUuids.size()) {
- newDeviceInfo.setServiceUuids(qtAdvData.serviceUuids,
- QBluetoothDeviceInfo::DataIncomplete);
- }
+ if (qtAdvData.serviceUuids.size())
+ newDeviceInfo.setServiceUuids(qtAdvData.serviceUuids);
const QList<quint16> keys = qtAdvData.manufacturerData.keys();
for (quint16 key : keys)
diff --git a/src/bluetooth/osx/osxbtsdpinquiry.mm b/src/bluetooth/osx/osxbtsdpinquiry.mm
index 591d75a5..a7bdc2c4 100644
--- a/src/bluetooth/osx/osxbtsdpinquiry.mm
+++ b/src/bluetooth/osx/osxbtsdpinquiry.mm
@@ -179,9 +179,9 @@ void extract_service_record(IOBluetoothSDPServiceRecord *record, QBluetoothServi
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, sequence);
}
-QList<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device)
+QVector<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device)
{
- QList<QBluetoothUuid> uuids;
+ QVector<QBluetoothUuid> uuids;
// All "temporary" obj-c objects are autoreleased.
QT_BT_MAC_AUTORELEASEPOOL;
@@ -197,7 +197,7 @@ QList<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device)
const QVector<QBluetoothUuid> idList(extract_service_class_ID_list(record));
if (idList.size())
- uuids.append(idList.toList());
+ uuids.append(idList);
}
return uuids;
diff --git a/src/bluetooth/osx/osxbtsdpinquiry_p.h b/src/bluetooth/osx/osxbtsdpinquiry_p.h
index c63738bb..dd38a28b 100644
--- a/src/bluetooth/osx/osxbtsdpinquiry_p.h
+++ b/src/bluetooth/osx/osxbtsdpinquiry_p.h
@@ -57,6 +57,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qlist.h>
+#include <QtCore/qvector.h>
#include <Foundation/Foundation.h>
@@ -81,7 +82,7 @@ public:
void extract_service_record(IOBluetoothSDPServiceRecord *record, QBluetoothServiceInfo &serviceInfo);
QVariant extract_attribute_value(IOBluetoothSDPDataElement *dataElement);
-QList<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device);
+QVector<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device);
}
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
index 8a5772c4..fb14850e 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
@@ -171,13 +171,11 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
This signal informs you that if your application is displaying this data, it
can be updated, rather than waiting until the discovery has finished.
- \note This signal is only emitted on Android and BlueZ 5.x.
+ \note This signal is only emitted on Android, iOS, macOS, and BlueZ 5.x.
\sa QBluetoothDeviceInfo::rssi(), lowEnergyDiscoveryTimeout()
*/
-// TODO deviceUpdated() signal not implemented on WinRT and Apple platforms
-
/*!
\fn void QBluetoothDeviceDiscoveryAgent::finished()
@@ -431,6 +429,6 @@ QString QBluetoothDeviceDiscoveryAgent::errorString() const
return d->errorString;
}
-#include "moc_qbluetoothdevicediscoveryagent.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qbluetoothdevicediscoveryagent.cpp"
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
index bbb4ac3e..a7def3d0 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
@@ -365,12 +365,12 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &addres
QBluetoothDeviceInfo device(btAddress, btName, btClass);
if (dict.value(QStringLiteral("RSSI")).isValid())
device.setRssi(dict.value(QStringLiteral("RSSI")).toInt());
- QList<QBluetoothUuid> uuids;
+ QVector<QBluetoothUuid> uuids;
const QStringList uuidStrings
= dict.value(QLatin1String("UUIDs")).toStringList();
for (const QString &u : uuidStrings)
uuids.append(QBluetoothUuid(u));
- device.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete);
+ device.setServiceUuids(uuids);
device.setCached(dict.value(QStringLiteral("Cached")).toBool());
@@ -444,7 +444,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString& dev
QBluetoothDeviceInfo deviceInfo(btAddress, btName, btClass);
deviceInfo.setRssi(device.rSSI());
- QList<QBluetoothUuid> uuids;
+ QVector<QBluetoothUuid> uuids;
bool foundLikelyLowEnergyUuid = false;
for (const auto &u: device.uUIDs()) {
const QBluetoothUuid id(u);
@@ -460,7 +460,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString& dev
}
uuids.append(id);
}
- deviceInfo.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete);
+ deviceInfo.setServiceUuids(uuids);
if (!btClass) {
deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
index c50d546d..059f244d 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_ios.mm
@@ -253,11 +253,40 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEdeviceFound(const QBluetoothDevice
// Update, append or discard.
for (int i = 0, e = discoveredDevices.size(); i < e; ++i) {
if (discoveredDevices[i].deviceUuid() == newDeviceInfo.deviceUuid()) {
- if (discoveredDevices[i] == newDeviceInfo)
+ QBluetoothDeviceInfo::Fields updatedFields = QBluetoothDeviceInfo::Field::None;
+ if (discoveredDevices[i].rssi() != newDeviceInfo.rssi()) {
+ qCDebug(QT_BT_OSX) << "Updating RSSI for" << newDeviceInfo.address()
+ << newDeviceInfo.rssi();
+ discoveredDevices[i].setRssi(newDeviceInfo.rssi());
+ updatedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI);
+ }
+
+ if (discoveredDevices[i].manufacturerData() != newDeviceInfo.manufacturerData()) {
+ qCDebug(QT_BT_OSX) << "Updating manufacturer data for" << newDeviceInfo.address();
+ const QVector<quint16> keys = newDeviceInfo.manufacturerIds();
+ for (auto key: keys)
+ discoveredDevices[i].setManufacturerData(key, newDeviceInfo.manufacturerData(key));
+ updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
+ }
+
+ if (lowEnergySearchTimeout > 0) {
+ if (discoveredDevices[i] != newDeviceInfo) {
+ discoveredDevices.replace(i, newDeviceInfo);
+ emit q_ptr->deviceDiscovered(newDeviceInfo);
+ } else {
+ if (!updatedFields.testFlag(QBluetoothDeviceInfo::Field::None))
+ emit q_ptr->deviceUpdated(discoveredDevices[i], updatedFields);
+ }
+
return;
+ }
discoveredDevices.replace(i, newDeviceInfo);
emit q_ptr->deviceDiscovered(newDeviceInfo);
+
+ if (!updatedFields.testFlag(QBluetoothDeviceInfo::Field::None))
+ emit q_ptr->deviceUpdated(discoveredDevices[i], updatedFields);
+
return;
}
}
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
index 4657da82..f62ca0dd 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_osx.mm
@@ -423,8 +423,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(IOBluetoothDeviceInquiry
deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
deviceInfo.setRssi(device.RSSI);
- const QList<QBluetoothUuid> uuids(OSXBluetooth::extract_services_uuids(device));
- deviceInfo.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete);
+ const QVector<QBluetoothUuid> uuids(OSXBluetooth::extract_services_uuids(device));
+ deviceInfo.setServiceUuids(uuids);
deviceFound(deviceInfo);
}
@@ -525,14 +525,53 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QBluetoothDeviceIn
const bool isLE = newDeviceInfo.coreConfigurations() == QBluetoothDeviceInfo::LowEnergyCoreConfiguration;
for (int i = 0, e = discoveredDevices.size(); i < e; ++i) {
- if (isLE ? discoveredDevices[i].deviceUuid() == newDeviceInfo.deviceUuid():
- discoveredDevices[i].address() == newDeviceInfo.address()) {
- if (discoveredDevices[i] == newDeviceInfo && (!isLE || lowEnergySearchTimeout > 0))
+ if (isLE) {
+ if (discoveredDevices[i].deviceUuid() == newDeviceInfo.deviceUuid()) {
+ QBluetoothDeviceInfo::Fields updatedFields = QBluetoothDeviceInfo::Field::None;
+ if (discoveredDevices[i].rssi() != newDeviceInfo.rssi()) {
+ qCDebug(QT_BT_OSX) << "Updating RSSI for" << newDeviceInfo.address()
+ << newDeviceInfo.rssi();
+ discoveredDevices[i].setRssi(newDeviceInfo.rssi());
+ updatedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI);
+ }
+
+ if (discoveredDevices[i].manufacturerData() != newDeviceInfo.manufacturerData()) {
+ qCDebug(QT_BT_OSX) << "Updating manufacturer data for" << newDeviceInfo.address();
+ const QVector<quint16> keys = newDeviceInfo.manufacturerIds();
+ for (auto key: keys)
+ discoveredDevices[i].setManufacturerData(key, newDeviceInfo.manufacturerData(key));
+ updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
+ }
+
+ if (lowEnergySearchTimeout > 0) {
+ if (discoveredDevices[i] != newDeviceInfo) {
+ discoveredDevices.replace(i, newDeviceInfo);
+ emit q_ptr->deviceDiscovered(newDeviceInfo);
+ } else {
+ if (!updatedFields.testFlag(QBluetoothDeviceInfo::Field::None))
+ emit q_ptr->deviceUpdated(discoveredDevices[i], updatedFields);
+ }
+
+ return;
+ }
+
+ discoveredDevices.replace(i, newDeviceInfo);
+ emit q_ptr->deviceDiscovered(newDeviceInfo);
+
+ if (!updatedFields.testFlag(QBluetoothDeviceInfo::Field::None))
+ emit q_ptr->deviceUpdated(discoveredDevices[i], updatedFields);
+
return;
+ }
+ } else {
+ if (discoveredDevices[i].address() == newDeviceInfo.address()) {
+ if (discoveredDevices[i] == newDeviceInfo)
+ return;
- discoveredDevices.replace(i, newDeviceInfo);
- emit q_ptr->deviceDiscovered(newDeviceInfo);
- return;
+ discoveredDevices.replace(i, newDeviceInfo);
+ emit q_ptr->deviceDiscovered(newDeviceInfo);
+ return;
+ }
}
}
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
index ce31392f..3e76c13d 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
@@ -81,6 +81,9 @@ QT_END_NAMESPACE
#ifdef QT_WINRT_BLUETOOTH
#include <QtCore/QPointer>
#include <QtCore/QTimer>
+
+using ManufacturerData = QHash<quint16, QByteArray>;
+Q_DECLARE_METATYPE(ManufacturerData)
#endif
QT_BEGIN_NAMESPACE
@@ -167,6 +170,8 @@ private:
#ifdef QT_WINRT_BLUETOOTH
private slots:
void registerDevice(const QBluetoothDeviceInfo &info);
+ void updateDeviceData(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields fields,
+ qint16 rssi, ManufacturerData manufacturerData);
void onScanFinished();
private:
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
index ef2a69b1..e0209693 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
@@ -47,9 +47,12 @@
#endif
#include "qfunctions_winrt.h"
+#include <QtBluetooth/private/qtbluetoothglobal_p.h>
+#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
+#include <robuffer.h>
#include <wrl.h>
#include <windows.devices.enumeration.h>
#include <windows.devices.bluetooth.h>
@@ -66,6 +69,7 @@ using namespace ABI::Windows::Devices;
using namespace ABI::Windows::Devices::Bluetooth;
using namespace ABI::Windows::Devices::Bluetooth::Advertisement;
using namespace ABI::Windows::Devices::Enumeration;
+using namespace ABI::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
@@ -77,6 +81,54 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
ret; \
}
+#define WARN_AND_CONTINUE_IF_FAILED(msg) \
+ if (FAILED(hr)) { \
+ qCWarning(QT_BT_WINRT) << msg; \
+ continue; \
+ }
+
+static QByteArray byteArrayFromBuffer(const ComPtr<IBuffer> &buffer)
+{
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
+ HRESULT hr = buffer.As(&byteAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ char *data;
+ hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
+ Q_ASSERT_SUCCEEDED(hr);
+ UINT32 size;
+ hr = buffer->get_Length(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ return QByteArray(data, int(size));
+}
+
+
+static ManufacturerData extractManufacturerData(ComPtr<IBluetoothLEAdvertisement> ad)
+{
+ ManufacturerData ret;
+ ComPtr<IVector<BluetoothLEManufacturerData*>> data;
+ HRESULT hr = ad->get_ManufacturerData(&data);
+ WARN_AND_RETURN_IF_FAILED("Could not obtain list of manufacturer data.", return ret);
+ quint32 size;
+ hr = data->get_Size(&size);
+ WARN_AND_RETURN_IF_FAILED("Could not obtain manufacturer data's list size.", return ret);
+ for (quint32 i = 0; i < size; ++i) {
+ ComPtr<IBluetoothLEManufacturerData> d;
+ hr = data->GetAt(i, &d);
+ WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data.");
+ quint16 id;
+ hr = d->get_CompanyId(&id);
+ WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data company id.");
+ ComPtr<IBuffer> buffer;
+ hr = d->get_Data(&buffer);
+ WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data set.");
+ const QByteArray bufferData = byteArrayFromBuffer(buffer);
+ if (ret.contains(id))
+ qCWarning(QT_BT_WINRT) << "Company ID already present in manufacturer data.";
+ ret.insert(id, bufferData);
+ }
+ return ret;
+}
+
class QWinRTBluetoothDeviceDiscoveryWorker : public QObject
{
Q_OBJECT
@@ -84,7 +136,7 @@ public:
explicit QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods);
~QWinRTBluetoothDeviceDiscoveryWorker();
void start();
- void stop();
+ void stopLEWatcher();
private:
void startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode);
@@ -105,13 +157,18 @@ private:
CheckForPairing,
OmitPairingCheck
};
- HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device, PairingCheck pairingCheck = CheckForPairing);
+ HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device, PairingCheck pairingCheck);
+#if QT_CONFIG(winrt_btle_no_pairing)
+ HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device);
+#endif
public slots:
void finishDiscovery();
Q_SIGNALS:
void deviceFound(const QBluetoothDeviceInfo &info);
+ void deviceDataChanged(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields,
+ qint16 rssi, ManufacturerData manufacturerData);
void scanFinished();
public:
@@ -120,7 +177,17 @@ public:
private:
ComPtr<IBluetoothLEAdvertisementWatcher> m_leWatcher;
EventRegistrationToken m_leDeviceAddedToken;
- QVector<quint64> m_foundLEDevices;
+#if QT_CONFIG(winrt_btle_no_pairing)
+ QMutex m_foundDevicesMutex;
+ struct LEAdvertisingInfo {
+ QVector<QBluetoothUuid> services;
+ qint16 rssi = 0;
+ };
+
+ QMap<quint64, LEAdvertisingInfo> m_foundLEDevicesMap;
+#endif
+ QMap<quint64, qint16> m_foundLEDevices;
+ QMap<quint64, ManufacturerData> m_foundLEManufacturerData;
int m_pendingPairedDevices;
ComPtr<IBluetoothDeviceStatics> m_deviceStatics;
@@ -132,6 +199,8 @@ QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker(QBlue
, m_pendingPairedDevices(0)
{
qRegisterMetaType<QBluetoothDeviceInfo>();
+ qRegisterMetaType<QBluetoothDeviceInfo::Fields>();
+ qRegisterMetaType<ManufacturerData>();
#ifdef CLASSIC_APP_BUILD
CoInitialize(NULL);
@@ -144,7 +213,7 @@ QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker(QBlue
QWinRTBluetoothDeviceDiscoveryWorker::~QWinRTBluetoothDeviceDiscoveryWorker()
{
- stop();
+ stopLEWatcher();
#ifdef CLASSIC_APP_BUILD
CoUninitialize();
#endif
@@ -166,7 +235,7 @@ void QWinRTBluetoothDeviceDiscoveryWorker::start()
qCDebug(QT_BT_WINRT) << "Worker started";
}
-void QWinRTBluetoothDeviceDiscoveryWorker::stop()
+void QWinRTBluetoothDeviceDiscoveryWorker::stopLEWatcher()
{
if (m_leWatcher) {
HRESULT hr = m_leWatcher->Stop();
@@ -191,9 +260,11 @@ void QWinRTBluetoothDeviceDiscoveryWorker::startDeviceDiscovery(QBluetoothDevice
ComPtr<IAsyncOperation<DeviceInformationCollection *>> op;
hr = deviceInformationStatics->FindAllAsyncAqsFilter(deviceSelector.Get(), &op);
WARN_AND_RETURN_IF_FAILED("Could not start bluetooth device discovery operation", return);
+ QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
hr = op->put_Completed(
- Callback<IAsyncOperationCompletedHandler<DeviceInformationCollection *>>([this, mode](IAsyncOperation<DeviceInformationCollection *> *op, AsyncStatus) {
- onDeviceDiscoveryFinished(op, mode);
+ Callback<IAsyncOperationCompletedHandler<DeviceInformationCollection *>>([thisPointer, mode](IAsyncOperation<DeviceInformationCollection *> *op, AsyncStatus status) {
+ if (status == Completed && thisPointer)
+ thisPointer->onDeviceDiscoveryFinished(op, mode);
return S_OK;
}).Get());
WARN_AND_RETURN_IF_FAILED("Could not add callback to bluetooth device discovery operation", return);
@@ -239,7 +310,8 @@ void QWinRTBluetoothDeviceDiscoveryWorker::gatherMultipleDeviceInformation(quint
{
for (quint32 i = 0; i < deviceCount; ++i) {
ComPtr<IDeviceInformation> device;
- HRESULT hr = devices->GetAt(i, &device);
+ HRESULT hr;
+ hr = devices->GetAt(i, &device);
Q_ASSERT_SUCCEEDED(hr);
gatherDeviceInformation(device.Get(), mode);
}
@@ -249,15 +321,104 @@ void QWinRTBluetoothDeviceDiscoveryWorker::setupLEDeviceWatcher()
{
HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_Advertisement_BluetoothLEAdvertisementWatcher).Get(), &m_leWatcher);
Q_ASSERT_SUCCEEDED(hr);
+#if QT_CONFIG(winrt_btle_no_pairing)
+ if (supportsNewLEApi()) {
+ hr = m_leWatcher->put_ScanningMode(BluetoothLEScanningMode_Active);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+#endif // winrt_btle_no_pairing
hr = m_leWatcher->add_Received(Callback<ITypedEventHandler<BluetoothLEAdvertisementWatcher *, BluetoothLEAdvertisementReceivedEventArgs *>>([this](IBluetoothLEAdvertisementWatcher *, IBluetoothLEAdvertisementReceivedEventArgs *args) {
quint64 address;
HRESULT hr;
hr = args->get_BluetoothAddress(&address);
Q_ASSERT_SUCCEEDED(hr);
- if (m_foundLEDevices.contains(address))
- return S_OK;
-
- m_foundLEDevices.append(address);
+ qint16 rssi;
+ hr = args->get_RawSignalStrengthInDBm(&rssi);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IBluetoothLEAdvertisement> ad;
+ hr = args->get_Advertisement(&ad);
+ Q_ASSERT_SUCCEEDED(hr);
+ const ManufacturerData manufacturerData = extractManufacturerData(ad);
+ QBluetoothDeviceInfo::Fields changedFields = QBluetoothDeviceInfo::Field::None;
+ if (!m_foundLEManufacturerData.contains(address)) {
+ m_foundLEManufacturerData.insert(address, manufacturerData);
+ changedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
+ } else if (m_foundLEManufacturerData.value(address) != manufacturerData) {
+ m_foundLEManufacturerData[address] = manufacturerData;
+ changedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
+ }
+#if QT_CONFIG(winrt_btle_no_pairing)
+ if (supportsNewLEApi()) {
+ ComPtr<IVector<GUID>> guids;
+ hr = ad->get_ServiceUuids(&guids);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 size;
+ hr = guids->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ QVector<QBluetoothUuid> serviceUuids;
+ for (quint32 i = 0; i < size; ++i) {
+ GUID guid;
+ hr = guids->GetAt(i, &guid);
+ Q_ASSERT_SUCCEEDED(hr);
+ QBluetoothUuid uuid(guid);
+ serviceUuids.append(uuid);
+ }
+ QMutexLocker locker(&m_foundDevicesMutex);
+ // Merge newly found services with list of currently found ones
+ if (m_foundLEDevicesMap.contains(address)) {
+ if (size == 0)
+ return S_OK;
+ const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.value(address);
+ QVector<QBluetoothUuid> foundServices = adInfo.services;
+ if (adInfo.rssi != rssi) {
+ m_foundLEDevicesMap[address].rssi = rssi;
+ changedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI);
+ }
+ bool newServiceAdded = false;
+ for (const QBluetoothUuid &uuid : qAsConst(serviceUuids)) {
+ if (!foundServices.contains(uuid)) {
+ foundServices.append(uuid);
+ newServiceAdded = true;
+ }
+ }
+ if (!newServiceAdded) {
+ if (!changedFields.testFlag(QBluetoothDeviceInfo::Field::None)) {
+ QMetaObject::invokeMethod(this, "deviceDataChanged", Qt::AutoConnection,
+ Q_ARG(QBluetoothAddress, QBluetoothAddress(address)),
+ Q_ARG(QBluetoothDeviceInfo::Fields, changedFields),
+ Q_ARG(qint16, rssi),
+ Q_ARG(ManufacturerData, manufacturerData));
+ }
+ return S_OK;
+ }
+ m_foundLEDevicesMap[address].services = foundServices;
+ } else {
+ LEAdvertisingInfo info;
+ info.services = std::move(serviceUuids);
+ info.rssi = rssi;
+ m_foundLEDevicesMap.insert(address, info);
+ }
+
+ locker.unlock();
+ } else
+#endif
+ {
+ if (m_foundLEDevices.contains(address)) {
+ if (m_foundLEDevices.value(address) != rssi) {
+ m_foundLEDevices[address] = rssi;
+ changedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI);
+ }
+ if (!changedFields.testFlag(QBluetoothDeviceInfo::Field::None)) {
+ QMetaObject::invokeMethod(this, "deviceDataChanged", Qt::AutoConnection,
+ Q_ARG(QBluetoothAddress, QBluetoothAddress(address)),
+ Q_ARG(QBluetoothDeviceInfo::Fields, changedFields),
+ Q_ARG(qint16, rssi),
+ Q_ARG(ManufacturerData, manufacturerData));
+ }
+ return S_OK;
+ }
+ m_foundLEDevices.insert(address, rssi);
+ }
leBluetoothInfoFromAddressAsync(address);
return S_OK;
}).Get(), &m_leDeviceAddedToken);
@@ -269,6 +430,7 @@ void QWinRTBluetoothDeviceDiscoveryWorker::setupLEDeviceWatcher()
void QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery()
{
emit scanFinished();
+ stopLEWatcher();
deleteLater();
}
@@ -288,9 +450,14 @@ void QWinRTBluetoothDeviceDiscoveryWorker::classicBluetoothInfoFromDeviceIdAsync
qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from id";
return S_OK;
}
-
+ QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
- (this, &QWinRTBluetoothDeviceDiscoveryWorker::onPairedClassicBluetoothDeviceFoundAsync).Get());
+ ([thisPointer](IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
+ {
+ if (status == Completed && thisPointer)
+ thisPointer->onPairedClassicBluetoothDeviceFoundAsync(op, status);
+ return S_OK;
+ }).Get());
if (FAILED(hr)) {
--m_pendingPairedDevices;
if (!m_pendingPairedDevices
@@ -317,9 +484,14 @@ void QWinRTBluetoothDeviceDiscoveryWorker::leBluetoothInfoFromDeviceIdAsync(HSTR
qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from id";
return S_OK;
}
-
+ QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothLEDevice *>>
- (this, &QWinRTBluetoothDeviceDiscoveryWorker::onPairedBluetoothLEDeviceFoundAsync).Get());
+ ([thisPointer] (IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
+ {
+ if (status == Completed && thisPointer)
+ thisPointer->onPairedBluetoothLEDeviceFoundAsync(op, status);
+ return S_OK;
+ }).Get());
if (FAILED(hr)) {
--m_pendingPairedDevices;
qCWarning(QT_BT_WINRT) << "Could not register device found callback";
@@ -343,9 +515,14 @@ void QWinRTBluetoothDeviceDiscoveryWorker::leBluetoothInfoFromAddressAsync(quint
qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from address";
return S_OK;
}
-
+ QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothLEDevice *>>
- (this, &QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFoundAsync).Get());
+ ([thisPointer](IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
+ {
+ if (status == Completed && thisPointer)
+ thisPointer->onBluetoothLEDeviceFoundAsync(op, status);
+ return S_OK;
+ }).Get());
if (FAILED(hr)) {
qCWarning(QT_BT_WINRT) << "Could not register device found callback";
return S_OK;
@@ -391,7 +568,7 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedClassicBluetoothDeviceFoun
uint serviceCount;
hr = deviceServices->get_Size(&serviceCount);
Q_ASSERT_SUCCEEDED(hr);
- QList<QBluetoothUuid> uuids;
+ QVector<QBluetoothUuid> uuids;
for (uint i = 0; i < serviceCount; ++i) {
ComPtr<Rfcomm::IRfcommDeviceService> service;
hr = deviceServices->GetAt(i, &service);
@@ -410,7 +587,7 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedClassicBluetoothDeviceFoun
QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, classOfDeviceInt);
info.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
- info.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete);
+ info.setServiceUuids(uuids);
info.setCached(true);
QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
@@ -431,7 +608,12 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedBluetoothLEDeviceFoundAsyn
HRESULT hr;
hr = op->GetResults(&device);
Q_ASSERT_SUCCEEDED(hr);
- return onBluetoothLEDeviceFound(device, OmitPairingCheck);
+#if QT_CONFIG(winrt_btle_no_pairing)
+ if (supportsNewLEApi())
+ return onBluetoothLEDeviceFound(device);
+ else
+#endif
+ return onBluetoothLEDeviceFound(device, OmitPairingCheck);
}
HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
@@ -443,7 +625,12 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFoundAsync(IAsy
HRESULT hr;
hr = op->GetResults(&device);
Q_ASSERT_SUCCEEDED(hr);
- return onBluetoothLEDeviceFound(device, PairingCheck::CheckForPairing);
+#if QT_CONFIG(winrt_btle_no_pairing)
+ if (supportsNewLEApi())
+ return onBluetoothLEDeviceFound(device);
+ else
+#endif
+ return onBluetoothLEDeviceFound(device, PairingCheck::CheckForPairing);
}
HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device, PairingCheck pairingCheck)
@@ -479,7 +666,7 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IB
QPointer<QWinRTBluetoothDeviceDiscoveryWorker> tPointer(this);
hr = pairing.Get()->PairAsync(&pairingOp);
Q_ASSERT_SUCCEEDED(hr);
- pairingOp.Get()->put_Completed(
+ pairingOp->put_Completed(
Callback<IAsyncOperationCompletedHandler<DevicePairingResult *>>([device, tPointer](IAsyncOperation<DevicePairingResult *> *op, AsyncStatus status) {
if (!tPointer)
return S_OK;
@@ -520,7 +707,7 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IB
uint serviceCount;
hr = deviceServices->get_Size(&serviceCount);
Q_ASSERT_SUCCEEDED(hr);
- QList<QBluetoothUuid> uuids;
+ QVector<QBluetoothUuid> uuids;
for (uint i = 0; i < serviceCount; ++i) {
ComPtr<GenericAttributeProfile::IGattDeviceService> service;
hr = deviceServices->GetAt(i, &service);
@@ -531,19 +718,104 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IB
Q_ASSERT_SUCCEEDED(hr);
uuids.append(QBluetoothUuid(uuid));
}
+ const qint16 rssi = m_foundLEDevices.value(address);
+ const ManufacturerData manufacturerData = m_foundLEManufacturerData.value(address);
qCDebug(QT_BT_WINRT) << "Discovered BTLE device: " << QString::number(address) << btName
- << "Num UUIDs" << uuids.count();
+ << "Num UUIDs" << uuids.count() << "RSSI:" << rssi
+ << "Num manufacturer data" << manufacturerData.count();
+
+ QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, 0);
+ info.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
+ info.setServiceUuids(uuids);
+ info.setRssi(rssi);
+ for (const quint16 key : manufacturerData.keys())
+ info.setManufacturerData(key, manufacturerData.value(key));
+ info.setCached(true);
+
+ QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
+ Q_ARG(QBluetoothDeviceInfo, info));
+ return S_OK;
+}
+
+#if QT_CONFIG(winrt_btle_no_pairing)
+HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device)
+{
+ if (!device) {
+ qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: No device given";
+ return S_OK;
+ }
+
+ UINT64 address;
+ HString name;
+ HRESULT 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));
+
+ ComPtr<IBluetoothLEDevice2> device2;
+ hr = device.As(&device2);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IDeviceInformation> deviceInfo;
+ hr = device2->get_DeviceInformation(&deviceInfo);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (!deviceInfo) {
+ qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: Could not obtain device information";
+ return S_OK;
+ }
+ ComPtr<IDeviceInformation2> deviceInfo2;
+ hr = deviceInfo.As(&deviceInfo2);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IDeviceInformationPairing> pairing;
+ hr = deviceInfo2->get_Pairing(&pairing);
+ Q_ASSERT_SUCCEEDED(hr);
+ boolean isPaired;
+ hr = pairing->get_IsPaired(&isPaired);
+ Q_ASSERT_SUCCEEDED(hr);
+ QList<QBluetoothUuid> uuids;
+
+ const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.value(address);
+ const qint16 rssi = adInfo.rssi;
+ // Use the services obtained from the advertisement data if the device is not paired
+ if (!isPaired) {
+ uuids = adInfo.services.toList();
+ } else {
+ IVectorView <GenericAttributeProfile::GattDeviceService *> *deviceServices;
+ hr = device->get_GattServices(&deviceServices);
+ Q_ASSERT_SUCCEEDED(hr);
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<GenericAttributeProfile::IGattDeviceService> service;
+ hr = deviceServices->GetAt(i, &service);
+ Q_ASSERT_SUCCEEDED(hr);
+ GUID uuid;
+ hr = service->get_Uuid(&uuid);
+ Q_ASSERT_SUCCEEDED(hr);
+ uuids.append(QBluetoothUuid(uuid));
+ }
+ }
+ const ManufacturerData manufacturerData = m_foundLEManufacturerData.value(address);
+
+ qCDebug(QT_BT_WINRT) << "Discovered BTLE device: " << QString::number(address) << btName
+ << "Num UUIDs" << uuids.count() << "RSSI:" << rssi
+ << "Num manufacturer data" << manufacturerData.count();
QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, 0);
info.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
info.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete);
+ info.setRssi(rssi);
+ for (quint16 key : manufacturerData.keys())
+ info.setManufacturerData(key, manufacturerData.value(key));
info.setCached(true);
QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
Q_ARG(QBluetoothDeviceInfo, info));
return S_OK;
}
+#endif // QT_CONFIG(winrt_btle_no_pairing)
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
const QBluetoothAddress &deviceAdapter,
@@ -582,6 +854,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
discoveredDevices.clear();
connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
+ connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData);
connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
worker->start();
@@ -602,7 +876,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
if (worker) {
- worker->stop();
+ worker->stopLEWatcher();
disconnectAndClearWorker();
emit q->canceled();
}
@@ -625,7 +899,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDevic
uuids.append(info.serviceUuids());
const QSet<QBluetoothUuid> uuidSet = uuids.toSet();
if (iter->serviceUuids().count() != uuidSet.count())
- iter->setServiceUuids(uuidSet.toList(), QBluetoothDeviceInfo::DataIncomplete);
+ iter->setServiceUuids(uuidSet.toList().toVector());
if (iter->coreConfigurations() != info.coreConfigurations())
iter->setCoreConfigurations(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration);
return;
@@ -636,6 +910,30 @@ void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDevic
emit q->deviceDiscovered(info);
}
+void QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData(const QBluetoothAddress &address,
+ QBluetoothDeviceInfo::Fields fields,
+ qint16 rssi,
+ ManufacturerData manufacturerData)
+{
+ if (fields.testFlag(QBluetoothDeviceInfo::Field::None))
+ return;
+
+ Q_Q(QBluetoothDeviceDiscoveryAgent);
+ for (QList<QBluetoothDeviceInfo>::iterator iter = discoveredDevices.begin();
+ iter != discoveredDevices.end(); ++iter) {
+ if (iter->address() == address) {
+ qCDebug(QT_BT_WINRT) << "Updating data for device" << iter->name() << iter->address();
+ if (fields.testFlag(QBluetoothDeviceInfo::Field::RSSI))
+ iter->setRssi(rssi);
+ if (fields.testFlag(QBluetoothDeviceInfo::Field::ManufacturerData))
+ for (quint16 key : manufacturerData.keys())
+ iter->setManufacturerData(key, manufacturerData.value(key));
+ emit q->deviceUpdated(*iter, fields);
+ return;
+ }
+ }
+}
+
void QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished()
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
@@ -645,17 +943,18 @@ void QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished()
void QBluetoothDeviceDiscoveryAgentPrivate::disconnectAndClearWorker()
{
- Q_Q(QBluetoothDeviceDiscoveryAgent);
if (!worker)
return;
disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
- this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
- q, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered);
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
+ disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData);
if (leScanTimer) {
disconnect(leScanTimer, &QTimer::timeout,
- worker, &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery);
+ worker, &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery);
}
worker.clear();
}
diff --git a/src/bluetooth/qbluetoothdeviceinfo.cpp b/src/bluetooth/qbluetoothdeviceinfo.cpp
index bde8655e..46df5c7b 100644
--- a/src/bluetooth/qbluetoothdeviceinfo.cpp
+++ b/src/bluetooth/qbluetoothdeviceinfo.cpp
@@ -61,7 +61,10 @@ QT_BEGIN_NAMESPACE
\value MiscellaneousDevice A miscellaneous device.
\value ComputerDevice A computer device or PDA.
\value PhoneDevice A telephone device.
- \value LANAccessDevice A device that provides access to a local area network.
+ \value LANAccessDevice A device that provides access to a local area network
+ (deprecated since Qt 5.13 and replaced by
+ \l QBluetoothDeviceInfo::NetworkDevice).
+ \value NetworkDevice A device that provides access to a local area network (since Qt 5.13).
\value AudioVideoDevice A device capable of playback or capture of audio and/or video.
\value PeripheralDevice A peripheral device such as a keyboard, mouse, and so on.
\value ImagingDevice An imaging device such as a display, printer, scanner or camera.
@@ -536,6 +539,8 @@ quint8 QBluetoothDeviceInfo::minorDeviceClass() const
}
/*!
+ \deprecated
+
Sets the list of service UUIDs to \a uuids and the completeness of the data to \a completeness.
*/
void QBluetoothDeviceInfo::setServiceUuids(const QList<QBluetoothUuid> &uuids,
@@ -543,11 +548,38 @@ void QBluetoothDeviceInfo::setServiceUuids(const QList<QBluetoothUuid> &uuids,
{
Q_D(QBluetoothDeviceInfo);
- d->serviceUuids = uuids;
+ d->serviceUuids = uuids.toVector();
d->serviceUuidsCompleteness = completeness;
}
/*!
+ Sets the list of service UUIDs to \a uuids.
+ \since 5.13
+ */
+void QBluetoothDeviceInfo::setServiceUuids(const QVector<QBluetoothUuid> &uuids)
+{
+ Q_D(QBluetoothDeviceInfo);
+ d->serviceUuids = uuids;
+}
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+/*!
+ Returns the list of service UUIDS supported by the device. Most commonly this
+ list of uuids represents custom uuids or a uuid value specified by
+ \l QBluetoothUuid::ServiceClassUuid.
+
+ \sa serviceUuids()
+ \since 6.0
+*/
+QVector<QBluetoothUuid> QBluetoothDeviceInfo::serviceUuids() const
+{
+ Q_D(const QBluetoothDeviceInfo);
+ return d->serviceUuids;
+}
+
+#else
+
+/*!
Returns the list of service UUIDS supported by the device. If \a completeness is not 0 it will
be set to DataComplete and the complete list of UUIDs supported by the device is returned.
DataIncomplete if additional service UUIDs are supported by the device and DataUnavailable if
@@ -562,10 +594,13 @@ QList<QBluetoothUuid> QBluetoothDeviceInfo::serviceUuids(DataCompleteness *compl
if (completeness)
*completeness = d->serviceUuidsCompleteness;
- return d->serviceUuids;
+ return d->serviceUuids.toList();
}
+#endif //QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
/*!
+ \deprecated
+
Returns the completeness of the service UUID list. If DataComplete is returned,
serviceUuids() returns the complete list of service UUIDs supported by the device, otherwise
only the partial or empty list of service UUIDs. To get a list
@@ -612,7 +647,6 @@ QVector<quint16> QBluetoothDeviceInfo::manufacturerIds() const
*/
QByteArray QBluetoothDeviceInfo::manufacturerData(quint16 manufacturerId) const
{
- // TODO Currently not implemented on WinRT
Q_D(const QBluetoothDeviceInfo);
return d->manufacturerData.value(manufacturerId);
}
diff --git a/src/bluetooth/qbluetoothdeviceinfo.h b/src/bluetooth/qbluetoothdeviceinfo.h
index d59eb27d..11cb2bea 100644
--- a/src/bluetooth/qbluetoothdeviceinfo.h
+++ b/src/bluetooth/qbluetoothdeviceinfo.h
@@ -60,7 +60,10 @@ public:
MiscellaneousDevice = 0,
ComputerDevice = 1,
PhoneDevice = 2,
- LANAccessDevice = 3, // TODO Qt 6 rename to NetworkDevice -> inconsistency with MinorNetworkClass
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ LANAccessDevice = 3,
+#endif
+ NetworkDevice = 3,
AudioVideoDevice = 4,
PeripheralDevice = 5,
ImagingDevice = 6,
@@ -191,12 +194,14 @@ public:
};
Q_DECLARE_FLAGS(ServiceClasses, ServiceClass)
- //TODO Qt6 Remove DataCompleteness -> it serves no purpose
+#if QT_DEPRECATED_SINCE(5, 13)
+ // adding QT_DEPRECATED causes compile failure with gcc 7
enum DataCompleteness {
DataComplete,
DataIncomplete,
DataUnavailable
};
+#endif
enum class Field {
None = 0x0000,
@@ -241,9 +246,19 @@ public:
qint16 rssi() const;
void setRssi(qint16 signal);
- void setServiceUuids(const QList<QBluetoothUuid> &uuids, DataCompleteness completeness);
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED void setServiceUuids(const QList<QBluetoothUuid> &uuids, DataCompleteness completeness);
+ QT_DEPRECATED DataCompleteness serviceUuidsCompleteness() const;
+#endif
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#ifndef Q_QDOC //suppress qdoc warnings
+ QVector<QBluetoothUuid> serviceUuids() const;
+#endif // Q_QDOC
+#else
QList<QBluetoothUuid> serviceUuids(DataCompleteness *completeness = nullptr) const;
- DataCompleteness serviceUuidsCompleteness() const;
+#endif
+ void setServiceUuids(const QVector<QBluetoothUuid> &uuids);
QVector<quint16> manufacturerIds() const;
QByteArray manufacturerData(quint16 manufacturerId) const;
@@ -269,5 +284,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QBluetoothDeviceInfo::ServiceClasses)
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QBluetoothDeviceInfo)
+#ifdef QT_WINRT_BLUETOOTH
+Q_DECLARE_METATYPE(QBluetoothDeviceInfo::Fields)
+#endif
#endif
diff --git a/src/bluetooth/qbluetoothdeviceinfo_p.h b/src/bluetooth/qbluetoothdeviceinfo_p.h
index 15c9e21c..3c19b10f 100644
--- a/src/bluetooth/qbluetoothdeviceinfo_p.h
+++ b/src/bluetooth/qbluetoothdeviceinfo_p.h
@@ -78,7 +78,7 @@ public:
quint8 minorDeviceClass;
QBluetoothDeviceInfo::DataCompleteness serviceUuidsCompleteness;
- QList<QBluetoothUuid> serviceUuids;
+ QVector<QBluetoothUuid> serviceUuids;
QHash<quint16, QByteArray> manufacturerData;
QBluetoothDeviceInfo::CoreConfigurations deviceCoreConfiguration;
diff --git a/src/bluetooth/qbluetoothlocaldevice.cpp b/src/bluetooth/qbluetoothlocaldevice.cpp
index 173650a0..38dd56f4 100644
--- a/src/bluetooth/qbluetoothlocaldevice.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice.cpp
@@ -326,6 +326,6 @@ bool QBluetoothLocalDevice::isValid() const
the resulting local device selects the local default device.
*/
-#include "moc_qbluetoothlocaldevice.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qbluetoothlocaldevice.cpp"
diff --git a/src/bluetooth/qbluetoothserver.cpp b/src/bluetooth/qbluetoothserver.cpp
index 8f760eed..6991518f 100644
--- a/src/bluetooth/qbluetoothserver.cpp
+++ b/src/bluetooth/qbluetoothserver.cpp
@@ -323,6 +323,6 @@ QBluetoothServer::Error QBluetoothServer::error() const
return d->m_lastError;
}
-#include "moc_qbluetoothserver.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qbluetoothserver.cpp"
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
index 0f6fdc63..da9c1386 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
@@ -580,6 +580,6 @@ bool QBluetoothServiceDiscoveryAgentPrivate::isDuplicatedService(
return false;
}
-#include "moc_qbluetoothservicediscoveryagent.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qbluetoothservicediscoveryagent.cpp"
diff --git a/src/bluetooth/qbluetoothsocket.cpp b/src/bluetooth/qbluetoothsocket.cpp
index eecb1401..e6e1d955 100644
--- a/src/bluetooth/qbluetoothsocket.cpp
+++ b/src/bluetooth/qbluetoothsocket.cpp
@@ -840,6 +840,6 @@ QDebug operator<<(QDebug debug, QBluetoothSocket::SocketState state)
}
#endif
-#include "moc_qbluetoothsocket.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qbluetoothsocket.cpp"
diff --git a/src/bluetooth/qbluetoothtransfermanager.cpp b/src/bluetooth/qbluetoothtransfermanager.cpp
index 165faceb..37a3191a 100644
--- a/src/bluetooth/qbluetoothtransfermanager.cpp
+++ b/src/bluetooth/qbluetoothtransfermanager.cpp
@@ -130,6 +130,7 @@ QBluetoothTransferReply *QBluetoothTransferManager::put(const QBluetoothTransfer
return 0;
#endif
}
-#include "moc_qbluetoothtransfermanager.cpp"
QT_END_NAMESPACE
+
+#include "moc_qbluetoothtransfermanager.cpp"
diff --git a/src/bluetooth/qbluetoothtransferreply.cpp b/src/bluetooth/qbluetoothtransferreply.cpp
index 0faea96c..a5da8f8f 100644
--- a/src/bluetooth/qbluetoothtransferreply.cpp
+++ b/src/bluetooth/qbluetoothtransferreply.cpp
@@ -209,6 +209,6 @@ QBluetoothTransferReplyPrivate::QBluetoothTransferReplyPrivate()
{
}
-#include "moc_qbluetoothtransferreply.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qbluetoothtransferreply.cpp"
diff --git a/src/bluetooth/qbluetoothutils_winrt.cpp b/src/bluetooth/qbluetoothutils_winrt.cpp
new file mode 100644
index 00000000..1d44221b
--- /dev/null
+++ b/src/bluetooth/qbluetoothutils_winrt.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothutils_winrt_p.h"
+#include <QtBluetooth/private/qtbluetoothglobal_p.h>
+
+#include <QtCore/qfunctions_winrt.h>
+
+#include <wrl.h>
+#include <windows.foundation.metadata.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation::Metadata;
+
+QT_BEGIN_NAMESPACE
+
+bool supportsNewLEApi()
+{
+ static bool initialized = false;
+ static boolean apiPresent = false;
+ if (initialized)
+ return apiPresent;
+
+ initialized = true;
+#if !QT_CONFIG(winrt_btle_no_pairing)
+ return apiPresent;
+#endif
+
+ ComPtr<IApiInformationStatics> apiInformationStatics;
+ HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(),
+ IID_PPV_ARGS(&apiInformationStatics));
+ if (FAILED(hr))
+ return apiPresent;
+
+ const HStringReference valueRef(L"Windows.Foundation.UniversalApiContract");
+ hr = apiInformationStatics->IsApiContractPresentByMajor(
+ valueRef.Get(), 4, &apiPresent);
+ apiPresent = SUCCEEDED(hr) && apiPresent;
+ return apiPresent;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothutils_winrt_p.h b/src/bluetooth/qbluetoothutils_winrt_p.h
new file mode 100644
index 00000000..c272bae1
--- /dev/null
+++ b/src/bluetooth/qbluetoothutils_winrt_p.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBLUETOOTHUTILS_WINRT_P_H
+#define QBLUETOOTHUTILS_WINRT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+bool supportsNewLEApi();
+
+QT_END_NAMESPACE
+
+#endif // QBLUETOOTHSOCKET_WINRT_P_H
diff --git a/src/bluetooth/qlowenergycharacteristic.h b/src/bluetooth/qlowenergycharacteristic.h
index cb747e32..9b27d621 100644
--- a/src/bluetooth/qlowenergycharacteristic.h
+++ b/src/bluetooth/qlowenergycharacteristic.h
@@ -103,6 +103,7 @@ protected:
friend class QLowEnergyControllerPrivateCommon;
friend class QLowEnergyControllerPrivateOSX;
friend class QLowEnergyControllerPrivateWinRT;
+ friend class QLowEnergyControllerPrivateWinRTNew;
QLowEnergyCharacteristicPrivate *data = nullptr;
QLowEnergyCharacteristic(QSharedPointer<QLowEnergyServicePrivate> p,
QLowEnergyHandle handle);
diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp
index 6b4c17d6..8fc044fb 100644
--- a/src/bluetooth/qlowenergycontroller.cpp
+++ b/src/bluetooth/qlowenergycontroller.cpp
@@ -55,7 +55,11 @@
#elif defined(QT_ANDROID_BLUETOOTH)
#include "qlowenergycontroller_android_p.h"
#elif defined(QT_WINRT_BLUETOOTH)
+#include "qtbluetoothglobal_p.h"
#include "qlowenergycontroller_winrt_p.h"
+#if QT_CONFIG(winrt_btle_no_pairing)
+#include "qlowenergycontroller_winrt_new_p.h"
+#endif
#else
#include "qlowenergycontroller_p.h"
#endif
@@ -65,6 +69,7 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT)
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
/*!
\class QLowEnergyController
@@ -310,7 +315,12 @@ static QLowEnergyControllerPrivate *privateController(QLowEnergyController::Role
return new QLowEnergyControllerPrivateAndroid();
#elif defined(QT_WINRT_BLUETOOTH)
Q_UNUSED(role);
+#if QT_CONFIG(winrt_btle_no_pairing)
+ return createWinRTLowEnergyController();
+#else
+ qCDebug(QT_BT_WINRT) << "Using pre 15063 low energy controller";
return new QLowEnergyControllerPrivateWinRT();
+#endif
#else
Q_UNUSED(role);
return new QLowEnergyControllerPrivateCommon();
diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp
index 6efa2231..989c5443 100644
--- a/src/bluetooth/qlowenergycontroller_winrt.cpp
+++ b/src/bluetooth/qlowenergycontroller_winrt.cpp
@@ -185,7 +185,7 @@ public slots:
GattCharacteristicProperties properties;
hr = characteristic->get_CharacteristicProperties(&properties);
Q_ASSERT_SUCCEEDED(hr);
- charData.properties = QLowEnergyCharacteristic::PropertyTypes(properties);
+ charData.properties = QLowEnergyCharacteristic::PropertyTypes(properties & 0xff);
if (charData.properties & QLowEnergyCharacteristic::Read) {
ComPtr<IAsyncOperation<GattReadResult *>> readOp;
hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
@@ -291,9 +291,7 @@ QLowEnergyControllerPrivateWinRT::~QLowEnergyControllerPrivateWinRT()
if (mDevice && mStatusChangedToken.value)
mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
- qCDebug(QT_BT_WINRT) << "Unregistering " << mValueChangedTokens.count() << " value change tokens";
- for (const ValueChangedEntry &entry : qAsConst(mValueChangedTokens))
- entry.characteristic->remove_ValueChanged(entry.token);
+ unregisterFromValueChanges();
}
void QLowEnergyControllerPrivateWinRT::init()
@@ -340,8 +338,10 @@ void QLowEnergyControllerPrivateWinRT::connectToDevice()
&& status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
setState(QLowEnergyController::ConnectedState);
emit q->connected();
- } else if (state == QLowEnergyController::ConnectedState
+ } else if (state != QLowEnergyController::UnconnectedState
&& status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
+ invalidateServices();
+ unregisterFromValueChanges();
setError(QLowEnergyController::RemoteHostClosedError);
setState(QLowEnergyController::UnconnectedState);
emit q->disconnected();
@@ -436,12 +436,17 @@ void QLowEnergyControllerPrivateWinRT::disconnectFromDevice()
{
qCDebug(QT_BT_WINRT) << __FUNCTION__;
Q_Q(QLowEnergyController);
+ setState(QLowEnergyController::ClosingState);
+ unregisterFromValueChanges();
+ if (mDevice) {
+ if (mStatusChangedToken.value) {
+ mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
+ mStatusChangedToken.value = 0;
+ }
+ mDevice = nullptr;
+ }
setState(QLowEnergyController::UnconnectedState);
emit q->disconnected();
- if (mDevice && mStatusChangedToken.value) {
- mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
- mStatusChangedToken.value = 0;
- }
}
ComPtr<IGattDeviceService> QLowEnergyControllerPrivateWinRT::getNativeService(const QBluetoothUuid &serviceUuid)
@@ -502,6 +507,17 @@ void QLowEnergyControllerPrivateWinRT::registerForValueChanges(const QBluetoothU
<< serviceUuid << "registered for value changes";
}
+void QLowEnergyControllerPrivateWinRT::unregisterFromValueChanges()
+{
+ qCDebug(QT_BT_WINRT) << "Unregistering " << mValueChangedTokens.count() << " value change tokens";
+ HRESULT hr;
+ for (const ValueChangedEntry &entry : qAsConst(mValueChangedTokens)) {
+ hr = entry.characteristic->remove_ValueChanged(entry.token);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ mValueChangedTokens.clear();
+}
+
void QLowEnergyControllerPrivateWinRT::obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer,
ComPtr<IGattDeviceService> service)
{
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
new file mode 100644
index 00000000..42d0a320
--- /dev/null
+++ b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
@@ -0,0 +1,1322 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlowenergycontroller_winrt_new_p.h"
+#include "qlowenergycontroller_winrt_p.h"
+
+#include <QtBluetooth/QLowEnergyCharacteristicData>
+#include <QtBluetooth/QLowEnergyDescriptorData>
+#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
+
+#ifdef CLASSIC_APP_BUILD
+#define Q_OS_WINRT
+#endif
+#include <QtCore/qfunctions_winrt.h>
+#include <QtCore/QtEndian>
+#include <QtCore/QLoggingCategory>
+#include <private/qeventdispatcher_winrt_p.h>
+
+#include <functional>
+#include <robuffer.h>
+#include <windows.devices.enumeration.h>
+#include <windows.devices.bluetooth.h>
+#include <windows.foundation.collections.h>
+#include <windows.foundation.metadata.h>
+#include <windows.storage.streams.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::Foundation::Metadata;
+using namespace ABI::Windows::Devices;
+using namespace ABI::Windows::Devices::Bluetooth;
+using namespace ABI::Windows::Devices::Bluetooth::GenericAttributeProfile;
+using namespace ABI::Windows::Devices::Enumeration;
+using namespace ABI::Windows::Storage::Streams;
+
+QT_BEGIN_NAMESPACE
+
+typedef ITypedEventHandler<BluetoothLEDevice *, IInspectable *> StatusHandler;
+typedef ITypedEventHandler<GattCharacteristic *, GattValueChangedEventArgs *> ValueChangedHandler;
+typedef GattReadClientCharacteristicConfigurationDescriptorResult ClientCharConfigDescriptorResult;
+typedef IGattReadClientCharacteristicConfigurationDescriptorResult IClientCharConfigDescriptorResult;
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+
+QLowEnergyControllerPrivate *createWinRTLowEnergyController()
+{
+ if (supportsNewLEApi()) {
+ qCDebug(QT_BT_WINRT) << "Using new low energy controller";
+ return new QLowEnergyControllerPrivateWinRTNew();
+ }
+
+ qCDebug(QT_BT_WINRT) << "Using pre 15063 low energy controller";
+ return new QLowEnergyControllerPrivateWinRT();
+}
+
+static QByteArray byteArrayFromBuffer(const ComPtr<IBuffer> &buffer, bool isWCharString = false)
+{
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
+ HRESULT hr = buffer.As(&byteAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ char *data;
+ hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
+ Q_ASSERT_SUCCEEDED(hr);
+ UINT32 size;
+ hr = buffer->get_Length(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (isWCharString) {
+ QString valueString = QString::fromUtf16(reinterpret_cast<ushort *>(data)).left(size / 2);
+ return valueString.toUtf8();
+ }
+ return QByteArray(data, int(size));
+}
+
+static QByteArray byteArrayFromGattResult(const ComPtr<IGattReadResult> &gattResult,
+ bool isWCharString = false)
+{
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ HRESULT hr;
+ hr = gattResult->get_Value(&buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ return byteArrayFromBuffer(buffer, isWCharString);
+}
+
+class QWinRTLowEnergyServiceHandlerNew : public QObject
+{
+ Q_OBJECT
+public:
+ QWinRTLowEnergyServiceHandlerNew(const QBluetoothUuid &service,
+ const ComPtr<IGattDeviceService2> &deviceService)
+ : mService(service)
+ , mDeviceService(deviceService)
+ {
+ qCDebug(QT_BT_WINRT) << __FUNCTION__;
+ }
+
+ ~QWinRTLowEnergyServiceHandlerNew()
+ {
+ }
+
+public slots:
+ void obtainCharList()
+ {
+ mIndicateChars.clear();
+ quint16 startHandle = 0;
+ quint16 endHandle = 0;
+ qCDebug(QT_BT_WINRT) << __FUNCTION__;
+ ComPtr<IVectorView<GattCharacteristic *>> characteristics;
+ HRESULT hr = mDeviceService->GetAllCharacteristics(&characteristics);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (!characteristics) {
+ emit charListObtained(mService, mCharacteristicList, mIndicateChars, startHandle, endHandle);
+ QThread::currentThread()->quit();
+ return;
+ }
+
+ uint characteristicsCount;
+ hr = characteristics->get_Size(&characteristicsCount);
+
+ // If there are no characteristics, we assume that the device is not paired (and not
+ // discovered by Windows) and we use new API (GetCharacteristicsAsync) to discover them
+ // without pairing.
+ if (characteristicsCount == 0) {
+ ComPtr<IGattDeviceService3> deviceService3;
+ hr = mDeviceService.As(&deviceService3);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<GattCharacteristicsResult*>> asyncResult;
+ deviceService3->GetCharacteristicsAsync(&asyncResult);
+ hr = asyncResult->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattCharacteristicsResult*>>(
+ [this](IAsyncOperation<GattCharacteristicsResult*> *, AsyncStatus status) {
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain characteristics";
+ return S_OK;
+ }
+ // TODO We should check if we found any characteristics. It makes no sense but
+ // there is a possibility that device doesn't state any characteristics under a service.
+ // So, for sanity, we should not continue endless loop here.
+ obtainCharList();
+ return S_OK;
+ }).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return;
+ }
+
+ Q_ASSERT_SUCCEEDED(hr);
+ mCharacteristicsCountToBeDiscovered = characteristicsCount;
+ for (uint i = 0; i < characteristicsCount; ++i) {
+ ComPtr<IGattCharacteristic> characteristic;
+ hr = characteristics->GetAt(i, &characteristic);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IGattCharacteristic3> characteristic3;
+ hr = characteristic.As(&characteristic3);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // For some strange reason, Windows doesn't discover descriptors of characteristics (if not paired).
+ // Qt API assumes that all characteristics and their descriptors are discovered in one go.
+ // So we start 'GetDescriptorsAsync' for each discovered characteristic and finish only
+ // when GetDescriptorsAsync for all characteristics return.
+ ComPtr<IAsyncOperation<GattDescriptorsResult*>> descAsyncResult;
+ hr = characteristic3->GetDescriptorsAsync(&descAsyncResult);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = descAsyncResult->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattDescriptorsResult*>>(
+ [this, characteristic](IAsyncOperation<GattDescriptorsResult *> *op,
+ AsyncStatus status) {
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain descriptors";
+ return S_OK;
+ }
+ quint16 handle;
+
+ HRESULT hr = characteristic->get_AttributeHandle(&handle);
+ Q_ASSERT_SUCCEEDED(hr);
+ QLowEnergyServicePrivate::CharData charData;
+ charData.valueHandle = handle + 1;
+ if (mStartHandle == 0 || mStartHandle > handle)
+ mStartHandle = handle;
+ if (mEndHandle == 0 || mEndHandle < handle)
+ mEndHandle = handle;
+ GUID guuid;
+ hr = characteristic->get_Uuid(&guuid);
+ Q_ASSERT_SUCCEEDED(hr);
+ charData.uuid = QBluetoothUuid(guuid);
+ GattCharacteristicProperties properties;
+ hr = characteristic->get_CharacteristicProperties(&properties);
+ Q_ASSERT_SUCCEEDED(hr);
+ charData.properties = QLowEnergyCharacteristic::PropertyTypes(properties & 0xff);
+ if (charData.properties & QLowEnergyCharacteristic::Read) {
+ ComPtr<IAsyncOperation<GattReadResult *>> readOp;
+ hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached,
+ &readOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IGattReadResult> readResult;
+ hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ if (readResult)
+ charData.value = byteArrayFromGattResult(readResult);
+ }
+
+ ComPtr<IVectorView<GattDescriptor *>> descriptors;
+
+ ComPtr<IGattDescriptorsResult> result;
+ hr = op->GetResults(&result);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = result->get_Descriptors(&descriptors);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ uint descriptorCount;
+ hr = descriptors->get_Size(&descriptorCount);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (uint j = 0; j < descriptorCount; ++j) {
+ QLowEnergyServicePrivate::DescData descData;
+ ComPtr<IGattDescriptor> descriptor;
+ hr = descriptors->GetAt(j, &descriptor);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint16 descHandle;
+ hr = descriptor->get_AttributeHandle(&descHandle);
+ Q_ASSERT_SUCCEEDED(hr);
+ GUID descriptorUuid;
+ hr = descriptor->get_Uuid(&descriptorUuid);
+ Q_ASSERT_SUCCEEDED(hr);
+ descData.uuid = QBluetoothUuid(descriptorUuid);
+ if (descData.uuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
+ ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
+ hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IClientCharConfigDescriptorResult> readResult;
+ hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ GattClientCharacteristicConfigurationDescriptorValue value;
+ hr = readResult->get_ClientCharacteristicConfigurationDescriptor(&value);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint16 result = 0;
+ bool correct = false;
+ if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
+ result |= GattClientCharacteristicConfigurationDescriptorValue_Indicate;
+ correct = true;
+ }
+ if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
+ result |= GattClientCharacteristicConfigurationDescriptorValue_Notify;
+ correct = true;
+ }
+ if (value == GattClientCharacteristicConfigurationDescriptorValue_None) {
+ correct = true;
+ }
+ if (!correct)
+ continue;
+
+ descData.value = QByteArray(2, Qt::Uninitialized);
+ qToLittleEndian(result, descData.value.data());
+ mIndicateChars << charData.uuid;
+ } else {
+ ComPtr<IAsyncOperation<GattReadResult *>> readOp;
+ hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached,
+ &readOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IGattReadResult> readResult;
+ hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ if (descData.uuid == QBluetoothUuid::CharacteristicUserDescription)
+ descData.value = byteArrayFromGattResult(readResult, true);
+ else
+ descData.value = byteArrayFromGattResult(readResult);
+ }
+ charData.descriptorList.insert(descHandle, descData);
+ }
+
+ mCharacteristicList.insert(handle, charData);
+ mCharacteristicsCountToBeDiscovered--;
+ if (mCharacteristicsCountToBeDiscovered == 0) {
+ emit charListObtained(mService, mCharacteristicList, mIndicateChars,
+ mStartHandle, mEndHandle);
+ QThread::currentThread()->quit();
+ }
+ return S_OK;
+ }).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ }
+
+public:
+ QBluetoothUuid mService;
+ ComPtr<IGattDeviceService2> mDeviceService;
+ QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> mCharacteristicList;
+ uint mCharacteristicsCountToBeDiscovered;
+ quint16 mStartHandle = 0;
+ quint16 mEndHandle = 0;
+ QVector<QBluetoothUuid> mIndicateChars;
+
+signals:
+ void charListObtained(const QBluetoothUuid &service, QHash<QLowEnergyHandle,
+ QLowEnergyServicePrivate::CharData> charList,
+ QVector<QBluetoothUuid> indicateChars,
+ QLowEnergyHandle startHandle, QLowEnergyHandle endHandle);
+};
+
+QLowEnergyControllerPrivateWinRTNew::QLowEnergyControllerPrivateWinRTNew()
+ : QLowEnergyControllerPrivate()
+{
+ registerQLowEnergyControllerMetaType();
+}
+
+QLowEnergyControllerPrivateWinRTNew::~QLowEnergyControllerPrivateWinRTNew()
+{
+ if (mDevice && mStatusChangedToken.value)
+ mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
+
+ unregisterFromValueChanges();
+}
+
+void QLowEnergyControllerPrivateWinRTNew::init()
+{
+}
+
+void QLowEnergyControllerPrivateWinRTNew::connectToDevice()
+{
+ qCDebug(QT_BT_WINRT) << __FUNCTION__;
+ Q_Q(QLowEnergyController);
+ if (remoteDevice.isNull()) {
+ qWarning() << "Invalid/null remote device address";
+ setError(QLowEnergyController::UnknownRemoteDeviceError);
+ return;
+ }
+
+ setState(QLowEnergyController::ConnectingState);
+
+ ComPtr<IBluetoothLEDeviceStatics> deviceStatics;
+ HRESULT hr = GetActivationFactory(
+ HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(),
+ &deviceStatics);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromIdOperation;
+ hr = deviceStatics->FromBluetoothAddressAsync(remoteDevice.toUInt64(), &deviceFromIdOperation);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(deviceFromIdOperation, mDevice.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ if (!mDevice) {
+ qCDebug(QT_BT_WINRT) << "Could not find LE device";
+ setError(QLowEnergyController::InvalidBluetoothAdapterError);
+ setState(QLowEnergyController::UnconnectedState);
+ }
+ BluetoothConnectionStatus status;
+ hr = mDevice->get_ConnectionStatus(&status);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, q]() {
+ HRESULT hr;
+ hr = mDevice->add_ConnectionStatusChanged(
+ Callback<StatusHandler>([this, q](IBluetoothLEDevice *dev, IInspectable *) {
+ BluetoothConnectionStatus status;
+ HRESULT hr;
+ hr = dev->get_ConnectionStatus(&status);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (state == QLowEnergyController::ConnectingState
+ && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ } else if (state != QLowEnergyController::UnconnectedState
+ && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
+ invalidateServices();
+ unregisterFromValueChanges();
+ setError(QLowEnergyController::RemoteHostClosedError);
+ setState(QLowEnergyController::UnconnectedState);
+ emit q->disconnected();
+ }
+ return S_OK;
+ }).Get(), &mStatusChangedToken);
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+
+ if (status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ return;
+ }
+
+ ComPtr<IVectorView <GattDeviceService *>> deviceServices;
+ hr = mDevice->get_GattServices(&deviceServices);
+ Q_ASSERT_SUCCEEDED(hr);
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // Windows doesn't provide any explicit connect/reconnect. We need to 'start using' the device
+ // and windows will initiate connection as a cause of that.
+ if (serviceCount == 0) {
+ // If we don't have any services discovered yet (for devices not paired), the simplest
+ // way to initiate connect is to start discovering services. It's not exactly how Qt API
+ // expects it to be but IMHO doesn't do any harm either. Services will already be discovered
+ // when coonnection state changes to 'connected'.
+ ComPtr<IBluetoothLEDevice3> device3;
+ hr = mDevice.As(&device3);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *>> asyncResult;
+ hr = device3->GetGattServicesAsync(&asyncResult);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = asyncResult->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GenericAttributeProfile::GattDeviceServicesResult *>>(
+ [this, q](IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *> *, AsyncStatus status) {
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain services";
+ return S_OK;
+ }
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ return S_OK;
+ }).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ } else {
+ // Windows Phone automatically connects to the device as soon as a service value is read/written.
+ // Thus we read one value in order to establish the connection.
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<IGattDeviceService> service;
+ hr = deviceServices->GetAt(i, &service);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IGattDeviceService2> service2;
+ hr = service.As(&service2);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<GattCharacteristic *>> characteristics;
+ hr = service2->GetAllCharacteristics(&characteristics);
+ if (hr == E_ACCESSDENIED) {
+ // Everything will work as expected up until this point if the manifest capabilties
+ // for bluetooth LE are not set.
+ qCWarning(QT_BT_WINRT) << "Could not obtain characteristic list. Please check your "
+ "manifest capabilities";
+ setState(QLowEnergyController::UnconnectedState);
+ setError(QLowEnergyController::ConnectionError);
+ return;
+ } else if (FAILED(hr)) {
+ qCWarning(QT_BT_WINRT) << "Connecting to device failed: "
+ << qt_error_string(hr);
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ return;
+ }
+ uint characteristicsCount;
+ hr = characteristics->get_Size(&characteristicsCount);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (uint j = 0; j < characteristicsCount; ++j) {
+ ComPtr<IGattCharacteristic> characteristic;
+ hr = characteristics->GetAt(j, &characteristic);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<GattReadResult *>> op;
+ GattCharacteristicProperties props;
+ hr = characteristic->get_CharacteristicProperties(&props);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (!(props & GattCharacteristicProperties_Read))
+ continue;
+ hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IGattReadResult> result;
+ hr = QWinRTFunctions::await(op, result.GetAddressOf());
+ if (hr == E_INVALIDARG) {
+ // E_INVALIDARG happens when user tries to connect to a device that was paired
+ // before but is not available.
+ qCDebug(QT_BT_WINRT) << "Could not obtain characteristic read result that triggers"
+ "device connection. Is the device reachable?";
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ return;
+ }
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ hr = result->get_Value(&buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (!buffer) {
+ qCDebug(QT_BT_WINRT) << "Problem reading value";
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ }
+ return;
+ }
+ }
+ }
+}
+
+void QLowEnergyControllerPrivateWinRTNew::disconnectFromDevice()
+{
+ qCDebug(QT_BT_WINRT) << __FUNCTION__;
+ Q_Q(QLowEnergyController);
+ setState(QLowEnergyController::ClosingState);
+ unregisterFromValueChanges();
+ if (mDevice) {
+ if (mStatusChangedToken.value) {
+ mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
+ mStatusChangedToken.value = 0;
+ }
+ mDevice = nullptr;
+ }
+ setState(QLowEnergyController::UnconnectedState);
+ emit q->disconnected();
+}
+
+ComPtr<IGattDeviceService> QLowEnergyControllerPrivateWinRTNew::getNativeService(
+ const QBluetoothUuid &serviceUuid)
+{
+ ComPtr<IGattDeviceService> deviceService;
+ HRESULT hr;
+ hr = mDevice->GetGattService(serviceUuid, &deviceService);
+ if (FAILED(hr))
+ qCDebug(QT_BT_WINRT) << "Could not obtain native service for Uuid" << serviceUuid;
+ return deviceService;
+}
+
+ComPtr<IGattCharacteristic> QLowEnergyControllerPrivateWinRTNew::getNativeCharacteristic(
+ const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid)
+{
+ ComPtr<IGattDeviceService> service = getNativeService(serviceUuid);
+ if (!service)
+ return nullptr;
+
+ ComPtr<IVectorView<GattCharacteristic *>> characteristics;
+ HRESULT hr = service->GetCharacteristics(charUuid, &characteristics);
+ RETURN_IF_FAILED("Could not obtain native characteristics for service", return nullptr);
+ ComPtr<IGattCharacteristic> characteristic;
+ hr = characteristics->GetAt(0, &characteristic);
+ RETURN_IF_FAILED("Could not obtain first characteristic for service", return nullptr);
+ return characteristic;
+}
+
+void QLowEnergyControllerPrivateWinRTNew::registerForValueChanges(const QBluetoothUuid &serviceUuid,
+ const QBluetoothUuid &charUuid)
+{
+ qCDebug(QT_BT_WINRT) << "Registering characteristic" << charUuid << "in service"
+ << serviceUuid << "for value changes";
+ for (const ValueChangedEntry &entry : qAsConst(mValueChangedTokens)) {
+ GUID guuid;
+ HRESULT hr;
+ hr = entry.characteristic->get_Uuid(&guuid);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (QBluetoothUuid(guuid) == charUuid)
+ return;
+ }
+ ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(serviceUuid, charUuid);
+
+ EventRegistrationToken token;
+ HRESULT hr;
+ hr = characteristic->add_ValueChanged(
+ Callback<ValueChangedHandler>(
+ [this](IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args) {
+ HRESULT hr;
+ quint16 handle;
+ hr = characteristic->get_AttributeHandle(&handle);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IBuffer> buffer;
+ hr = args->get_CharacteristicValue(&buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ characteristicChanged(handle, byteArrayFromBuffer(buffer));
+ return S_OK;
+ }).Get(), &token);
+ Q_ASSERT_SUCCEEDED(hr);
+ mValueChangedTokens.append(ValueChangedEntry(characteristic, token));
+ qCDebug(QT_BT_WINRT) << "Characteristic" << charUuid << "in service"
+ << serviceUuid << "registered for value changes";
+}
+
+void QLowEnergyControllerPrivateWinRTNew::unregisterFromValueChanges()
+{
+ qCDebug(QT_BT_WINRT) << "Unregistering " << mValueChangedTokens.count() << " value change tokens";
+ HRESULT hr;
+ for (const ValueChangedEntry &entry : qAsConst(mValueChangedTokens)) {
+ hr = entry.characteristic->remove_ValueChanged(entry.token);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ mValueChangedTokens.clear();
+}
+
+void QLowEnergyControllerPrivateWinRTNew::obtainIncludedServices(
+ QSharedPointer<QLowEnergyServicePrivate> servicePointer,
+ ComPtr<IGattDeviceService> service)
+{
+ Q_Q(QLowEnergyController);
+ ComPtr<IGattDeviceService2> service2;
+ HRESULT hr = service.As(&service2);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<GattDeviceService *>> includedServices;
+ hr = service2->GetAllIncludedServices(&includedServices);
+ // Some devices return ERROR_ACCESS_DISABLED_BY_POLICY
+ if (FAILED(hr))
+ return;
+
+ uint count;
+ hr = includedServices->get_Size(&count);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (uint i = 0; i < count; ++i) {
+ ComPtr<IGattDeviceService> includedService;
+ hr = includedServices->GetAt(i, &includedService);
+ Q_ASSERT_SUCCEEDED(hr);
+ GUID guuid;
+ hr = includedService->get_Uuid(&guuid);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QBluetoothUuid includedUuid(guuid);
+ QSharedPointer<QLowEnergyServicePrivate> includedPointer;
+ if (serviceList.contains(includedUuid)) {
+ includedPointer = serviceList.value(includedUuid);
+ } else {
+ QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
+ priv->uuid = includedUuid;
+ priv->setController(this);
+
+ includedPointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
+ serviceList.insert(includedUuid, includedPointer);
+ }
+ includedPointer->type |= QLowEnergyService::IncludedService;
+ servicePointer->includedServices.append(includedUuid);
+
+ obtainIncludedServices(includedPointer, includedService);
+
+ emit q->serviceDiscovered(includedUuid);
+ }
+}
+
+void QLowEnergyControllerPrivateWinRTNew::discoverServices()
+{
+ Q_Q(QLowEnergyController);
+
+ qCDebug(QT_BT_WINRT) << "Service discovery initiated";
+
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *>> asyncResult;
+ hr = device3->GetGattServicesAsync(&asyncResult);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QEventDispatcherWinRT::runOnXamlThread( [asyncResult, q, this] () {
+ HRESULT hr = asyncResult->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GenericAttributeProfile::GattDeviceServicesResult *>>(
+ [this, q](IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *> *, AsyncStatus status) {
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain services";
+ return S_OK;
+ }
+ ComPtr<IVectorView<GattDeviceService *>> deviceServices;
+ HRESULT hr = mDevice->get_GattServices(&deviceServices);
+ Q_ASSERT_SUCCEEDED(hr);
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<IGattDeviceService> deviceService;
+ hr = deviceServices->GetAt(i, &deviceService);
+ Q_ASSERT_SUCCEEDED(hr);
+ GUID guuid;
+ hr = deviceService->get_Uuid(&guuid);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QBluetoothUuid service(guuid);
+
+ QSharedPointer<QLowEnergyServicePrivate> pointer;
+ if (serviceList.contains(service)) {
+ pointer = serviceList.value(service);
+ } else {
+ QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
+ priv->uuid = service;
+ priv->setController(this);
+
+ pointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
+ serviceList.insert(service, pointer);
+ }
+ pointer->type |= QLowEnergyService::PrimaryService;
+
+ obtainIncludedServices(pointer, deviceService);
+
+ emit q->serviceDiscovered(service);
+ }
+
+ setState(QLowEnergyController::DiscoveredState);
+ emit q->discoveryFinished();
+
+ return S_OK;
+ }).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+void QLowEnergyControllerPrivateWinRTNew::discoverServiceDetails(const QBluetoothUuid &service)
+{
+ qCDebug(QT_BT_WINRT) << __FUNCTION__ << service;
+ if (!serviceList.contains(service)) {
+ qCWarning(QT_BT_WINRT) << "Discovery done of unknown service:"
+ << service.toString();
+ return;
+ }
+
+ ComPtr<IGattDeviceService> deviceService = getNativeService(service);
+ if (!deviceService) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain native service for uuid " << service;
+ return;
+ }
+
+ //update service data
+ QSharedPointer<QLowEnergyServicePrivate> pointer = serviceList.value(service);
+
+ pointer->setState(QLowEnergyService::DiscoveringServices);
+ ComPtr<IGattDeviceService2> deviceService2;
+ HRESULT hr = deviceService.As(&deviceService2);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<GattDeviceService *>> deviceServices;
+ hr = deviceService2->GetAllIncludedServices(&deviceServices);
+ if (FAILED(hr)) { // ERROR_ACCESS_DISABLED_BY_POLICY
+ qCDebug(QT_BT_WINRT) << "Could not obtain included services list for" << service;
+ pointer->setError(QLowEnergyService::UnknownError);
+ pointer->setState(QLowEnergyService::InvalidService);
+ return;
+ }
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<IGattDeviceService> includedService;
+ hr = deviceServices->GetAt(i, &includedService);
+ Q_ASSERT_SUCCEEDED(hr);
+ GUID guuid;
+ hr = includedService->get_Uuid(&guuid);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ const QBluetoothUuid service(guuid);
+ if (service.isNull()) {
+ qCDebug(QT_BT_WINRT) << "Could not find service";
+ return;
+ }
+
+ pointer->includedServices.append(service);
+
+ // update the type of the included service
+ QSharedPointer<QLowEnergyServicePrivate> otherService = serviceList.value(service);
+ if (!otherService.isNull())
+ otherService->type |= QLowEnergyService::IncludedService;
+ }
+
+ QWinRTLowEnergyServiceHandlerNew *worker
+ = new QWinRTLowEnergyServiceHandlerNew(service, deviceService2);
+ QThread *thread = new QThread;
+ worker->moveToThread(thread);
+ connect(thread, &QThread::started, worker, &QWinRTLowEnergyServiceHandlerNew::obtainCharList);
+ connect(thread, &QThread::finished, thread, &QObject::deleteLater);
+ connect(thread, &QThread::finished, worker, &QObject::deleteLater);
+ connect(worker, &QWinRTLowEnergyServiceHandlerNew::charListObtained,
+ [this, thread](const QBluetoothUuid &service, QHash<QLowEnergyHandle,
+ QLowEnergyServicePrivate::CharData> charList, QVector<QBluetoothUuid> indicateChars,
+ QLowEnergyHandle startHandle, QLowEnergyHandle endHandle) {
+ if (!serviceList.contains(service)) {
+ qCWarning(QT_BT_WINRT) << "Discovery done of unknown service:"
+ << service.toString();
+ return;
+ }
+
+ QSharedPointer<QLowEnergyServicePrivate> pointer = serviceList.value(service);
+ pointer->startHandle = startHandle;
+ pointer->endHandle = endHandle;
+ pointer->characteristicList = charList;
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([indicateChars, service, this]() {
+ for (const QBluetoothUuid &indicateChar : qAsConst(indicateChars))
+ registerForValueChanges(service, indicateChar);
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+
+ pointer->setState(QLowEnergyService::ServiceDiscovered);
+ thread->exit(0);
+ });
+ thread->start();
+}
+
+void QLowEnergyControllerPrivateWinRTNew::startAdvertising(
+ const QLowEnergyAdvertisingParameters &,
+ const QLowEnergyAdvertisingData &,
+ const QLowEnergyAdvertisingData &)
+{
+ setError(QLowEnergyController::AdvertisingError);
+ Q_UNIMPLEMENTED();
+}
+
+void QLowEnergyControllerPrivateWinRTNew::stopAdvertising()
+{
+ Q_UNIMPLEMENTED();
+}
+
+void QLowEnergyControllerPrivateWinRTNew::requestConnectionUpdate(const QLowEnergyConnectionParameters &)
+{
+ Q_UNIMPLEMENTED();
+}
+
+void QLowEnergyControllerPrivateWinRTNew::readCharacteristic(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle)
+{
+ qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle;
+ Q_ASSERT(!service.isNull());
+ if (role == QLowEnergyController::PeripheralRole) {
+ service->setError(QLowEnergyService::CharacteristicReadError);
+ Q_UNIMPLEMENTED();
+ return;
+ }
+
+ if (!service->characteristicList.contains(charHandle)) {
+ qCDebug(QT_BT_WINRT) << charHandle << "could not be found in service" << service->uuid;
+ service->setError(QLowEnergyService::CharacteristicReadError);
+ return;
+ }
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, service, this]() {
+ const QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
+ if (!(charData.properties & QLowEnergyCharacteristic::Read))
+ qCDebug(QT_BT_WINRT) << "Read flag is not set for characteristic" << charData.uuid;
+
+ ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
+ if (!characteristic) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
+ << "from service" << service->uuid;
+ service->setError(QLowEnergyService::CharacteristicReadError);
+ return S_OK;
+ }
+ ComPtr<IAsyncOperation<GattReadResult*>> readOp;
+ HRESULT hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ auto readCompletedLambda = [charData, charHandle, service]
+ (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "read operation failed.";
+ service->setError(QLowEnergyService::CharacteristicReadError);
+ return S_OK;
+ }
+ ComPtr<IGattReadResult> characteristicValue;
+ HRESULT hr;
+ hr = op->GetResults(&characteristicValue);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain result for characteristic" << charHandle;
+ service->setError(QLowEnergyService::CharacteristicReadError);
+ return S_OK;
+ }
+
+ const QByteArray value = byteArrayFromGattResult(characteristicValue);
+ QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
+ charData.value = value;
+ service->characteristicList.insert(charHandle, charData);
+ emit service->characteristicRead(QLowEnergyCharacteristic(service, charHandle), value);
+ return S_OK;
+ };
+ hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(
+ readCompletedLambda).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+void QLowEnergyControllerPrivateWinRTNew::readDescriptor(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descHandle)
+{
+ qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << descHandle;
+ Q_ASSERT(!service.isNull());
+ if (role == QLowEnergyController::PeripheralRole) {
+ service->setError(QLowEnergyService::DescriptorReadError);
+ Q_UNIMPLEMENTED();
+ return;
+ }
+
+ if (!service->characteristicList.contains(charHandle)) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "in characteristic" << charHandle
+ << "cannot be found in service" << service->uuid;
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return;
+ }
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, descHandle, service, this]() {
+ QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
+ ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
+ if (!characteristic) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
+ << "from service" << service->uuid;
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return S_OK;
+ }
+
+ // Get native descriptor
+ if (!charData.descriptorList.contains(descHandle))
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "cannot be found in characteristic" << charHandle;
+ QLowEnergyServicePrivate::DescData descData = charData.descriptorList.value(descHandle);
+ if (descData.uuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
+ ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
+ HRESULT hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ auto readCompletedLambda = [&charData, charHandle, &descData, descHandle, service]
+ (IAsyncOperation<ClientCharConfigDescriptorResult *> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "read operation failed";
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return S_OK;
+ }
+ ComPtr<IClientCharConfigDescriptorResult> iValue;
+ HRESULT hr;
+ hr = op->GetResults(&iValue);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return S_OK;
+ }
+ GattClientCharacteristicConfigurationDescriptorValue value;
+ hr = iValue->get_ClientCharacteristicConfigurationDescriptor(&value);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain value for descriptor" << descHandle;
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return S_OK;
+ }
+ quint16 result = 0;
+ bool correct = false;
+ if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
+ result |= QLowEnergyCharacteristic::Indicate;
+ correct = true;
+ }
+ if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
+ result |= QLowEnergyCharacteristic::Notify;
+ correct = true;
+ }
+ if (value == GattClientCharacteristicConfigurationDescriptorValue_None)
+ correct = true;
+ if (!correct) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle
+ << "read operation failed. Obtained unexpected value.";
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return S_OK;
+ }
+ descData.value = QByteArray(2, Qt::Uninitialized);
+ qToLittleEndian(result, descData.value.data());
+ charData.descriptorList.insert(descHandle, descData);
+ emit service->descriptorRead(QLowEnergyDescriptor(service, charHandle, descHandle),
+ descData.value);
+ return S_OK;
+ };
+ hr = readOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<ClientCharConfigDescriptorResult *>>(
+ readCompletedLambda).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ } else {
+ ComPtr<IVectorView<GattDescriptor *>> descriptors;
+ HRESULT hr = characteristic->GetDescriptors(descData.uuid, &descriptors);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IGattDescriptor> descriptor;
+ hr = descriptors->GetAt(0, &descriptor);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<GattReadResult*>> readOp;
+ hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ auto readCompletedLambda = [&charData, charHandle, &descData, descHandle, service]
+ (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "read operation failed";
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return S_OK;
+ }
+ ComPtr<IGattReadResult> descriptorValue;
+ HRESULT hr;
+ hr = op->GetResults(&descriptorValue);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return S_OK;
+ }
+ if (descData.uuid == QBluetoothUuid::CharacteristicUserDescription)
+ descData.value = byteArrayFromGattResult(descriptorValue, true);
+ else
+ descData.value = byteArrayFromGattResult(descriptorValue);
+ charData.descriptorList.insert(descHandle, descData);
+ emit service->descriptorRead(QLowEnergyDescriptor(service, charHandle, descHandle),
+ descData.value);
+ return S_OK;
+ };
+ hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(
+ readCompletedLambda).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ }
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+void QLowEnergyControllerPrivateWinRTNew::writeCharacteristic(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QByteArray &newValue,
+ QLowEnergyService::WriteMode mode)
+{
+ qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << newValue << mode;
+ Q_ASSERT(!service.isNull());
+ if (role == QLowEnergyController::PeripheralRole) {
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ Q_UNIMPLEMENTED();
+ return;
+ }
+ if (!service->characteristicList.contains(charHandle)) {
+ qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "cannot be found in service"
+ << service->uuid;
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return;
+ }
+
+ QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
+ const bool writeWithResponse = mode == QLowEnergyService::WriteWithResponse;
+ if (!(charData.properties & (writeWithResponse ? QLowEnergyCharacteristic::Write
+ : QLowEnergyCharacteristic::WriteNoResponse)))
+ qCDebug(QT_BT_WINRT) << "Write flag is not set for characteristic" << charHandle;
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([charData, charHandle, this, service, newValue,
+ writeWithResponse]() {
+ ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid,
+ charData.uuid);
+ if (!characteristic) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
+ << "from service" << service->uuid;
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return S_OK;
+ }
+ ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
+ HRESULT hr = GetActivationFactory(
+ HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ &bufferFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ const quint32 length = quint32(newValue.length());
+ hr = bufferFactory->Create(length, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = buffer->put_Length(length);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
+ hr = buffer.As(&byteAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ byte *bytes;
+ hr = byteAccess->Buffer(&bytes);
+ Q_ASSERT_SUCCEEDED(hr);
+ memcpy(bytes, newValue, length);
+ ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
+ GattWriteOption option = writeWithResponse ? GattWriteOption_WriteWithResponse
+ : GattWriteOption_WriteWithoutResponse;
+ hr = characteristic->WriteValueWithOptionAsync(buffer.Get(), option, &writeOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ auto writeCompletedLambda =[charData, charHandle, newValue, service, writeWithResponse, this]
+ (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "write operation failed";
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return S_OK;
+ }
+ GattCommunicationStatus result;
+ HRESULT hr;
+ hr = op->GetResults(&result);
+ if (hr == E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH) {
+ qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle
+ << "write operation was tried with invalid value length";
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return S_OK;
+ }
+ Q_ASSERT_SUCCEEDED(hr);
+ if (result != GattCommunicationStatus_Success) {
+ qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "write operation failed";
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return S_OK;
+ }
+ // only update cache when property is readable. Otherwise it remains
+ // empty.
+ if (charData.properties & QLowEnergyCharacteristic::Read)
+ updateValueOfCharacteristic(charHandle, newValue, false);
+ if (writeWithResponse)
+ emit service->characteristicWritten(QLowEnergyCharacteristic(service, charHandle),
+ newValue);
+ return S_OK;
+ };
+ hr = writeOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(
+ writeCompletedLambda).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descHandle,
+ const QByteArray &newValue)
+{
+ qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << descHandle << newValue;
+ Q_ASSERT(!service.isNull());
+ if (role == QLowEnergyController::PeripheralRole) {
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ Q_UNIMPLEMENTED();
+ return;
+ }
+
+ if (!service->characteristicList.contains(charHandle)) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "in characteristic" << charHandle
+ << "could not be found in service" << service->uuid;
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return;
+ }
+
+ HRESULT hr;
+ hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, descHandle, this, service, newValue]() {
+ const QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
+ ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
+ if (!characteristic) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
+ << "from service" << service->uuid;
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+
+ // Get native descriptor
+ if (!charData.descriptorList.contains(descHandle))
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "could not be found in Characteristic"
+ << charHandle;
+
+ QLowEnergyServicePrivate::DescData descData = charData.descriptorList.value(descHandle);
+ if (descData.uuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
+ GattClientCharacteristicConfigurationDescriptorValue value;
+ quint16 intValue = qFromLittleEndian<quint16>(newValue);
+ if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate
+ && intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
+ qCWarning(QT_BT_WINRT) << "Setting both Indicate and Notify is not supported on WinRT";
+ value = GattClientCharacteristicConfigurationDescriptorValue(
+ (GattClientCharacteristicConfigurationDescriptorValue_Indicate
+ | GattClientCharacteristicConfigurationDescriptorValue_Notify));
+ } else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
+ value = GattClientCharacteristicConfigurationDescriptorValue_Indicate;
+ } else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
+ value = GattClientCharacteristicConfigurationDescriptorValue_Notify;
+ } else if (intValue == 0) {
+ value = GattClientCharacteristicConfigurationDescriptorValue_None;
+ } else {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle
+ << "write operation failed: Invalid value";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+ ComPtr<IAsyncOperation<enum GattCommunicationStatus>> writeOp;
+ HRESULT hr = characteristic->WriteClientCharacteristicConfigurationDescriptorAsync(value, &writeOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ auto writeCompletedLambda = [charHandle, descHandle, newValue, service, this]
+ (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+ GattCommunicationStatus result;
+ HRESULT hr;
+ hr = op->GetResults(&result);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+ if (result != GattCommunicationStatus_Success) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+ updateValueOfDescriptor(charHandle, descHandle, newValue, false);
+ emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
+ newValue);
+ return S_OK;
+ };
+ hr = writeOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus >>(
+ writeCompletedLambda).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ } else {
+ ComPtr<IVectorView<GattDescriptor *>> descriptors;
+ HRESULT hr = characteristic->GetDescriptors(descData.uuid, &descriptors);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IGattDescriptor> descriptor;
+ hr = descriptors->GetAt(0, &descriptor);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
+ hr = GetActivationFactory(
+ HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ &bufferFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ const quint32 length = quint32(newValue.length());
+ hr = bufferFactory->Create(length, &buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = buffer->put_Length(length);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
+ hr = buffer.As(&byteAccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ byte *bytes;
+ hr = byteAccess->Buffer(&bytes);
+ Q_ASSERT_SUCCEEDED(hr);
+ memcpy(bytes, newValue, length);
+ ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
+ hr = descriptor->WriteValueAsync(buffer.Get(), &writeOp);
+ Q_ASSERT_SUCCEEDED(hr);
+ auto writeCompletedLambda = [charHandle, descHandle, newValue, service, this]
+ (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+ GattCommunicationStatus result;
+ HRESULT hr;
+ hr = op->GetResults(&result);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+ if (result != GattCommunicationStatus_Success) {
+ qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+ updateValueOfDescriptor(charHandle, descHandle, newValue, false);
+ emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
+ newValue);
+ return S_OK;
+ };
+ hr = writeOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(
+ writeCompletedLambda).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ }
+ return S_OK;
+ });
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+
+void QLowEnergyControllerPrivateWinRTNew::addToGenericAttributeList(const QLowEnergyServiceData &,
+ QLowEnergyHandle)
+{
+ Q_UNIMPLEMENTED();
+}
+
+void QLowEnergyControllerPrivateWinRTNew::characteristicChanged(
+ quint16 charHandle, const QByteArray &data)
+{
+ QSharedPointer<QLowEnergyServicePrivate> service =
+ serviceForHandle(charHandle);
+ if (service.isNull())
+ return;
+
+ qCDebug(QT_BT_WINRT) << "Characteristic change notification" << service->uuid
+ << charHandle << data.toHex();
+
+ QLowEnergyCharacteristic characteristic = characteristicForHandle(charHandle);
+ if (!characteristic.isValid()) {
+ qCWarning(QT_BT_WINRT) << "characteristicChanged: Cannot find characteristic";
+ return;
+ }
+
+ // only update cache when property is readable. Otherwise it remains
+ // empty.
+ if (characteristic.properties() & QLowEnergyCharacteristic::Read)
+ updateValueOfCharacteristic(characteristic.attributeHandle(),
+ data, false);
+ emit service->characteristicChanged(characteristic, data);
+}
+
+QT_END_NAMESPACE
+
+#include "qlowenergycontroller_winrt_new.moc"
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new_p.h b/src/bluetooth/qlowenergycontroller_winrt_new_p.h
new file mode 100644
index 00000000..b3990acd
--- /dev/null
+++ b/src/bluetooth/qlowenergycontroller_winrt_new_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLOWENERGYCONTROLLERPRIVATEWINRT_NEW_P_H
+#define QLOWENERGYCONTROLLERPRIVATEWINRT_NEW_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qglobal.h>
+#include <QtCore/QQueue>
+#include <QtCore/QVector>
+#include <QtBluetooth/qbluetooth.h>
+#include <QtBluetooth/qlowenergycharacteristic.h>
+#include <QtBluetooth/qlowenergyservicedata.h>
+#include "qlowenergycontroller.h"
+#include "qlowenergycontrollerbase_p.h"
+
+#include <wrl.h>
+#include <windows.devices.bluetooth.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+class QLowEnergyServiceData;
+class QTimer;
+class QWinRTLowEnergyServiceHandler;
+
+extern void registerQLowEnergyControllerMetaType();
+
+QLowEnergyControllerPrivate *createWinRTLowEnergyController();
+
+class QLowEnergyControllerPrivateWinRTNew final : public QLowEnergyControllerPrivate
+{
+ Q_OBJECT
+public:
+ QLowEnergyControllerPrivateWinRTNew();
+ ~QLowEnergyControllerPrivateWinRTNew() override;
+
+ void init() override;
+
+ void connectToDevice() override;
+ void disconnectFromDevice() override;
+
+ void discoverServices() override;
+ void discoverServiceDetails(const QBluetoothUuid &service) override;
+
+ void startAdvertising(const QLowEnergyAdvertisingParameters &params,
+ const QLowEnergyAdvertisingData &advertisingData,
+ const QLowEnergyAdvertisingData &scanResponseData) override;
+ void stopAdvertising() override;
+
+ void requestConnectionUpdate(const QLowEnergyConnectionParameters &params) override;
+
+ // read data
+ void readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle) override;
+ void readDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descriptorHandle) override;
+
+ // write data
+ void writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QByteArray &newValue, QLowEnergyService::WriteMode mode) override;
+ void writeDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descriptorHandle,
+ const QByteArray &newValue) override;
+
+ void addToGenericAttributeList(const QLowEnergyServiceData &service,
+ QLowEnergyHandle startHandle) override;
+
+private slots:
+ void characteristicChanged(quint16 charHandle, const QByteArray &data);
+
+private:
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> mDevice;
+ EventRegistrationToken mStatusChangedToken;
+ struct ValueChangedEntry {
+ ValueChangedEntry() {}
+ ValueChangedEntry(Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> c,
+ EventRegistrationToken t)
+ : characteristic(c)
+ , token(t)
+ {
+ }
+
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> characteristic;
+ EventRegistrationToken token;
+ };
+ QVector<ValueChangedEntry> mValueChangedTokens;
+
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> getNativeService(const QBluetoothUuid &serviceUuid);
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> getNativeCharacteristic(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
+
+ void registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
+ void unregisterFromValueChanges();
+
+ void obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer,
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> nativeService);
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QLOWENERGYCONTROLLERPRIVATEWINRT_NEW_P_H
diff --git a/src/bluetooth/qlowenergycontroller_winrt_p.h b/src/bluetooth/qlowenergycontroller_winrt_p.h
index 783a71fa..da21353f 100644
--- a/src/bluetooth/qlowenergycontroller_winrt_p.h
+++ b/src/bluetooth/qlowenergycontroller_winrt_p.h
@@ -138,6 +138,7 @@ private:
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> getNativeCharacteristic(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
void registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
+ void unregisterFromValueChanges();
void obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer,
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> nativeService);
diff --git a/src/bluetooth/qlowenergydescriptor.h b/src/bluetooth/qlowenergydescriptor.h
index 9dd0cc20..62ca5fd3 100644
--- a/src/bluetooth/qlowenergydescriptor.h
+++ b/src/bluetooth/qlowenergydescriptor.h
@@ -85,6 +85,7 @@ protected:
friend class QLowEnergyControllerPrivateCommon;
friend class QLowEnergyControllerPrivateOSX;
friend class QLowEnergyControllerPrivateWinRT;
+ friend class QLowEnergyControllerPrivateWinRTNew;
QLowEnergyDescriptorPrivate *data = nullptr;
QLowEnergyDescriptor(QSharedPointer<QLowEnergyServicePrivate> p,
diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
index 6b2f32f3..6213355e 100644
--- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
+++ b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
@@ -165,14 +165,6 @@ QDeclarativeBluetoothDiscoveryModel::QDeclarativeBluetoothDiscoveryModel(QObject
this,
&QDeclarativeBluetoothDiscoveryModel::errorDiscovery);
d->m_serviceAgent->setObjectName(QStringLiteral("ServiceDiscoveryAgent"));
-
- QHash<int, QByteArray> roleNames;
- roleNames = QAbstractItemModel::roleNames();
- roleNames.insert(Name, "name");
- roleNames.insert(ServiceRole, "service");
- roleNames.insert(RemoteAddress, "remoteAddress");
- roleNames.insert(DeviceName, "deviceName");
- setRoleNames(roleNames);
}
QDeclarativeBluetoothDiscoveryModel::~QDeclarativeBluetoothDiscoveryModel()
@@ -314,6 +306,14 @@ QVariant QDeclarativeBluetoothDiscoveryModel::data(const QModelIndex &index, int
return QVariant();
}
+QHash<int,QByteArray> QDeclarativeBluetoothDiscoveryModel::roleNames() const
+{
+ return {{Name, "name"},
+ {ServiceRole, "service"},
+ {RemoteAddress, "remoteAddress"},
+ {DeviceName, "deviceName"}};
+}
+
/*!
\qmlsignal BluetoothDiscoveryModel::serviceDiscovered(BluetoothService service)
diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h
index 0aa134f5..6cbde088 100644
--- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h
+++ b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h
@@ -106,13 +106,15 @@ public:
Error error() const;
- void componentComplete();
+ void componentComplete() override;
- void classBegin() { }
+ void classBegin() override { }
// From QAbstractListModel
- int rowCount(const QModelIndex &parent) const;
- QVariant data(const QModelIndex &index, int role) const;
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+ QHash<int,QByteArray> roleNames() const override;
DiscoveryMode discoveryMode() const;
void setDiscoveryMode(DiscoveryMode discovery);
diff --git a/src/nfc/qnearfieldmanager.h b/src/nfc/qnearfieldmanager.h
index 500b9631..22506e7e 100644
--- a/src/nfc/qnearfieldmanager.h
+++ b/src/nfc/qnearfieldmanager.h
@@ -99,7 +99,7 @@ public:
bool unregisterNdefMessageHandler(int handlerId);
Q_SIGNALS:
- void adapterStateChanged(AdapterState state);
+ void adapterStateChanged(QNearFieldManager::AdapterState state);
void targetDetected(QNearFieldTarget *target);
void targetLost(QNearFieldTarget *target);
diff --git a/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp b/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp
index fd2ed46f..6636f0cd 100644
--- a/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp
+++ b/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp
@@ -452,6 +452,11 @@ void tst_QBluetoothDeviceInfo::tst_serviceUuids()
servicesList.append(QBluetoothUuid::Rfcomm);
QVERIFY(servicesList.count() > 0);
+ deviceInfo.setServiceUuids(servicesList.toVector());
+ QVERIFY(deviceInfo.serviceUuids().count() > 0);
+ deviceInfo.setServiceUuids(QVector<QBluetoothUuid>());
+ QCOMPARE(deviceInfo.serviceUuids().count(), 0);
+
deviceInfo.setServiceUuids(servicesList, QBluetoothDeviceInfo::DataComplete);
QVERIFY(deviceInfo.serviceUuids().count() > 0);
QVERIFY(deviceInfo != copyInfo);