diff options
author | Alex Blasche <alexander.blasche@qt.io> | 2017-01-17 15:17:10 +0100 |
---|---|---|
committer | Alex Blasche <alexander.blasche@qt.io> | 2017-01-24 14:49:13 +0000 |
commit | 6b0595b64ea46554a8a63f026c15ab07ea804285 (patch) | |
tree | 97a469bd455cbe32ee7dfc23a79c05cb9b7e41dd | |
parent | a8604157818e21d7b70e2853258fc4569db770be (diff) |
Android: Implement QLEService::characteristicChanged() for peripheral mode
Emits the above signal when the remote client successfully updates
a characteristic.
Change-Id: I236b1f92b682028bc10be798192f46bffc981101
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
6 files changed, 87 insertions, 3 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 910143dd..b283a4b3 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 @@ -165,6 +165,7 @@ public class QtBluetoothLEServer { if (!preparedWrite) { // regular write if (offset == 0) { characteristic.setValue(value); + leServerCharacteristicChanged(qtObject, characteristic, value); } else { // This should not really happen as per Bluetooth spec Log.w(TAG, "onCharacteristicWriteRequest: !preparedWrite, offset " + offset + ", Not supported"); @@ -345,5 +346,7 @@ public class QtBluetoothLEServer { public native void leServerConnectionStateChange(long qtObject, int errorCode, int newState); public native void leServerAdvertisementError(long qtObject, int status); - + public native void leServerCharacteristicChanged(long qtObject, + BluetoothGattCharacteristic characteristic, + byte[] newValue); } diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp index e63854bd..7f08ea85 100644 --- a/src/bluetooth/android/jni_android.cpp +++ b/src/bluetooth/android/jni_android.cpp @@ -232,6 +232,8 @@ static JNINativeMethod methods_leServer[] = { (void *) LowEnergyNotificationHub::lowEnergy_connectionChange}, {"leServerAdvertisementError", "(JI)V", (void *) LowEnergyNotificationHub::lowEnergy_advertisementError}, + {"leServerCharacteristicChanged", "(JLandroid/bluetooth/BluetoothGattCharacteristic;[B)V", + (void *) LowEnergyNotificationHub::lowEnergy_serverCharacteristicChanged}, }; static JNINativeMethod methods_server[] = { diff --git a/src/bluetooth/android/lowenergynotificationhub.cpp b/src/bluetooth/android/lowenergynotificationhub.cpp index d6e0a4f1..b0d8b0a2 100644 --- a/src/bluetooth/android/lowenergynotificationhub.cpp +++ b/src/bluetooth/android/lowenergynotificationhub.cpp @@ -294,6 +294,28 @@ void LowEnergyNotificationHub::lowEnergy_characteristicChanged( Q_ARG(int, charHandle), Q_ARG(QByteArray, payload)); } +void LowEnergyNotificationHub::lowEnergy_serverCharacteristicChanged( + JNIEnv *env, jobject, jlong qtObject, jobject characteristic, jbyteArray newValue) +{ + lock.lockForRead(); + LowEnergyNotificationHub *hub = hubMap()->value(qtObject); + lock.unlock(); + if (!hub) + return; + + QByteArray payload; + if (newValue) { //empty Java byte array is 0x0 + jsize length = env->GetArrayLength(newValue); + payload.resize(length); + env->GetByteArrayRegion(newValue, 0, length, + reinterpret_cast<signed char*>(payload.data())); + } + + QMetaObject::invokeMethod(hub, "serverCharacteristicChanged", Qt::QueuedConnection, + Q_ARG(QAndroidJniObject, characteristic), + Q_ARG(QByteArray, payload)); +} + void LowEnergyNotificationHub::lowEnergy_serviceError( JNIEnv *, jobject, jlong qtObject, jint attributeHandle, int errorCode) { diff --git a/src/bluetooth/android/lowenergynotificationhub_p.h b/src/bluetooth/android/lowenergynotificationhub_p.h index 4efbd6de..b3962190 100644 --- a/src/bluetooth/android/lowenergynotificationhub_p.h +++ b/src/bluetooth/android/lowenergynotificationhub_p.h @@ -93,6 +93,8 @@ public: jint errorCode); static void lowEnergy_characteristicChanged(JNIEnv *, jobject, jlong qtObject, jint charHandle, jbyteArray data); + static void lowEnergy_serverCharacteristicChanged(JNIEnv *, jobject, jlong qtObject, + jobject characteristic, jbyteArray newValue); static void lowEnergy_serviceError(JNIEnv *, jobject, jlong qtObject, jint attributeHandle, int errorCode); static void lowEnergy_advertisementError(JNIEnv *, jobject, jlong qtObject, @@ -119,6 +121,7 @@ signals: void descriptorWritten(int descHandle, const QByteArray &data, QLowEnergyService::ServiceError errorCode); void characteristicChanged(int charHandle, const QByteArray &data); + void serverCharacteristicChanged(const QAndroidJniObject& characteristic, const QByteArray& newValue); void serviceError(int attributeHandle, QLowEnergyService::ServiceError errorCode); void advertisementError(int status); diff --git a/src/bluetooth/qlowenergycontroller_android.cpp b/src/bluetooth/qlowenergycontroller_android.cpp index 0d63faf1..9efd6045 100644 --- a/src/bluetooth/qlowenergycontroller_android.cpp +++ b/src/bluetooth/qlowenergycontroller_android.cpp @@ -52,6 +52,8 @@ QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID) +Q_DECLARE_METATYPE(QAndroidJniObject) + QLowEnergyControllerPrivate::QLowEnergyControllerPrivate() : QObject(), state(QLowEnergyController::UnconnectedState), @@ -83,6 +85,8 @@ void QLowEnergyControllerPrivate::init() return; } + qRegisterMetaType<QAndroidJniObject>(); + hub = new LowEnergyNotificationHub(remoteDevice, isPeripheral, this); // we only connect to the peripheral role specific signals // TODO add connections as they get added later on @@ -90,6 +94,8 @@ void QLowEnergyControllerPrivate::init() this, &QLowEnergyControllerPrivate::connectionUpdated); connect(hub, &LowEnergyNotificationHub::advertisementError, this, &QLowEnergyControllerPrivate::advertisementError); + connect(hub, &LowEnergyNotificationHub::serverCharacteristicChanged, + this, &QLowEnergyControllerPrivate::serverCharacteristicChanged); } else { if (version < 18) { qWarning() << "Qt Bluetooth LE Central/Client support not available" @@ -115,8 +121,6 @@ void QLowEnergyControllerPrivate::init() this, &QLowEnergyControllerPrivate::descriptorWritten); connect(hub, &LowEnergyNotificationHub::characteristicChanged, this, &QLowEnergyControllerPrivate::characteristicChanged); - connect(hub, &LowEnergyNotificationHub::serviceError, - this, &QLowEnergyControllerPrivate::serviceError); } } @@ -664,6 +668,55 @@ void QLowEnergyControllerPrivate::characteristicChanged( emit service->characteristicChanged(characteristic, data); } +void QLowEnergyControllerPrivate::serverCharacteristicChanged( + const QAndroidJniObject &characteristic, const QByteArray &newValue) +{ + qCDebug(QT_BT_ANDROID) << "Server characteristic change notification" << newValue.toHex(); + + // match characteristic to servicePrivate + QAndroidJniObject service = characteristic.callObjectMethod( + "getService", "()Landroid/bluetooth/BluetoothGattService;"); + if (!service.isValid()) + return; + + QAndroidJniObject jniUuid = service.callObjectMethod("getUuid", "()Ljava/util/UUID;"); + QBluetoothUuid serviceUuid(jniUuid.toString()); + if (serviceUuid.isNull()) + return; + + // TODO test if two service with same uuid exist + if (!localServices.contains(serviceUuid)) + return; + + auto servicePrivate = localServices.value(serviceUuid); + + jniUuid = characteristic.callObjectMethod("getUuid", "()Ljava/util/UUID;"); + QBluetoothUuid characteristicUuid(jniUuid.toString()); + if (characteristicUuid.isNull()) + return; + + QLowEnergyHandle foundHandle = 0; + const auto handleList = servicePrivate->characteristicList.keys(); + // TODO test if service contains two characteristics with same uuid + for (const auto handle : handleList) { + QLowEnergyServicePrivate::CharData& charData = servicePrivate->characteristicList[handle]; + if (charData.uuid != characteristicUuid) + continue; + + qCDebug(QT_BT_ANDROID) << "serverCharacteristicChanged: Matching characteristic" + << characteristicUuid << " on " << serviceUuid; + charData.value = newValue; + foundHandle = handle; + break; + } + + if (!foundHandle) + return; + + emit servicePrivate->characteristicChanged( + QLowEnergyCharacteristic(servicePrivate, foundHandle), newValue); +} + void QLowEnergyControllerPrivate::serviceError( int attributeHandle, QLowEnergyService::ServiceError errorCode) { diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h index bb12c933..4ac9f3f4 100644 --- a/src/bluetooth/qlowenergycontroller_p.h +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -441,6 +441,7 @@ private slots: void descriptorWritten(int descHandle, const QByteArray &data, QLowEnergyService::ServiceError errorCode); void characteristicChanged(int charHandle, const QByteArray &data); + void serverCharacteristicChanged(const QAndroidJniObject &jniChar, const QByteArray &newValue); void serviceError(int attributeHandle, QLowEnergyService::ServiceError errorCode); void advertisementError(int errorCode); |