diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bluetooth/qbluetoothlocaldevice_android.cpp | 38 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp | 4 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket.cpp | 14 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_android.cpp | 300 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_bluez.cpp | 14 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_p.h | 23 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez.cpp | 20 |
7 files changed, 296 insertions, 117 deletions
diff --git a/src/bluetooth/qbluetoothlocaldevice_android.cpp b/src/bluetooth/qbluetoothlocaldevice_android.cpp index 133b76b9..20ac3d0a 100644 --- a/src/bluetooth/qbluetoothlocaldevice_android.cpp +++ b/src/bluetooth/qbluetoothlocaldevice_android.cpp @@ -83,35 +83,20 @@ void QBluetoothLocalDevicePrivate::initialize(const QBluetoothAddress &address) { QAndroidJniEnvironment env; - jclass btAdapterClass = env->FindClass("android/bluetooth/BluetoothAdapter"); - if (btAdapterClass == NULL) { - qCWarning(QT_BT_ANDROID) - << "Native registration unable to find class android/bluetooth/BluetoothAdapter"; - return; - } - - jmethodID getDefaultAdapterID - = env->GetStaticMethodID(btAdapterClass, "getDefaultAdapter", - "()Landroid/bluetooth/BluetoothAdapter;"); - if (getDefaultAdapterID == NULL) { - qCWarning(QT_BT_ANDROID) - << "Native registration unable to get method ID: " \ - "getDefaultAdapter of android/bluetooth/BluetoothAdapter"; - return; - } - - jobject btAdapterObject = env->CallStaticObjectMethod(btAdapterClass, getDefaultAdapterID); - if (btAdapterObject == NULL) { + QAndroidJniObject adapter = QAndroidJniObject::callStaticObjectMethod( + "android/bluetooth/BluetoothAdapter", "getDefaultAdapter", + "()Landroid/bluetooth/BluetoothAdapter;"); + if (!adapter.isValid()) { + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth"; - env->DeleteLocalRef(btAdapterClass); return; } - obj = new QAndroidJniObject(btAdapterObject); - if (!obj->isValid()) { - delete obj; - obj = 0; - } else if (!address.isNull()) { + obj = new QAndroidJniObject(adapter); + if (!address.isNull()) { const QString localAddress = obj->callObjectMethod("getAddress", "()Ljava/lang/String;").toString(); if (localAddress != address.toString()) { @@ -120,9 +105,6 @@ void QBluetoothLocalDevicePrivate::initialize(const QBluetoothAddress &address) obj = 0; } } - - env->DeleteLocalRef(btAdapterObject); - env->DeleteLocalRef(btAdapterClass); } bool QBluetoothLocalDevicePrivate::isValid() const diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp index 86d35428..f66603a9 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp @@ -272,7 +272,9 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_finishSdpScan(QBluetoothServiceD if (errorCode != QBluetoothServiceDiscoveryAgent::NoError) { qCWarning(QT_BT_BLUEZ) << "SDP search failed for" - << discoveredDevices.at(0).address().toString(); + << (!discoveredDevices.isEmpty() + ? discoveredDevices.at(0).address().toString() + : QStringLiteral("<Unknown>")); // We have an error which we need to indicate and stop further processing discoveredDevices.clear(); error = errorCode; diff --git a/src/bluetooth/qbluetoothsocket.cpp b/src/bluetooth/qbluetoothsocket.cpp index e82e866a..56428544 100644 --- a/src/bluetooth/qbluetoothsocket.cpp +++ b/src/bluetooth/qbluetoothsocket.cpp @@ -602,6 +602,13 @@ void QBluetoothSocket::abort() Q_D(QBluetoothSocket); setOpenMode(QIODevice::NotOpen); + + if (state() == ServiceLookupState && d->discoveryAgent) { + d->discoveryAgent->disconnect(); + d->discoveryAgent->stop(); + d->discoveryAgent = 0; + } + setSocketState(ClosingState); d->abort(); @@ -679,6 +686,13 @@ void QBluetoothSocket::close() Q_D(QBluetoothSocket); setOpenMode(QIODevice::NotOpen); + + if (state() == ServiceLookupState && d->discoveryAgent) { + d->discoveryAgent->disconnect(); + d->discoveryAgent->stop(); + d->discoveryAgent = 0; + } + setSocketState(ClosingState); d->close(); diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp index ab257cf4..990ab378 100644 --- a/src/bluetooth/qbluetoothsocket_android.cpp +++ b/src/bluetooth/qbluetoothsocket_android.cpp @@ -36,15 +36,136 @@ #include "qbluetoothsocket_p.h" #include "qbluetoothaddress.h" #include <QtCore/QLoggingCategory> +#include <QtCore/QThread> #include <QtCore/QTime> #include <QtCore/private/qjni_p.h> -#include <QtConcurrent/QtConcurrentRun> #include <QtAndroidExtras/QAndroidJniEnvironment> QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) +#define FALLBACK_CHANNEL 1 +#define USE_FALLBACK true + +Q_DECLARE_METATYPE(QAndroidJniObject) + + +/* BluetoothSocket.connect() can block up to 10s. Therefore it must be + * in a separate thread. Unfortunately if BluetoothSocket.close() is + * called while connect() is still blocking the resulting behavior is not reliable. + * This may well be an Android platform bug. In any case, close() must + * be queued up until connect() has returned. + * + * The WorkerThread manages the connect() and close() calls. Interaction + * with the main thread happens via signals and slots. There is an accepted but + * undesirable side effect of this approach as the user may call connect() + * and close() and the socket would continue to successfully connect to + * the remote device just to immidiately close the physical connection again. + * + * WorkerThread and SocketConnectWorker are cleaned up via the threads + * finished() signal. + */ + +class SocketConnectWorker : public QObject +{ + Q_OBJECT +public: + SocketConnectWorker(const QAndroidJniObject& socket, + const QAndroidJniObject& targetUuid) + : QObject(), + mSocketObject(socket), + mTargetUuid(targetUuid) + { + static int t = qRegisterMetaType<QAndroidJniObject>(); + Q_UNUSED(t); + } + +signals: + void socketConnectDone(const QAndroidJniObject &socket); + void socketConnectFailed(const QAndroidJniObject &socket, + const QAndroidJniObject &targetUuid); +public slots: + void connectSocket() + { + QAndroidJniEnvironment env; + + qCDebug(QT_BT_ANDROID) << "Connecting socket"; + mSocketObject.callMethod<void>("connect"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + + emit socketConnectFailed(mSocketObject, mTargetUuid); + QThread::currentThread()->quit(); + return; + } + + qCDebug(QT_BT_ANDROID) << "Socket connection established"; + emit socketConnectDone(mSocketObject); + } + + void closeSocket() + { + qCDebug(QT_BT_ANDROID) << "Executing queued closeSocket()"; + + QAndroidJniEnvironment env; + mSocketObject.callMethod<void>("close"); + if (env->ExceptionCheck()) { + + qCWarning(QT_BT_ANDROID) << "Error during closure of abandoned socket"; + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + QThread::currentThread()->quit(); + } + +private: + QAndroidJniObject mSocketObject; + QAndroidJniObject mTargetUuid; +}; + +class WorkerThread: public QThread +{ + Q_OBJECT +public: + WorkerThread() + : QThread(), workerPointer(0) + { + } + + // Runs in same thread as QBluetoothSocketPrivate + void setupWorker(QBluetoothSocketPrivate* d_ptr, const QAndroidJniObject& socketObject, + const QAndroidJniObject& uuidObject, bool useFallback) + { + SocketConnectWorker* worker = new SocketConnectWorker( + socketObject, uuidObject); + worker->moveToThread(this); + + connect(this, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &QThread::finished, this, &QObject::deleteLater); + connect(d_ptr, &QBluetoothSocketPrivate::connectJavaSocket, + worker, &SocketConnectWorker::connectSocket); + connect(d_ptr, &QBluetoothSocketPrivate::closeJavaSocket, + worker, &SocketConnectWorker::closeSocket); + connect(worker, &SocketConnectWorker::socketConnectDone, + d_ptr, &QBluetoothSocketPrivate::socketConnectSuccess); + if (useFallback) { + connect(worker, &SocketConnectWorker::socketConnectFailed, + d_ptr, &QBluetoothSocketPrivate::fallbackSocketConnectFailed); + } else { + connect(worker, &SocketConnectWorker::socketConnectFailed, + d_ptr, &QBluetoothSocketPrivate::defaultSocketConnectFailed); + } + + workerPointer = worker; + } + +private: + QPointer<SocketConnectWorker> workerPointer; +}; + QBluetoothSocketPrivate::QBluetoothSocketPrivate() : socket(-1), socketType(QBluetoothServiceInfo::UnknownProtocol), @@ -63,6 +184,8 @@ QBluetoothSocketPrivate::QBluetoothSocketPrivate() QBluetoothSocketPrivate::~QBluetoothSocketPrivate() { + if (state != QBluetoothSocket::UnconnectedState) + emit closeJavaSocket(); } bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol type) @@ -74,18 +197,6 @@ bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol return false; } -void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, - const QBluetoothUuid &uuid, - QIODevice::OpenMode openMode, - int fallbackServiceChannel) -{ - Q_Q(QBluetoothSocket); - - q->setSocketState(QBluetoothSocket::ConnectingState); - QtConcurrent::run(this, &QBluetoothSocketPrivate::connectToServiceConc, - address, uuid, openMode, fallbackServiceChannel); -} - bool QBluetoothSocketPrivate::fallBackConnect(QAndroidJniObject uuid, int channel) { qCWarning(QT_BT_ANDROID) << "Falling back to workaround."; @@ -181,26 +292,42 @@ bool QBluetoothSocketPrivate::fallBackConnect(QAndroidJniObject uuid, int channe } socketObject = QAndroidJniObject(invokeResult); - socketObject.callMethod<void>("connect"); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - qCWarning(QT_BT_ANDROID) << "Socket connect via workaround failed."; - return false; - } + WorkerThread *workerThread = new WorkerThread(); + workerThread->setupWorker(this, socketObject, uuid, USE_FALLBACK); + workerThread->start(); + emit connectJavaSocket(); - qCWarning(QT_BT_ANDROID) << "Workaround invoked."; + qCWarning(QT_BT_ANDROID) << "Workaround thread invoked."; return true; } -void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &address, - const QBluetoothUuid &uuid, QIODevice::OpenMode openMode, int fallbackServiceChannel) + +/* + * The call order during a connectToService() is as follows: + * + * 1. call connectToService() + * 2. wait for execution of SocketConnectThread::run() + * 3. if threaded connect succeeds call socketConnectSuccess() via signals + * -> done + * 4. if threaded connect fails call defaultSocketConnectFailed() via signals + * 5. call fallBackConnect() + * 6. if threaded connect on fallback channel succeeds call socketConnectSuccess() + * via signals + * -> done + * 7. if threaded connect on fallback channel fails call fallbackSocketConnectFailed() + * -> complete failure of entire connectToService() + * */ +void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, + const QBluetoothUuid &uuid, + QIODevice::OpenMode openMode) { Q_Q(QBluetoothSocket); Q_UNUSED(openMode); - qCDebug(QT_BT_ANDROID) << "connectToServiceConc()" << address.toString() << uuid.toString(); + qCDebug(QT_BT_ANDROID) << "connectToService()" << address.toString() << uuid.toString(); + + q->setSocketState(QBluetoothSocket::ConnectingState); if (!adapter.isValid()) { qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth"; @@ -260,22 +387,21 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr return; } - socketObject.callMethod<void>("connect"); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); + WorkerThread *workerThread = new WorkerThread(); + workerThread->setupWorker(this, socketObject, uuidObject, !USE_FALLBACK); + workerThread->start(); + emit connectJavaSocket(); +} - bool success = fallBackConnect(uuidObject, fallbackServiceChannel); - if (!success) { - errorString = QBluetoothSocket::tr("Connection to service failed"); - socketObject = remoteDevice = QAndroidJniObject(); - q->setSocketError(QBluetoothSocket::ServiceNotFoundError); - q->setSocketState(QBluetoothSocket::UnconnectedState); +void QBluetoothSocketPrivate::socketConnectSuccess(const QAndroidJniObject &socket) +{ + Q_Q(QBluetoothSocket); + QAndroidJniEnvironment env; - env->ExceptionClear(); //just in case - return; - } - } + // test we didn't get a success from a previous connect + // which was cleaned up late + if (socket != socketObject) + return; if (inputThread) { inputThread->deleteLater(); @@ -289,13 +415,7 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr env->ExceptionDescribe(); env->ExceptionClear(); - //close socket again - socketObject.callMethod<void>("close"); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - + emit closeJavaSocket(); socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject(); @@ -313,11 +433,7 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr if (!inputThread->run()) { //close socket again - socketObject.callMethod<void>("close"); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } + emit closeJavaSocket(); socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject(); @@ -337,6 +453,48 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr emit q->connected(); } +void QBluetoothSocketPrivate::defaultSocketConnectFailed( + const QAndroidJniObject &socket, const QAndroidJniObject &targetUuid) +{ + Q_Q(QBluetoothSocket); + + // test we didn't get a fail from a previous connect + // which was cleaned up late - should be same socket + if (socket != socketObject) + return; + + bool success = fallBackConnect(targetUuid, FALLBACK_CHANNEL); + if (!success) { + errorString = QBluetoothSocket::tr("Connection to service failed"); + socketObject = remoteDevice = QAndroidJniObject(); + q->setSocketError(QBluetoothSocket::ServiceNotFoundError); + q->setSocketState(QBluetoothSocket::UnconnectedState); + + QAndroidJniEnvironment env; + env->ExceptionClear(); // just in case + qCWarning(QT_BT_ANDROID) << "Workaround failed"; + } +} + +void QBluetoothSocketPrivate::fallbackSocketConnectFailed( + const QAndroidJniObject &socket, const QAndroidJniObject &targetUuid) +{ + Q_UNUSED(targetUuid); + Q_Q(QBluetoothSocket); + + // test we didn't get a fail from a previous connect + // which was cleaned up late - should be same socket + if (socket != socketObject) + return; + + qCWarning(QT_BT_ANDROID) << "Socket connect via workaround failed."; + errorString = QBluetoothSocket::tr("Connection to service failed"); + socketObject = remoteDevice = QAndroidJniObject(); + + q->setSocketError(QBluetoothSocket::ServiceNotFoundError); + q->setSocketState(QBluetoothSocket::UnconnectedState); +} + void QBluetoothSocketPrivate::abort() { if (state == QBluetoothSocket::UnconnectedState) @@ -356,23 +514,26 @@ void QBluetoothSocketPrivate::abort() if (inputThread) inputThread->prepareForClosure(); - //triggers abort of input thread as well - socketObject.callMethod<void>("close"); - if (env->ExceptionCheck()) { + emit closeJavaSocket(); - qCWarning(QT_BT_ANDROID) << "Error during closure of socket"; - env->ExceptionDescribe(); - env->ExceptionClear(); - } + inputStream = outputStream = socketObject = remoteDevice = QAndroidJniObject(); if (inputThread) { + // inputThread exists hence we had a successful connect + // which means inputThread is responsible for setting Unconnected + //don't delete here as signals caused by Java Thread are still //going to be emitted //delete occurs in inputThreadError() inputThread = 0; + } else { + // inputThread doesn't exist hence + // we abort in the middle of connect(). WorkerThread will do + // close() without further feedback. Therefore we have to set + // Unconnected (now) in advance + Q_Q(QBluetoothSocket); + q->setSocketState(QBluetoothSocket::UnconnectedState); } - - inputStream = outputStream = socketObject = remoteDevice = QAndroidJniObject(); } } @@ -486,14 +647,13 @@ void QBluetoothSocketPrivate::inputThreadError(int errorCode) //cleanup internal objects //if it was call to local close()/abort() the objects are cleaned up already - QAndroidJniEnvironment env; - socketObject.callMethod<void>("close"); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } + emit closeJavaSocket(); inputStream = outputStream = remoteDevice = socketObject = QAndroidJniObject(); + if (inputThread) { + // deleted already above (client->deleteLater()) + inputThread = 0; + } } q->setSocketState(QBluetoothSocket::UnconnectedState); @@ -575,6 +735,14 @@ bool QBluetoothSocketPrivate::setSocketDescriptor(const QAndroidJniObject &socke q->setSocketState(socketState); q->setOpenMode(openMode | QIODevice::Unbuffered); + // WorkerThread manages all sockets for us + // When we come through here the socket was already connected by + // server socket listener (see QBluetoothServer) + // Therefore we only use WorkerThread to potentially close it later on + WorkerThread *workerThread = new WorkerThread(); + workerThread->setupWorker(this, socketObject, QAndroidJniObject(), !USE_FALLBACK); + workerThread->start(); + if (openMode == QBluetoothSocket::ConnectedState) emit q->connected(); @@ -591,3 +759,5 @@ qint64 QBluetoothSocketPrivate::bytesAvailable() const } QT_END_NAMESPACE + +#include <qbluetoothsocket_android.moc> diff --git a/src/bluetooth/qbluetoothsocket_bluez.cpp b/src/bluetooth/qbluetoothsocket_bluez.cpp index 47f5629e..c18ce279 100644 --- a/src/bluetooth/qbluetoothsocket_bluez.cpp +++ b/src/bluetooth/qbluetoothsocket_bluez.cpp @@ -511,20 +511,10 @@ qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize) void QBluetoothSocketPrivate::close() { - Q_Q(QBluetoothSocket); - - // Only go through closing if the socket was fully opened - if(state == QBluetoothSocket::ConnectedState) - q->setSocketState(QBluetoothSocket::ClosingState); - - if(txBuffer.size() > 0 && - state == QBluetoothSocket::ClosingState){ + if (txBuffer.size() > 0) connectWriteNotifier->setEnabled(true); - } - else { + else abort(); - } - } bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType_, diff --git a/src/bluetooth/qbluetoothsocket_p.h b/src/bluetooth/qbluetoothsocket_p.h index 40bc678f..e5ddf798 100644 --- a/src/bluetooth/qbluetoothsocket_p.h +++ b/src/bluetooth/qbluetoothsocket_p.h @@ -52,8 +52,10 @@ #endif #ifdef QT_ANDROID_BLUETOOTH #include <QtAndroidExtras/QAndroidJniObject> +#include <QtCore/QPointer> #include "android/inputstreamthread_p.h" #include <jni.h> +class WorkerThread; #endif #ifndef QPRIVATELINEARBUFFER_BUFFERSIZE @@ -94,18 +96,14 @@ public: ~QBluetoothSocketPrivate(); //On QNX and Android we connect using the uuid not the port -#if defined(QT_QNX_BLUETOOTH) - void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode); -#elif defined(QT_ANDROID_BLUETOOTH) +#if defined(QT_QNX_BLUETOOTH) || defined(QT_ANDROID_BLUETOOTH) void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, - QIODevice::OpenMode openMode, int fallbackServiceChannel = 1); - bool fallBackConnect(QAndroidJniObject uuid, int channel); + QIODevice::OpenMode openMode); #else void connectToService(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode); #endif #ifdef QT_ANDROID_BLUETOOTH - void connectToServiceConc(const QBluetoothAddress &address, const QBluetoothUuid &uuid, - QIODevice::OpenMode openMode, int fallbackServiceChannel = 1); + bool fallBackConnect(QAndroidJniObject uuid, int channel); #endif @@ -167,9 +165,18 @@ public: QAndroidJniObject outputStream; InputStreamThread *inputThread; -private slots: +public slots: + void socketConnectSuccess(const QAndroidJniObject &socket); + void defaultSocketConnectFailed(const QAndroidJniObject & socket, + const QAndroidJniObject &targetUuid); + void fallbackSocketConnectFailed(const QAndroidJniObject &socket, + const QAndroidJniObject &targetUuid); void inputThreadError(int errorCode); +signals: + void connectJavaSocket(); + void closeJavaSocket(); + #endif #if defined(QT_QNX_BLUETOOTH) || defined(QT_BLUEZ_BLUETOOTH) diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp index 2d4fa7be..d355b070 100644 --- a/src/bluetooth/qlowenergycontroller_bluez.cpp +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -79,6 +79,7 @@ #define ATT_OP_WRITE_COMMAND 0x52 //write characteristic without response //GATT command sizes in bytes +#define ERROR_RESPONSE_HEADER_SIZE 5 #define FIND_INFO_REQUEST_HEADER_SIZE 5 #define GRP_TYPE_REQ_HEADER_SIZE 7 #define READ_BY_TYPE_REQ_HEADER_SIZE 7 @@ -358,9 +359,20 @@ void QLowEnergyControllerPrivate::l2cpReadyRead() case ATT_OP_READ_REQUEST: case ATT_OP_FIND_INFORMATION_REQUEST: case ATT_OP_WRITE_REQUEST: - qCWarning(QT_BT_BLUEZ) << "Unexpected message type" << hex << command - << "will be ignored" ; + { + qCDebug(QT_BT_BLUEZ) << "Server request" << hex << command; + + //send not supported + QByteArray packet(ERROR_RESPONSE_HEADER_SIZE, Qt::Uninitialized); + packet[0] = ATT_OP_ERROR_RESPONSE; + packet[1] = command; + bt_put_unaligned(htobs(0), (quint16 *)(packet.data() + 2)); + packet[4] = ATT_ERROR_REQUEST_NOT_SUPPORTED; + + sendCommand(packet); + return; + } default: //only solicited replies finish pending requests requestPending = false; @@ -386,10 +398,12 @@ void QLowEnergyControllerPrivate::l2cpReadyRead() void QLowEnergyControllerPrivate::encryptionChangedEvent( const QBluetoothAddress &address, bool wasSuccess) { + if (!encryptionChangePending) // somebody else caused change event + return; + if (remoteDevice != address) return; - Q_ASSERT(encryptionChangePending); securityLevelValue = securityLevel(); // On success continue to process ATT command queue |