summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2022-11-10 22:42:26 +0200
committerTarja Sundqvist <tarja.sundqvist@qt.io>2022-11-10 22:42:26 +0200
commite957d4810b05d8453e163d7bcdcab42d3c60a7bb (patch)
tree76ed3d969c478042f8ca747bf425b0e5d2e893dc
parent47c424c7990061714bd3108e3fbaa4339ba411b9 (diff)
parenta6f5b79169991ffde38643d7b1a04d6a9de137bf (diff)
Merge remote-tracking branch 'origin/tqtc/lts-5.15.8' into tqtc/lts-5.15-opensourcev5.15.8-lts-lgpl
-rw-r--r--.qmake.conf2
-rw-r--r--examples/bluetooth/btscanner/btscanner.pro1
-rw-r--r--examples/bluetooth/heartrate-game/heartrate-game.pro1
-rw-r--r--examples/bluetooth/heartrate-server/heartrate-server.pro1
-rw-r--r--examples/bluetooth/lowenergyscanner/lowenergyscanner.pro1
-rw-r--r--examples/bluetooth/shared/Info.qmake.macos.plist24
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java434
-rw-r--r--src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java8
-rw-r--r--src/bluetooth/osx/osxbtconnectionmonitor.mm24
-rw-r--r--src/bluetooth/osx/osxbtconnectionmonitor_p.h2
-rw-r--r--src/bluetooth/osx/osxbtutility.mm19
-rw-r--r--src/bluetooth/osx/osxbtutility_p.h6
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm21
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_osx.mm6
-rw-r--r--src/bluetooth/qbluetoothsocket_winrt.cpp46
-rw-r--r--src/bluetooth/qlowenergycontroller_darwin.mm65
-rw-r--r--src/bluetooth/qlowenergycontroller_darwin_p.h5
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt.cpp7
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new.cpp10
19 files changed, 488 insertions, 195 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 6d03a03f..48f4c9ef 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -2,4 +2,4 @@ load(qt_build_config)
DEFINES += QT_NO_FOREACH QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST
-MODULE_VERSION = 5.15.7
+MODULE_VERSION = 5.15.8
diff --git a/examples/bluetooth/btscanner/btscanner.pro b/examples/bluetooth/btscanner/btscanner.pro
index d5fd66ae..ee781ff7 100644
--- a/examples/bluetooth/btscanner/btscanner.pro
+++ b/examples/bluetooth/btscanner/btscanner.pro
@@ -10,6 +10,7 @@ SOURCES = \
service.cpp
ios: QMAKE_INFO_PLIST = Info.plist
+macos: QMAKE_INFO_PLIST = ../shared/Info.qmake.macos.plist
HEADERS = \
device.h \
diff --git a/examples/bluetooth/heartrate-game/heartrate-game.pro b/examples/bluetooth/heartrate-game/heartrate-game.pro
index a0827d89..02d238ad 100644
--- a/examples/bluetooth/heartrate-game/heartrate-game.pro
+++ b/examples/bluetooth/heartrate-game/heartrate-game.pro
@@ -20,6 +20,7 @@ SOURCES += main.cpp \
bluetoothbaseclass.cpp
ios: QMAKE_INFO_PLIST = Info.plist
+macos: QMAKE_INFO_PLIST = ../shared/Info.qmake.macos.plist
RESOURCES += qml.qrc \
images.qrc
diff --git a/examples/bluetooth/heartrate-server/heartrate-server.pro b/examples/bluetooth/heartrate-server/heartrate-server.pro
index 992f2d66..8ec3f703 100644
--- a/examples/bluetooth/heartrate-server/heartrate-server.pro
+++ b/examples/bluetooth/heartrate-server/heartrate-server.pro
@@ -8,6 +8,7 @@ CONFIG += c++11
SOURCES += main.cpp
ios: QMAKE_INFO_PLIST = Info.plist
+macos: QMAKE_INFO_PLIST = ../shared/Info.qmake.macos.plist
target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/heartrate-server
INSTALLS += target
diff --git a/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro b/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro
index 934f6cfa..31b243ac 100644
--- a/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro
+++ b/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro
@@ -11,6 +11,7 @@ SOURCES += main.cpp \
characteristicinfo.cpp
ios: QMAKE_INFO_PLIST = Info.plist
+macos: QMAKE_INFO_PLIST = ../shared/Info.qmake.macos.plist
OTHER_FILES += assets/*.qml
diff --git a/examples/bluetooth/shared/Info.qmake.macos.plist b/examples/bluetooth/shared/Info.qmake.macos.plist
new file mode 100644
index 00000000..80b3630b
--- /dev/null
+++ b/examples/bluetooth/shared/Info.qmake.macos.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>Qt BT Example wants to access your Bluetooth adapter</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java
index 9ef254f5..2e3e32d5 100644
--- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java
+++ b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java
@@ -82,11 +82,20 @@ public class QtBluetoothLEServer {
private BluetoothGattServer mGattServer = null;
private BluetoothLeAdvertiser mLeAdvertiser = null;
+ private ArrayList<BluetoothGattService> mPendingServiceAdditions =
+ new ArrayList<BluetoothGattService>();
+
private String mRemoteName = "";
- public String remoteName() { return mRemoteName; }
+ // This function is called from Qt thread
+ public synchronized String remoteName() {
+ return mRemoteName;
+ }
private String mRemoteAddress = "";
- public String remoteAddress() { return mRemoteAddress; }
+ // This function is called from Qt thread
+ public synchronized String remoteAddress() {
+ return mRemoteAddress;
+ }
/*
As per Bluetooth specification each connected device can have individual and persistent
@@ -221,170 +230,297 @@ public class QtBluetoothLEServer {
Log.w(TAG, "Let's do BTLE Peripheral.");
}
- /*
- * Call back handler for the Gatt Server.
- */
- private BluetoothGattServerCallback mGattServerListener = new BluetoothGattServerCallback()
- {
- @Override
- public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
- Log.w(TAG, "Our gatt server connection state changed, new state: " + newState + " " + status);
- super.onConnectionStateChange(device, status, newState);
- int qtControllerState = 0;
- switch (newState) {
- case BluetoothProfile.STATE_DISCONNECTED:
- qtControllerState = 0; // QLowEnergyController::UnconnectedState
- clientCharacteristicManager.markDeviceConnectivity(device, false);
- mGattServer.close();
- mGattServer = null;
- break;
- case BluetoothProfile.STATE_CONNECTED:
- clientCharacteristicManager.markDeviceConnectivity(device, true);
- qtControllerState = 2; // QLowEnergyController::ConnectedState
- break;
- }
+ // The following functions are synchronized callback handlers. The callbacks
+ // from Android are forwarded to these methods to synchronize member variable
+ // access with other threads (the Qt thread's JNI calls in particular).
+ //
+ // We use a single lock object (this server) for simplicity because:
+ // - Some variables may change and would thus not be suitable as locking objects but
+ // would require their own additional objects => overhead
+ // - Many accesses to shared variables are infrequent and the code paths are fast and
+ // deterministic meaning that long "wait times" on a lock should not happen
+ // - Typically several shared variables are accessed in a single code block.
+ // If each variable would be protected individually, the amount of (nested) locking
+ // would become quite unreasonable
+
+ public synchronized void handleOnConnectionStateChange(BluetoothDevice device,
+ int status, int newState)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring connection state event, server is disconnected");
+ return;
+ }
- mRemoteName = device.getName();
- mRemoteAddress = device.getAddress();
+ int qtControllerState = 0;
+ switch (newState) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ qtControllerState = 0; // QLowEnergyController::UnconnectedState
+ clientCharacteristicManager.markDeviceConnectivity(device, false);
+ mGattServer.close();
+ mPendingServiceAdditions.clear();
+ mGattServer = null;
+ break;
+ case BluetoothProfile.STATE_CONNECTED:
+ clientCharacteristicManager.markDeviceConnectivity(device, true);
+ qtControllerState = 2; // QLowEnergyController::ConnectedState
+ break;
+ }
- int qtErrorCode;
- switch (status) {
- case BluetoothGatt.GATT_SUCCESS:
- qtErrorCode = 0; break;
- default:
- Log.w(TAG, "Unhandled error code on peripheral connectionStateChanged: " + status + " " + newState);
- qtErrorCode = status;
- break;
- }
+ mRemoteName = device.getName();
+ mRemoteAddress = device.getAddress();
- leServerConnectionStateChange(qtObject, qtErrorCode, qtControllerState);
+ int qtErrorCode;
+ switch (status) {
+ case BluetoothGatt.GATT_SUCCESS:
+ qtErrorCode = 0;
+ break;
+ default:
+ Log.w(TAG, "Unhandled error code on peripheral connectionStateChanged: "
+ + status + " " + newState);
+ qtErrorCode = status;
+ break;
}
+ leServerConnectionStateChange(qtObject, qtErrorCode, qtControllerState);
+ }
- @Override
- public void onServiceAdded(int status, BluetoothGattService service) {
- super.onServiceAdded(status, service);
+ public synchronized void handleOnServiceAdded(int status, BluetoothGattService service)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring service addition event, server is disconnected");
+ return;
}
- @Override
- public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic)
- {
- byte[] dataArray;
- try {
- dataArray = Arrays.copyOfRange(characteristic.getValue(), offset, characteristic.getValue().length);
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, dataArray);
- } catch (Exception ex) {
- Log.w(TAG, "onCharacteristicReadRequest: " + requestId + " " + offset + " " + characteristic.getValue().length);
- ex.printStackTrace();
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, offset, null);
- }
+ Log.d(TAG, "Service " + service.getUuid().toString() + " addition result: " + status);
- super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
+ // Remove the indicated service from the pending queue
+ ListIterator<BluetoothGattService> iterator = mPendingServiceAdditions.listIterator();
+ while (iterator.hasNext()) {
+ if (iterator.next().getUuid().equals(service.getUuid())) {
+ iterator.remove();
+ break;
+ }
}
- @Override
- public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic,
- boolean preparedWrite, boolean responseNeeded, int offset, byte[] value)
- {
- Log.w(TAG, "onCharacteristicWriteRequest");
- int resultStatus = BluetoothGatt.GATT_SUCCESS;
- boolean sendNotificationOrIndication = false;
- if (!preparedWrite) { // regular write
- if (offset == 0) {
- characteristic.setValue(value);
- leServerCharacteristicChanged(qtObject, characteristic, value);
- sendNotificationOrIndication = true;
- } else {
- // This should not really happen as per Bluetooth spec
- Log.w(TAG, "onCharacteristicWriteRequest: !preparedWrite, offset " + offset + ", Not supported");
- resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
- }
+ // If there are more services in the queue, add the next whose add initiation succeeds
+ iterator = mPendingServiceAdditions.listIterator();
+ while (iterator.hasNext()) {
+ BluetoothGattService nextService = iterator.next();
+ if (mGattServer.addService(nextService)) {
+ break;
+ } else {
+ Log.w(TAG, "Adding service " + nextService.getUuid().toString() + " failed");
+ iterator.remove();
+ }
+ }
+ }
+ public synchronized void handleOnCharacteristicReadRequest(BluetoothDevice device,
+ int requestId, int offset,
+ BluetoothGattCharacteristic characteristic)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring characteristic read, server is disconnected");
+ return;
+ }
+ byte[] dataArray;
+ try {
+ dataArray = Arrays.copyOfRange(characteristic.getValue(),
+ offset, characteristic.getValue().length);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+ offset, dataArray);
+ } catch (Exception ex) {
+ Log.w(TAG, "onCharacteristicReadRequest: " + requestId + " "
+ + offset + " " + characteristic.getValue().length);
+ ex.printStackTrace();
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, offset, null);
+ }
+ }
+ public synchronized void handleOnCharacteristicWriteRequest(BluetoothDevice device,
+ int requestId,
+ BluetoothGattCharacteristic characteristic,
+ boolean preparedWrite, boolean responseNeeded,
+ int offset, byte[] value)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring characteristic write, server is disconnected");
+ return;
+ }
+ Log.w(TAG, "onCharacteristicWriteRequest");
+ int resultStatus = BluetoothGatt.GATT_SUCCESS;
+ boolean sendNotificationOrIndication = false;
+ if (!preparedWrite) { // regular write
+ if (offset == 0) {
+ characteristic.setValue(value);
+ leServerCharacteristicChanged(qtObject, characteristic, value);
+ sendNotificationOrIndication = true;
} else {
- Log.w(TAG, "onCharacteristicWriteRequest: preparedWrite, offset " + offset + ", Not supported");
+ // This should not really happen as per Bluetooth spec
+ Log.w(TAG, "onCharacteristicWriteRequest: !preparedWrite, offset "
+ + offset + ", Not supported");
resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
-
- // TODO we need to record all requests and execute them in one go once onExecuteWrite() is received
- // we use a queue to remember the pending requests
- // TODO we are ignoring the device identificator for now -> Bluetooth spec requires a queue per device
}
+ } else {
+ Log.w(TAG, "onCharacteristicWriteRequest: preparedWrite, offset "
+ + offset + ", Not supported");
+ resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
+
+ // TODO we need to record all requests and execute them in one go once onExecuteWrite() is received
+ // we use a queue to remember the pending requests
+ // TODO we are ignoring the device identificator for now -> Bluetooth spec requires a queue per device
+ }
- if (responseNeeded)
- mGattServer.sendResponse(device, requestId, resultStatus, offset, value);
- if (sendNotificationOrIndication)
- sendNotificationsOrIndications(characteristic);
+ if (responseNeeded)
+ mGattServer.sendResponse(device, requestId, resultStatus, offset, value);
+ if (sendNotificationOrIndication)
+ sendNotificationsOrIndications(characteristic);
+ }
- super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
+ public synchronized void handleOnDescriptorReadRequest(BluetoothDevice device, int requestId,
+ int offset, BluetoothGattDescriptor descriptor)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring descriptor read, server is disconnected");
+ return;
}
- @Override
- public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor)
- {
- byte[] dataArray = descriptor.getValue();
- try {
- if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) {
- dataArray = clientCharacteristicManager.valueFor(descriptor.getCharacteristic(), device);
- if (dataArray == null)
- dataArray = descriptor.getValue();
- }
-
- dataArray = Arrays.copyOfRange(dataArray, offset, dataArray.length);
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, dataArray);
- } catch (Exception ex) {
- Log.w(TAG, "onDescriptorReadRequest: " + requestId + " " + offset + " " + dataArray.length);
- ex.printStackTrace();
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, offset, null);
+ byte[] dataArray = descriptor.getValue();
+ try {
+ if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) {
+ dataArray = clientCharacteristicManager.valueFor(
+ descriptor.getCharacteristic(), device);
+ if (dataArray == null)
+ dataArray = descriptor.getValue();
}
- super.onDescriptorReadRequest(device, requestId, offset, descriptor);
+ dataArray = Arrays.copyOfRange(dataArray, offset, dataArray.length);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+ offset, dataArray);
+ } catch (Exception ex) {
+ Log.w(TAG, "onDescriptorReadRequest: " + requestId + " "
+ + offset + " " + dataArray.length);
+ ex.printStackTrace();
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE,
+ offset, null);
}
+ }
- @Override
- public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor,
- boolean preparedWrite, boolean responseNeeded, int offset, byte[] value)
- {
- int resultStatus = BluetoothGatt.GATT_SUCCESS;
- if (!preparedWrite) { // regular write
- if (offset == 0) {
- descriptor.setValue(value);
-
- if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) {
- clientCharacteristicManager.insertOrUpdate(descriptor.getCharacteristic(),
- device, value);
- }
+ public synchronized void handleOnDescriptorWriteRequest(BluetoothDevice device, int requestId,
+ BluetoothGattDescriptor descriptor, boolean preparedWrite,
+ boolean responseNeeded, int offset, byte[] value)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring descriptor write, server is disconnected");
+ return;
+ }
+ int resultStatus = BluetoothGatt.GATT_SUCCESS;
+ if (!preparedWrite) { // regular write
+ if (offset == 0) {
+ descriptor.setValue(value);
- leServerDescriptorWritten(qtObject, descriptor, value);
- } else {
- // This should not really happen as per Bluetooth spec
- Log.w(TAG, "onDescriptorWriteRequest: !preparedWrite, offset " + offset + ", Not supported");
- resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
+ if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) {
+ clientCharacteristicManager.insertOrUpdate(descriptor.getCharacteristic(),
+ device, value);
}
-
+ leServerDescriptorWritten(qtObject, descriptor, value);
} else {
- Log.w(TAG, "onDescriptorWriteRequest: preparedWrite, offset " + offset + ", Not supported");
+ // This should not really happen as per Bluetooth spec
+ Log.w(TAG, "onDescriptorWriteRequest: !preparedWrite, offset "
+ + offset + ", Not supported");
resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
- // TODO we need to record all requests and execute them in one go once onExecuteWrite() is received
- // we use a queue to remember the pending requests
- // TODO we are ignoring the device identificator for now -> Bluetooth spec requires a queue per device
}
+ } else {
+ Log.w(TAG, "onDescriptorWriteRequest: preparedWrite, offset "
+ + offset + ", Not supported");
+ resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
+ // TODO we need to record all requests and execute them in one go once onExecuteWrite() is received
+ // we use a queue to remember the pending requests
+ // TODO we are ignoring the device identificator for now -> Bluetooth spec requires a queue per device
+ }
- if (responseNeeded)
- mGattServer.sendResponse(device, requestId, resultStatus, offset, value);
+ if (responseNeeded)
+ mGattServer.sendResponse(device, requestId, resultStatus, offset, value);
+ }
- super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
+ public synchronized void handleOnExecuteWrite(BluetoothDevice device,
+ int requestId, boolean execute)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring execute write, server is disconnected");
+ return;
}
+ // TODO not yet implemented -> return proper GATT error for it
+ mGattServer.sendResponse(device, requestId,
+ BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, 0, null);
+ }
+ /*
+ * Call back handler for the Gatt Server.
+ */
+ private BluetoothGattServerCallback mGattServerListener = new BluetoothGattServerCallback()
+ {
@Override
- public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute)
+ public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
+ super.onConnectionStateChange(device, status, newState);
+ handleOnConnectionStateChange(device, status, newState);
+ }
+
+ @Override
+ public void onServiceAdded(int status, BluetoothGattService service) {
+ super.onServiceAdded(status, service);
+ handleOnServiceAdded(status, service);
+ }
+
+ @Override
+ public void onCharacteristicReadRequest(BluetoothDevice device,
+ int requestId, int offset,
+ BluetoothGattCharacteristic characteristic)
+ {
+ super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
+ handleOnCharacteristicReadRequest(device, requestId, offset, characteristic);
+ }
+
+ @Override
+ public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
+ BluetoothGattCharacteristic characteristic,
+ boolean preparedWrite, boolean responseNeeded,
+ int offset, byte[] value)
+ {
+ super.onCharacteristicWriteRequest(device, requestId, characteristic,
+ preparedWrite, responseNeeded, offset, value);
+ handleOnCharacteristicWriteRequest(device, requestId, characteristic,
+ preparedWrite, responseNeeded, offset, value);
+ }
+
+ @Override
+ public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
+ int offset, BluetoothGattDescriptor descriptor)
+ {
+ super.onDescriptorReadRequest(device, requestId, offset, descriptor);
+ handleOnDescriptorReadRequest(device, requestId, offset, descriptor);
+ }
+
+ @Override
+ public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
+ BluetoothGattDescriptor descriptor,
+ boolean preparedWrite, boolean responseNeeded,
+ int offset, byte[] value)
{
- // TODO not yet implemented -> return proper GATT error for it
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, 0, null);
+ super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite,
+ responseNeeded, offset, value);
+ handleOnDescriptorWriteRequest(device, requestId, descriptor, preparedWrite,
+ responseNeeded, offset, value);
+ }
+ @Override
+ public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute)
+ {
super.onExecuteWrite(device, requestId, execute);
+ handleOnExecuteWrite(device, requestId, execute);
}
@Override
@@ -393,14 +529,15 @@ public class QtBluetoothLEServer {
Log.w(TAG, "onNotificationSent" + device + " " + status);
}
- // MTU change disabled since it requires API level 22. Right now we only enforce lvl 21
+// MTU change disabled since it requires API level 22. Right now we only enforce lvl 21
// @Override
// public void onMtuChanged(BluetoothDevice device, int mtu) {
// super.onMtuChanged(device, mtu);
// }
};
- public boolean connectServer()
+ // This function is called from Qt thread
+ public synchronized boolean connectServer()
{
if (mGattServer != null)
return true;
@@ -416,11 +553,13 @@ public class QtBluetoothLEServer {
return (mGattServer != null);
}
- public void disconnectServer()
+ // This function is called from Qt thread
+ public synchronized void disconnectServer()
{
if (mGattServer == null)
return;
+ mPendingServiceAdditions.clear();
mGattServer.close();
mGattServer = null;
@@ -428,6 +567,7 @@ public class QtBluetoothLEServer {
leServerConnectionStateChange(qtObject, 0 /*NoError*/, 0 /*QLowEnergyController::UnconnectedState*/);
}
+ // This function is called from Qt thread
public boolean startAdvertising(AdvertiseData advertiseData,
AdvertiseData scanResponse,
AdvertiseSettings settings)
@@ -446,6 +586,7 @@ public class QtBluetoothLEServer {
return true;
}
+ // This function is called from Qt thread
public void stopAdvertising()
{
if (mLeAdvertiser == null)
@@ -455,20 +596,33 @@ public class QtBluetoothLEServer {
Log.w(TAG, "Advertisement stopped.");
}
- public void addService(BluetoothGattService service)
+ // This function is called from Qt thread
+ public synchronized void addService(BluetoothGattService service)
{
if (!connectServer()) {
Log.w(TAG, "Server::addService: Cannot open GATT server");
return;
}
- boolean success = mGattServer.addService(service);
- Log.w(TAG, "Services successfully added: " + success);
+ // When we add a service, we must wait for onServiceAdded callback before adding the
+ // next one. If the pending service queue is empty it means that there are no ongoing
+ // service additions => add the service to the server. If there are services in the
+ // queue it means there is an initiated addition ongoing, and we only add to the queue.
+ if (mPendingServiceAdditions.isEmpty()) {
+ if (mGattServer.addService(service))
+ mPendingServiceAdditions.add(service);
+ else
+ Log.w(TAG, "Adding service " + service.getUuid().toString() + " failed.");
+ } else {
+ mPendingServiceAdditions.add(service);
+ }
}
/*
Check the client characteristics configuration for the given characteristic
and sends notifications or indications as per required.
+
+ This function is called from Qt and Java threads and calls must be protected
*/
private void sendNotificationsOrIndications(BluetoothGattCharacteristic characteristic)
{
@@ -518,9 +672,13 @@ public class QtBluetoothLEServer {
return false;
}
- foundChar.setValue(newValue);
- sendNotificationsOrIndications(foundChar);
-
+ synchronized (this) // a value update might be in progress
+ {
+ foundChar.setValue(newValue);
+ // Value is updated even if server is not connected, but notifying is not possible
+ if (mGattServer != null)
+ sendNotificationsOrIndications(foundChar);
+ }
return true;
}
@@ -557,8 +715,10 @@ public class QtBluetoothLEServer {
// we even write CLIENT_CHARACTERISTIC_CONFIGURATION_UUID this way as we choose
// to interpret the server's call as a change of the default value.
- foundDesc.setValue(newValue);
-
+ synchronized (this) // a value update might be in progress
+ {
+ foundDesc.setValue(newValue);
+ }
return true;
}
diff --git a/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java b/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java
index 19e645f5..610d4cd6 100644
--- a/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java
+++ b/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java
@@ -52,6 +52,7 @@ import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.os.Bundle;
+import android.os.Build;
import android.util.Log;
import android.content.BroadcastReceiver;
import android.content.pm.PackageManager;
@@ -82,11 +83,16 @@ public class QtNfc
return;
}
+ // Since Android 12 (API level 31) it's mandatory to specify mutability
+ // of PendingIntent. We need a mutable intent, which was a default
+ // option earlier.
+ int flags = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? PendingIntent.FLAG_MUTABLE
+ : 0;
m_pendingIntent = PendingIntent.getActivity(
m_activity,
0,
new Intent(m_activity, m_activity.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
- 0);
+ flags);
//Log.d(TAG, "Pending intent:" + m_pendingIntent);
diff --git a/src/bluetooth/osx/osxbtconnectionmonitor.mm b/src/bluetooth/osx/osxbtconnectionmonitor.mm
index b777af8e..f41bbed5 100644
--- a/src/bluetooth/osx/osxbtconnectionmonitor.mm
+++ b/src/bluetooth/osx/osxbtconnectionmonitor.mm
@@ -81,14 +81,8 @@ using namespace QT_NAMESPACE;
- (void)dealloc
{
- [discoveryNotification unregister];
- [discoveryNotification release];
-
- for (IOBluetoothUserNotification *n in foundConnections)
- [n unregister];
-
- [foundConnections release];
-
+ Q_ASSERT_X(!monitor, "-dealloc",
+ "Connection monitor was not stopped, calling -stopMonitoring is required");
[super dealloc];
}
@@ -137,4 +131,18 @@ using namespace QT_NAMESPACE;
monitor->deviceDisconnected(deviceAddress);
}
+- (void)stopMonitoring
+{
+ monitor = nullptr;
+ [discoveryNotification unregister];
+ [discoveryNotification release];
+ discoveryNotification = nil;
+
+ for (IOBluetoothUserNotification *n in foundConnections)
+ [n unregister];
+
+ [foundConnections release];
+ foundConnections = nil;
+}
+
@end
diff --git a/src/bluetooth/osx/osxbtconnectionmonitor_p.h b/src/bluetooth/osx/osxbtconnectionmonitor_p.h
index 679f6124..50dc9d77 100644
--- a/src/bluetooth/osx/osxbtconnectionmonitor_p.h
+++ b/src/bluetooth/osx/osxbtconnectionmonitor_p.h
@@ -84,6 +84,8 @@ QT_END_NAMESPACE
- (void)connectionNotification:(id)notification withDevice:(IOBluetoothDevice *)device;
- (void)connectionClosedNotification:(id)notification withDevice:(IOBluetoothDevice *)device;
+- (void)stopMonitoring;
+
@end
#endif
diff --git a/src/bluetooth/osx/osxbtutility.mm b/src/bluetooth/osx/osxbtutility.mm
index c7fa7c42..3d41a224 100644
--- a/src/bluetooth/osx/osxbtutility.mm
+++ b/src/bluetooth/osx/osxbtutility.mm
@@ -42,6 +42,7 @@
#include "osxbtutility_p.h"
#include "qbluetoothuuid.h"
+#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qendian.h>
#include <QtCore/qstring.h>
@@ -76,6 +77,8 @@ const int defaultLEScanTimeoutMS = 25000;
// We use it only on iOS for now:
const int maxValueLength = 512;
+NSString *const bluetoothUsageKey = @"NSBluetoothAlwaysUsageDescription";
+
QString qt_address(NSString *address)
{
if (address && address.length) {
@@ -351,6 +354,22 @@ ObjCStrongReference<NSMutableData> mutable_data_from_bytearray(const QByteArray
return result;
}
+bool qt_appNeedsBluetoothUsageDescription()
+{
+#ifdef Q_OS_MACOS
+ return QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSBigSur;
+#endif
+ return true;
+}
+
+bool qt_appPlistContainsDescription(NSString *key)
+{
+ Q_ASSERT(key);
+
+ NSDictionary<NSString *, id> *infoDict = NSBundle.mainBundle.infoDictionary;
+ return !!infoDict[key];
+}
+
// A small RAII class for a dispatch queue.
class SerialDispatchQueue
{
diff --git a/src/bluetooth/osx/osxbtutility_p.h b/src/bluetooth/osx/osxbtutility_p.h
index c2bc6cf8..1b1d44be 100644
--- a/src/bluetooth/osx/osxbtutility_p.h
+++ b/src/bluetooth/osx/osxbtutility_p.h
@@ -307,6 +307,12 @@ dispatch_queue_t qt_LE_queue();
extern const int defaultLEScanTimeoutMS;
extern const int maxValueLength;
+// Add more keys if needed, for now this one is enough:
+extern NSString *const bluetoothUsageKey;
+
+bool qt_appNeedsBluetoothUsageDescription();
+bool qt_appPlistContainsDescription(NSString *key);
+
} // namespace OSXBluetooth
// Logging category for both OS X and iOS.
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm
index d9883d28..a5cb034a 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm
@@ -144,6 +144,8 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
{
+ using namespace OSXBluetooth;
+
Q_ASSERT(!isActive());
Q_ASSERT(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError);
Q_ASSERT(methods & (QBluetoothDeviceDiscoveryAgent::ClassicMethod
@@ -157,6 +159,25 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
}
#endif // Q_OS_MACOS
+ // To be able to scan for devices, iOS requires Info.plist containing
+ // NSBluetoothAlwaysUsageDescription entry with a string, explaining
+ // the usage of Bluetooth interface. macOS also requires this description,
+ // starting from Monterey.
+
+ // No Classic on iOS, and Classic does not require a description on macOS:
+ if (methods.testFlag(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)
+ && qt_appNeedsBluetoothUsageDescription()
+ && !qt_appPlistContainsDescription(bluetoothUsageKey)) {
+ // This would result in Bluetooth framework throwing an exception
+ // the moment we try to start device discovery.
+ qCWarning(QT_BT_OSX)
+ << "A proper Info.plist with NSBluetoothAlwaysUsageDescription "
+ "entry is required, cannot start device discovery";
+ setError(QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod);
+ emit q_ptr->error(lastError);
+ return;
+ }
+
requestedMethods = methods;
if (stopPending) {
diff --git a/src/bluetooth/qbluetoothlocaldevice_osx.mm b/src/bluetooth/qbluetoothlocaldevice_osx.mm
index e7dd9906..2bf467f8 100644
--- a/src/bluetooth/qbluetoothlocaldevice_osx.mm
+++ b/src/bluetooth/qbluetoothlocaldevice_osx.mm
@@ -66,6 +66,7 @@ public:
QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *, const QBluetoothAddress & =
QBluetoothAddress());
+ ~QBluetoothLocalDevicePrivate();
bool isValid() const;
void requestPairing(const QBluetoothAddress &address, Pairing pairing);
@@ -147,6 +148,11 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice
connectionMonitor.reset([[ObjCConnectionMonitor alloc] initWithMonitor:this]);
}
+QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
+{
+ [connectionMonitor stopMonitoring];
+}
+
bool QBluetoothLocalDevicePrivate::isValid() const
{
return hostController.data();
diff --git a/src/bluetooth/qbluetoothsocket_winrt.cpp b/src/bluetooth/qbluetoothsocket_winrt.cpp
index 48b14757..d562f6f7 100644
--- a/src/bluetooth/qbluetoothsocket_winrt.cpp
+++ b/src/bluetooth/qbluetoothsocket_winrt.cpp
@@ -576,6 +576,17 @@ QString QBluetoothSocketPrivateWinRT::localName() const
return device.name();
}
+static QString fromWinApiAddress(HString address)
+{
+ // WinAPI returns address with parentheses around it. We need to remove
+ // them to convert to QBluetoothAddress.
+ QString addressStr(qt_QStringFromHString(address));
+ if (addressStr.startsWith(QLatin1Char('(')) && addressStr.endsWith(QLatin1Char(')'))) {
+ addressStr = addressStr.mid(1, addressStr.size() - 2);
+ }
+ return addressStr;
+}
+
QBluetoothAddress QBluetoothSocketPrivateWinRT::localAddress() const
{
if (!m_socketObject)
@@ -588,10 +599,13 @@ QBluetoothAddress QBluetoothSocketPrivateWinRT::localAddress() const
ComPtr<IHostName> localHost;
hr = info->get_LocalAddress(&localHost);
Q_ASSERT_SUCCEEDED(hr);
- HString localAddress;
- hr = localHost->get_CanonicalName(localAddress.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- return QBluetoothAddress(qt_QStringFromHString(localAddress));
+ if (localHost) {
+ HString localAddress;
+ hr = localHost->get_CanonicalName(localAddress.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ return QBluetoothAddress(fromWinApiAddress(std::move(localAddress)));
+ }
+ return QBluetoothAddress();
}
quint16 QBluetoothSocketPrivateWinRT::localPort() const
@@ -627,10 +641,13 @@ QString QBluetoothSocketPrivateWinRT::peerName() const
ComPtr<IHostName> remoteHost;
hr = info->get_RemoteHostName(&remoteHost);
Q_ASSERT_SUCCEEDED(hr);
- HString remoteHostName;
- hr = remoteHost->get_DisplayName(remoteHostName.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- return qt_QStringFromHString(remoteHostName);
+ if (remoteHost) {
+ HString remoteHostName;
+ hr = remoteHost->get_DisplayName(remoteHostName.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ return qt_QStringFromHString(remoteHostName);
+ }
+ return {};
}
QBluetoothAddress QBluetoothSocketPrivateWinRT::peerAddress() const
@@ -645,10 +662,13 @@ QBluetoothAddress QBluetoothSocketPrivateWinRT::peerAddress() const
ComPtr<IHostName> remoteHost;
hr = info->get_RemoteAddress(&remoteHost);
Q_ASSERT_SUCCEEDED(hr);
- HString remoteAddress;
- hr = remoteHost->get_CanonicalName(remoteAddress.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- return QBluetoothAddress(qt_QStringFromHString(remoteAddress));
+ if (remoteHost) {
+ HString remoteAddress;
+ hr = remoteHost->get_CanonicalName(remoteAddress.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ return QBluetoothAddress(fromWinApiAddress(std::move(remoteAddress)));
+ }
+ return QBluetoothAddress();
}
quint16 QBluetoothSocketPrivateWinRT::peerPort() const
@@ -661,7 +681,7 @@ quint16 QBluetoothSocketPrivateWinRT::peerPort() const
hr = m_socketObject->get_Information(&info);
Q_ASSERT_SUCCEEDED(hr);
HString remotePortString;
- hr = info->get_LocalPort(remotePortString.GetAddressOf());
+ hr = info->get_RemotePort(remotePortString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
bool ok = true;
const uint port = qt_QStringFromHString(remotePortString).toUInt(&ok);
diff --git a/src/bluetooth/qlowenergycontroller_darwin.mm b/src/bluetooth/qlowenergycontroller_darwin.mm
index e2b3d618..019cabf8 100644
--- a/src/bluetooth/qlowenergycontroller_darwin.mm
+++ b/src/bluetooth/qlowenergycontroller_darwin.mm
@@ -165,7 +165,14 @@ bool QLowEnergyControllerPrivateDarwin::isValid() const
void QLowEnergyControllerPrivateDarwin::init()
{
- using OSXBluetooth::LECBManagerNotifier;
+ using namespace OSXBluetooth;
+
+ if (qt_appNeedsBluetoothUsageDescription() && !qt_appPlistContainsDescription(bluetoothUsageKey)) {
+ qCWarning(QT_BT_OSX)
+ << "The Info.plist file is required to contain "
+ "'NSBluetoothAlwaysUsageDescription' entry";
+ return;
+ }
QScopedPointer<LECBManagerNotifier> notifier(new LECBManagerNotifier);
if (role == QLowEnergyController::PeripheralRole) {
@@ -202,7 +209,7 @@ void QLowEnergyControllerPrivateDarwin::connectToDevice()
Q_FUNC_INFO, "invalid state");
if (!isValid()) {
- // init() had failed for was never called.
+ // init() had failed or was never called.
return _q_CBManagerError(QLowEnergyController::UnknownError);
}
@@ -234,6 +241,8 @@ void QLowEnergyControllerPrivateDarwin::connectToDevice()
void QLowEnergyControllerPrivateDarwin::disconnectFromDevice()
{
+ Q_ASSERT(isValid()); // Check for proper state is in q's code.
+
if (role == QLowEnergyController::PeripheralRole) {
// CoreBluetooth API intentionally does not provide any way of closing
// a connection. All we can do here is to stop the advertisement.
@@ -241,29 +250,28 @@ void QLowEnergyControllerPrivateDarwin::disconnectFromDevice()
return;
}
- if (isValid()) {
- const auto oldState = state;
+ const auto oldState = state;
- if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
- setState(QLowEnergyController::ClosingState);
- invalidateServices();
- auto manager = centralManager.getAs<ObjCCentralManager>();
- dispatch_async(leQueue, ^{
- [manager disconnectFromDevice];
- });
+ if (dispatch_queue_t leQueue = OSXBluetooth::qt_LE_queue()) {
+ setState(QLowEnergyController::ClosingState);
+ invalidateServices();
- if (oldState == QLowEnergyController::ConnectingState) {
- // With a pending connect attempt there is no
- // guarantee we'll ever have didDisconnect callback,
- // set the state here and now to make sure we still
- // can connect.
- setState(QLowEnergyController::UnconnectedState);
- }
- } else {
- qCCritical(QT_BT_OSX) << "qt LE queue is nil, "
- "can not dispatch 'disconnect'";
+ auto manager = centralManager.getAs<ObjCCentralManager>();
+ dispatch_async(leQueue, ^{
+ [manager disconnectFromDevice];
+ });
+
+ if (oldState == QLowEnergyController::ConnectingState) {
+ // With a pending connect attempt there is no
+ // guarantee we'll ever have didDisconnect callback,
+ // set the state here and now to make sure we still
+ // can connect.
+ setState(QLowEnergyController::UnconnectedState);
}
+ } else {
+ qCCritical(QT_BT_OSX) << "qt LE queue is nil, "
+ "can not dispatch 'disconnect'";
}
}
@@ -274,6 +282,8 @@ void QLowEnergyControllerPrivateDarwin::discoverServices()
Q_ASSERT_X(role != QLowEnergyController::PeripheralRole,
Q_FUNC_INFO, "invalid role (peripheral)");
+ Q_ASSERT(isValid()); // Check we're in a proper state is in q's code.
+
dispatch_queue_t leQueue(OSXBluetooth::qt_LE_queue());
Q_ASSERT_X(leQueue, Q_FUNC_INFO, "LE queue not found");
@@ -334,6 +344,11 @@ QLowEnergyService * QLowEnergyControllerPrivateDarwin::addServiceHelper(const QL
Q_UNUSED(service);
qCDebug(QT_BT_OSX, "peripheral role is not supported on tvOS");
#else
+ if (!isValid()) {
+ qCWarning(QT_BT_OSX) << "invalid peripheral";
+ return nullptr;
+ }
+
if (role != QLowEnergyController::PeripheralRole) {
qCWarning(QT_BT_OSX) << "not in peripheral role";
return nullptr;
@@ -1040,14 +1055,16 @@ void QLowEnergyControllerPrivateDarwin::startAdvertising(const QLowEnergyAdverti
qCWarning(QT_BT_OSX) << "advertising is not supported on your platform";
#else
- if (!isValid())
- return _q_CBManagerError(QLowEnergyController::UnknownError);
-
if (role != QLowEnergyController::PeripheralRole) {
qCWarning(QT_BT_OSX) << "controller is not a peripheral, cannot start advertising";
return;
}
+ if (!isValid()) {
+ qCWarning(QT_BT_OSX, "LE controller is an invalid peripheral");
+ return;
+ }
+
if (state != QLowEnergyController::UnconnectedState) {
qCWarning(QT_BT_OSX) << "invalid state" << state;
return;
diff --git a/src/bluetooth/qlowenergycontroller_darwin_p.h b/src/bluetooth/qlowenergycontroller_darwin_p.h
index 960d7fbc..3c98ca34 100644
--- a/src/bluetooth/qlowenergycontroller_darwin_p.h
+++ b/src/bluetooth/qlowenergycontroller_darwin_p.h
@@ -108,7 +108,10 @@ public:
const QLowEnergyAdvertisingData &scanResponseData) override;
void stopAdvertising()override;
QLowEnergyService *addServiceHelper(const QLowEnergyServiceData &service) override;
- bool isValid() const; // QT6 - delete this logic.
+
+ // Valid - a central or peripheral instance was allocated, and this may also
+ // mean a proper usage description was provided/found:
+ bool isValid() const;
private Q_SLOTS:
void _q_connected();
diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp
index 5b14a92c..f69a0d91 100644
--- a/src/bluetooth/qlowenergycontroller_winrt.cpp
+++ b/src/bluetooth/qlowenergycontroller_winrt.cpp
@@ -642,10 +642,10 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails(const QBluetoothUu
QThread *thread = new QThread;
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &QWinRTLowEnergyServiceHandler::obtainCharList);
- connect(thread, &QThread::finished, thread, &QObject::deleteLater);
connect(thread, &QThread::finished, worker, &QObject::deleteLater);
- connect(worker, &QWinRTLowEnergyServiceHandler::charListObtained,
- [this, thread](const QBluetoothUuid &service, QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> charList
+ connect(worker, &QObject::destroyed, thread, &QObject::deleteLater);
+ connect(worker, &QWinRTLowEnergyServiceHandler::charListObtained, this,
+ [this](const QBluetoothUuid &service, QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> charList
, QVector<QBluetoothUuid> indicateChars
, QLowEnergyHandle startHandle, QLowEnergyHandle endHandle) {
if (!serviceList.contains(service)) {
@@ -668,7 +668,6 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails(const QBluetoothUu
Q_ASSERT_SUCCEEDED(hr);
pointer->setState(QLowEnergyService::ServiceDiscovered);
- thread->exit(0);
});
thread->start();
}
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
index a6371c0a..42f4380e 100644
--- a/src/bluetooth/qlowenergycontroller_winrt_new.cpp
+++ b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
@@ -711,8 +711,8 @@ void QLowEnergyControllerPrivateWinRTNew::connectToDevice()
connect(this, &QLowEnergyControllerPrivateWinRTNew::abortConnection, worker,
&QWinRTLowEnergyConnectionHandler::handleDeviceDisconnectRequest);
connect(thread, &QThread::started, worker, &QWinRTLowEnergyConnectionHandler::connectToDevice);
- connect(thread, &QThread::finished, thread, &QObject::deleteLater);
connect(thread, &QThread::finished, worker, &QObject::deleteLater);
+ connect(worker, &QObject::destroyed, thread, &QObject::deleteLater);
connect(worker, &QWinRTLowEnergyConnectionHandler::errorOccurred, this,
[this](const QString &msg) { handleConnectionError(msg.toUtf8().constData()); });
connect(worker, &QWinRTLowEnergyConnectionHandler::deviceConnected, this,
@@ -1166,12 +1166,12 @@ void QLowEnergyControllerPrivateWinRTNew::discoverServiceDetails(const QBluetoot
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, &QObject::destroyed, thread, &QObject::deleteLater);
connect(worker, &QWinRTLowEnergyServiceHandlerNew::errorOccured,
this, &QLowEnergyControllerPrivateWinRTNew::handleServiceHandlerError);
- connect(worker, &QWinRTLowEnergyServiceHandlerNew::charListObtained,
- [this, reactOnDiscoveryError, thread](const QBluetoothUuid &service, QHash<QLowEnergyHandle,
+ connect(worker, &QWinRTLowEnergyServiceHandlerNew::charListObtained, this,
+ [this, reactOnDiscoveryError](const QBluetoothUuid &service, QHash<QLowEnergyHandle,
QLowEnergyServicePrivate::CharData> charList, QVector<QBluetoothUuid> indicateChars,
QLowEnergyHandle startHandle, QLowEnergyHandle endHandle) {
if (!serviceList.contains(service)) {
@@ -1194,12 +1194,10 @@ void QLowEnergyControllerPrivateWinRTNew::discoverServiceDetails(const QBluetoot
if (FAILED(hr)) {
reactOnDiscoveryError(pointer,
QStringLiteral("Could not register for value changes in Xaml thread: %1").arg(hr));
- thread->exit(0);
return;
}
pointer->setState(QLowEnergyService::ServiceDiscovered);
- thread->exit(0);
});
thread->start();
}