From 184307884f560653421286cc9e5e6f0e86a4cef4 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Thu, 12 Apr 2018 11:17:00 +0200 Subject: BlueZ: Ensure that QLEController::remoteName() has a value This fixes the problem for the custom GATT stack on Bluez4 and older Bluez5 versions (below 5.42). Task-number: QTBUG-67651 Change-Id: Ia3c64c06777c8d357f615d681838bcdc83b92236 Reviewed-by: Oliver Wolff Reviewed-by: Alex Blasche --- src/bluetooth/qlowenergycontroller_bluez.cpp | 79 +++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp index 40519b51..d58e0ee8 100644 --- a/src/bluetooth/qlowenergycontroller_bluez.cpp +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -44,10 +44,16 @@ #include "qleadvertiser_p.h" #include "bluez/bluez_data_p.h" #include "bluez/hcimanager_p.h" +#include "bluez/objectmanager_p.h" #include "bluez/remotedevicemanager_p.h" #include "bluez/bluez5_helper_p.h" #include "bluez/bluetoothmanagement_p.h" +// Bluez 4 +#include "bluez/adapter_p.h" +#include "bluez/device_p.h" +#include "bluez/manager_p.h" + #include #include #include @@ -746,8 +752,11 @@ void QLowEnergyControllerPrivateBluez::l2cpDisconnected() { Q_Q(QLowEnergyController); - if (role == QLowEnergyController::PeripheralRole) + if (role == QLowEnergyController::PeripheralRole) { storeClientConfigurations(); + remoteDevice.clear(); + remoteName.clear(); + } invalidateServices(); resetController(); setState(QLowEnergyController::UnconnectedState); @@ -3012,6 +3021,69 @@ void QLowEnergyControllerPrivateBluez::sendNextIndication() sendIndication(scheduledIndications.takeFirst()); } +static QString nameOfRemoteCentral(const QBluetoothAddress &peerAddress, const QBluetoothAddress &localAdapter) +{ + const QString peerAddressString = peerAddress.toString(); + if (isBluez5()) { + OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"), + QStringLiteral("/"), + QDBusConnection::systemBus()); + QDBusPendingReply reply = manager.GetManagedObjects(); + reply.waitForFinished(); + if (reply.isError()) + return QString(); + + ManagedObjectList managedObjectList = reply.value(); + for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) { + const InterfaceList &ifaceList = it.value(); + + for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) { + const QString &iface = jt.key(); + const QVariantMap &ifaceValues = jt.value(); + + if (iface == QStringLiteral("org.bluez.Device1")) { + if (ifaceValues.value(QStringLiteral("Address")).toString() == peerAddressString) + return ifaceValues.value(QStringLiteral("Alias")).toString(); + } + } + } + return QString(); + } else { + OrgBluezManagerInterface manager(QStringLiteral("org.bluez"), QStringLiteral("/"), + QDBusConnection::systemBus()); + + QDBusPendingReply reply = manager.FindAdapter(localAdapter.toString()); + reply.waitForFinished(); + if (reply.isError()) + return QString(); + + OrgBluezAdapterInterface adapter(QStringLiteral("org.bluez"), reply.value().path(), + QDBusConnection::systemBus()); + + QDBusPendingReply deviceObjectPath = adapter.FindDevice(peerAddressString); + deviceObjectPath.waitForFinished(); + if (deviceObjectPath.isError()) { + if (deviceObjectPath.error().name() != QStringLiteral("org.bluez.Error.DoesNotExist")) + return QString(); + + deviceObjectPath = adapter.CreateDevice(peerAddressString); + deviceObjectPath.waitForFinished(); + if (deviceObjectPath.isError()) + return QString(); + } + + OrgBluezDeviceInterface device(QStringLiteral("org.bluez"), deviceObjectPath.value().path(), + QDBusConnection::systemBus()); + + QDBusPendingReply properties = device.GetProperties(); + properties.waitForFinished(); + if (properties.isError()) + return QString(); + + return properties.value().value(QStringLiteral("Alias")).toString(); + } +} + void QLowEnergyControllerPrivateBluez::handleConnectionRequest() { if (state != QLowEnergyController::AdvertisingState) { @@ -3030,8 +3102,11 @@ void QLowEnergyControllerPrivateBluez::handleConnectionRequest() serverSocketNotifier->setEnabled(true); return; } + remoteDevice = QBluetoothAddress(convertAddress(clientAddr.l2_bdaddr.b)); - qCDebug(QT_BT_BLUEZ) << "GATT connection from device" << remoteDevice; + remoteName = nameOfRemoteCentral(remoteDevice, localAdapter); + qCDebug(QT_BT_BLUEZ) << "GATT connection from device" << remoteDevice << remoteName; + if (connectionHandle == 0) qCWarning(QT_BT_BLUEZ) << "Received client connection, but no connection complete event"; -- cgit v1.2.3 From e68b5e17b071ca11974474546be04c7d564eae3a Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Fri, 13 Apr 2018 17:17:19 +0200 Subject: Android: Fix start/stop behavior of QLowEnergyController (peripheral) This patch addresses two bugs. Firstly it ensures that the correct Java function is executed when disconectFromDevice() is called on Android peripheral. Secondly, it turned out that calling disconnectFromDevice() while a connection to a central exists and restarting the advertisement resulted in a non-functional QLEController instance because BluetoothGattServer was not properly restarted. As a side effects the controller's state tracking stopped as well. Change-Id: I98851fc974ceff2a1fcb03fe754dbda9c4aba271 Reviewed-by: Timur Pocheptsov --- .../qt5/android/bluetooth/QtBluetoothLEServer.java | 29 +++++++++++++++++----- src/bluetooth/qlowenergycontroller_android.cpp | 8 ++++-- 2 files changed, 29 insertions(+), 8 deletions(-) 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 034190fd..cdd16686 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 @@ -213,7 +213,6 @@ public class QtBluetoothLEServer { return; } - mGattServer = manager.openGattServer(qtContext, mGattServerListener); mLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser(); if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) @@ -229,7 +228,7 @@ public class QtBluetoothLEServer { { @Override public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { - Log.w(TAG, "Our gatt server connection state changed, new state: " + newState); + Log.w(TAG, "Our gatt server connection state changed, new state: " + newState + " " + status); super.onConnectionStateChange(device, status, newState); int qtControllerState = 0; @@ -237,6 +236,7 @@ public class QtBluetoothLEServer { case BluetoothProfile.STATE_DISCONNECTED: qtControllerState = 0; // QLowEnergyController::UnconnectedState clientCharacteristicManager.markDeviceConnectivity(device, false); + mGattServer.close(); break; case BluetoothProfile.STATE_CONNECTED: clientCharacteristicManager.markDeviceConnectivity(device, true); @@ -401,10 +401,18 @@ public class QtBluetoothLEServer { public boolean connectServer() { - if (mGattServer == null) + if (mGattServer != null) + return true; + + BluetoothManager manager = (BluetoothManager) qtContext.getSystemService(Context.BLUETOOTH_SERVICE); + if (manager == null) { + Log.w(TAG, "Bluetooth service not available."); return false; + } - return true; + mGattServer = manager.openGattServer(qtContext, mGattServerListener); + + return (mGattServer != null); } public void disconnectServer() @@ -413,6 +421,10 @@ public class QtBluetoothLEServer { return; mGattServer.close(); + mGattServer = null; + + mRemoteName = mRemoteAddress = ""; + leServerConnectionStateChange(qtObject, 0 /*NoError*/, 0 /*QLowEnergyController::UnconnectedState*/); } public boolean startAdvertising(AdvertiseData advertiseData, @@ -422,7 +434,10 @@ public class QtBluetoothLEServer { if (mLeAdvertiser == null) return false; - connectServer(); + if (!connectServer()) { + Log.w(TAG, "Server::startAdvertising: Cannot open GATT server"); + return false; + } Log.w(TAG, "Starting to advertise."); mLeAdvertiser.startAdvertising(settings, advertiseData, scanResponse, mAdvertiseListener); @@ -441,8 +456,10 @@ public class QtBluetoothLEServer { public void addService(BluetoothGattService service) { - if (mGattServer == null) + if (!connectServer()) { + Log.w(TAG, "Server::addService: Cannot open GATT server"); return; + } mGattServer.addService(service); } diff --git a/src/bluetooth/qlowenergycontroller_android.cpp b/src/bluetooth/qlowenergycontroller_android.cpp index c5c9ba56..54665f7b 100644 --- a/src/bluetooth/qlowenergycontroller_android.cpp +++ b/src/bluetooth/qlowenergycontroller_android.cpp @@ -180,8 +180,12 @@ void QLowEnergyControllerPrivateAndroid::disconnectFromDevice() QLowEnergyController::ControllerState oldState = state; setState(QLowEnergyController::ClosingState); - if (hub) - hub->javaObject().callMethod("disconnect"); + if (hub) { + if (role == QLowEnergyController::PeripheralRole) + hub->javaObject().callMethod("disconnectServer"); + else + hub->javaObject().callMethod("disconnect"); + } if (oldState == QLowEnergyController::ConnectingState) setState(QLowEnergyController::UnconnectedState); -- cgit v1.2.3 From dc435c6ce0a6ecae776dc0dd032016453a0b4b56 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Wed, 18 Apr 2018 09:51:46 +0200 Subject: General QML version bump in docs and qmltypes Change-Id: If31e244e44106af1550e572acb9a172497467b20 Reviewed-by: Kai Koehne --- src/bluetooth/doc/src/bluetooth-qml.qdoc | 2 +- src/imports/bluetooth/plugins.qmltypes | 2 +- src/imports/nfc/plugins.qmltypes | 2 +- src/nfc/doc/src/nfc-qml.qdoc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bluetooth/doc/src/bluetooth-qml.qdoc b/src/bluetooth/doc/src/bluetooth-qml.qdoc index 51aa5a25..2f37cb9b 100644 --- a/src/bluetooth/doc/src/bluetooth-qml.qdoc +++ b/src/bluetooth/doc/src/bluetooth-qml.qdoc @@ -28,7 +28,7 @@ /*! -\qmlmodule QtBluetooth 5.2 +\qmlmodule QtBluetooth 5.11 \title Qt Bluetooth QML Types \ingroup qmlmodules \brief Provides QML types for basic Bluetooth operations on devices. diff --git a/src/imports/bluetooth/plugins.qmltypes b/src/imports/bluetooth/plugins.qmltypes index a00b0324..a22b950a 100644 --- a/src/imports/bluetooth/plugins.qmltypes +++ b/src/imports/bluetooth/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtBluetooth 5.10' +// 'qmlplugindump -nonrelocatable QtBluetooth 5.11' Module { dependencies: ["QtQuick 2.8"] diff --git a/src/imports/nfc/plugins.qmltypes b/src/imports/nfc/plugins.qmltypes index e6e98c24..4f723967 100644 --- a/src/imports/nfc/plugins.qmltypes +++ b/src/imports/nfc/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtNfc 5.10' +// 'qmlplugindump -nonrelocatable QtNfc 5.11' Module { dependencies: ["QtQuick 2.8"] diff --git a/src/nfc/doc/src/nfc-qml.qdoc b/src/nfc/doc/src/nfc-qml.qdoc index 48df6d32..bbacb2de 100644 --- a/src/nfc/doc/src/nfc-qml.qdoc +++ b/src/nfc/doc/src/nfc-qml.qdoc @@ -28,7 +28,7 @@ /*! -\qmlmodule QtNfc 5.2 +\qmlmodule QtNfc 5.11 \title Qt NFC QML Types \ingroup qmlmodules \brief Provides QML types for accessing NFC Forum Tags. -- cgit v1.2.3