summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@qt.io>2017-01-17 15:17:10 +0100
committerAlex Blasche <alexander.blasche@qt.io>2017-01-24 14:49:13 +0000
commit6b0595b64ea46554a8a63f026c15ab07ea804285 (patch)
tree97a469bd455cbe32ee7dfc23a79c05cb9b7e41dd /src
parenta8604157818e21d7b70e2853258fc4569db770be (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>
Diffstat (limited to 'src')
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java5
-rw-r--r--src/bluetooth/android/jni_android.cpp2
-rw-r--r--src/bluetooth/android/lowenergynotificationhub.cpp22
-rw-r--r--src/bluetooth/android/lowenergynotificationhub_p.h3
-rw-r--r--src/bluetooth/qlowenergycontroller_android.cpp57
-rw-r--r--src/bluetooth/qlowenergycontroller_p.h1
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);