From 46a776eb70d7b3e40bb80cb4f4314d3462801b62 Mon Sep 17 00:00:00 2001
From: Alex Blasche <alexander.blasche@qt.io>
Date: Mon, 2 Jan 2017 15:05:59 +0100
Subject: [PATCH] Setup descriptor permissions for Android peripheral

Change-Id: Id40033b0745a720466a8466ad3c82ad804cadd9c
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
---
 .../qlowenergycontroller_android.cpp          | 91 +++++++++++++++++--
 1 file changed, 85 insertions(+), 6 deletions(-)

diff --git a/src/bluetooth/qlowenergycontroller_android.cpp b/src/bluetooth/qlowenergycontroller_android.cpp
index 5c0bee7b..613c2bed 100644
--- a/src/bluetooth/qlowenergycontroller_android.cpp
+++ b/src/bluetooth/qlowenergycontroller_android.cpp
@@ -872,6 +872,58 @@ static int setupCharPermissions(const QLowEnergyCharacteristicData &charData)
     return permission;
 }
 
+/*
+ * Returns the Java desc permissions based on the given descriptor data.
+ */
+static int setupDescPermissions(const QLowEnergyDescriptorData &descData)
+{
+    int permissions = 0;
+
+    if (descData.isReadable()) {
+        if (int(descData.readConstraints()) == 0 // empty is equivalent to simple read
+            || (descData.readConstraints() & QBluetooth::AttAuthorizationRequired)) {
+            permissions |= QAndroidJniObject::getStaticField<jint>(
+                                "android/bluetooth/BluetoothGattDescriptor",
+                                "PERMISSION_READ");
+        }
+
+        if (descData.readConstraints() & QBluetooth::AttAuthenticationRequired) {
+            permissions |= QAndroidJniObject::getStaticField<jint>(
+                                "android/bluetooth/BluetoothGattDescriptor",
+                                "PERMISSION_READ_ENCRYPTED");
+        }
+
+        if (descData.readConstraints() & QBluetooth::AttEncryptionRequired) {
+            permissions |= QAndroidJniObject::getStaticField<jint>(
+                                                "android/bluetooth/BluetoothGattDescriptor",
+                                                "PERMISSION_READ_ENCRYPTED_MITM");
+        }
+    }
+
+    if (descData.isWritable()) {
+        if (((int)descData.readConstraints()) == 0 // empty is equivalent to simple read
+            || (descData.readConstraints() & QBluetooth::AttAuthorizationRequired)) {
+            permissions |= QAndroidJniObject::getStaticField<jint>(
+                                "android/bluetooth/BluetoothGattDescriptor",
+                                "PERMISSION_WRITE");
+        }
+
+        if (descData.readConstraints() & QBluetooth::AttAuthenticationRequired) {
+            permissions |= QAndroidJniObject::getStaticField<jint>(
+                                "android/bluetooth/BluetoothGattDescriptor",
+                                "PERMISSION_WRITE_ENCRYPTED");
+        }
+
+        if (descData.readConstraints() & QBluetooth::AttEncryptionRequired) {
+            permissions |= QAndroidJniObject::getStaticField<jint>(
+                                                "android/bluetooth/BluetoothGattDescriptor",
+                                                "PERMISSION_WRITE_ENCRYPTED_MITM");
+        }
+    }
+
+    return permissions;
+}
+
 void QLowEnergyControllerPrivate::addToGenericAttributeList(const QLowEnergyServiceData &serviceData,
                                                             QLowEnergyHandle startHandle)
 {
@@ -905,7 +957,6 @@ void QLowEnergyControllerPrivate::addToGenericAttributeList(const QLowEnergyServ
     // add characteristics
     const QList<QLowEnergyCharacteristicData> serviceCharsData = serviceData.characteristics();
     for (const auto &charData: serviceCharsData) {
-        //TODO add chars and their descriptors
         QAndroidJniObject javaChar = QAndroidJniObject("android/bluetooth/BluetoothGattCharacteristic",
                                                        "(Ljava/util/UUID;II)V",
                                                        javaUuidfromQtUuid(charData.uuid()).object(),
@@ -917,18 +968,46 @@ void QLowEnergyControllerPrivate::addToGenericAttributeList(const QLowEnergyServ
         env->SetByteArrayRegion(jb, 0, charData.value().size(), (jbyte*)charData.value().data());
         jboolean success = javaChar.callMethod<jboolean>("setValue", "([B)Z", jb);
         if (!success)
-            qWarning() << "Cannot setup initial characteristic value for " << charData.uuid();
+            qCWarning(QT_BT_ANDROID) << "Cannot setup initial characteristic value for " << charData.uuid();
 
         env->DeleteLocalRef(jb);
 
-        // TODO set all descriptors
+        const QList<QLowEnergyDescriptorData> descriptorList = charData.descriptors();
+        for (const auto &descData: descriptorList) {
+            QAndroidJniObject javaDesc = QAndroidJniObject("android/bluetooth/BluetoothGattDescriptor",
+                                                           "(Ljava/util/UUID;I)V",
+                                                           javaUuidfromQtUuid(descData.uuid()).object(),
+                                                           setupDescPermissions(descData));
+
+            jb = env->NewByteArray(descData.value().size());
+            env->SetByteArrayRegion(jb, 0, descData.value().size(), (jbyte*)descData.value().data());
+            success = javaDesc.callMethod<jboolean>("setValue", "([B)Z", jb);
+            if (!success) {
+                qCWarning(QT_BT_ANDROID) << "Cannot setup initial descriptor value for "
+                                         << descData.uuid() << "(char" << charData.uuid()
+                                         << "on service " << service->uuid << ")";
+            }
+
+            env->DeleteLocalRef(jb);
+
+
+            success = javaChar.callMethod<jboolean>("addDescriptor",
+                                                    "(Landroid/bluetooth/BluetoothGattDescriptor;)Z",
+                                                    javaDesc.object());
+            if (!success) {
+                qCWarning(QT_BT_ANDROID) << "Cannot add descriptor" << descData.uuid()
+                                         << "to service" << service->uuid << "(char:"
+                                         << charData.uuid() << ")";
+            }
+        }
 
         success = service->androidService.callMethod<jboolean>(
                             "addCharacteristic",
                             "(Landroid/bluetooth/BluetoothGattCharacteristic;)Z", javaChar.object());
-        if (!success)
-            qWarning() << "Cannot add characteristic" << charData.uuid() << "to service"
-                       << service->uuid;
+        if (!success) {
+            qCWarning(QT_BT_ANDROID) << "Cannot add characteristic" << charData.uuid()
+                                     << "to service" << service->uuid;
+        }
     }
 
     hub->javaObject().callMethod<void>("addService",
-- 
GitLab