diff options
author | Juha Vuolle <juha.vuolle@qt.io> | 2023-01-13 12:08:05 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-02-04 13:48:53 +0000 |
commit | 8363df31ff4712f97874e9c0ea2a0aeacda47ca2 (patch) | |
tree | 6cc050b0436487c00caa730034a4db4f0d2f72bd | |
parent | 163ce3e87f1566ec820637724dfbbc12d8f90096 (diff) | |
download | qtconnectivity-8363df31ff4712f97874e9c0ea2a0aeacda47ca2.tar.gz |
Replace deprecated BT LE methods on Android API 33: descriptors
The overarching theme for these API deprecations is to
improve memory safety. This patch replaces the descriptor
related APIs.
Fixes: QTBUG-107180
Change-Id: Ief098d67d2601e06a2f29fa38d9b481bbda605f9
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
(cherry picked from commit 8ae30c552ce7ae1e0ee4c6a472666a1e8ee2790a)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
6 files changed, 77 insertions, 16 deletions
diff --git a/src/android/bluetooth/CMakeLists.txt b/src/android/bluetooth/CMakeLists.txt index 7dd0c257..f8692576 100644 --- a/src/android/bluetooth/CMakeLists.txt +++ b/src/android/bluetooth/CMakeLists.txt @@ -8,6 +8,7 @@ set(java_sources src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java src/org/qtproject/qt/android/bluetooth/QtBluetoothSocketServer.java src/org/qtproject/qt/android/bluetooth/QtBluetoothGattCharacteristic.java + src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java ) qt_internal_add_jar(Qt${QtConnectivity_VERSION_MAJOR}AndroidBluetooth diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java new file mode 100644 index 00000000..10194ea4 --- /dev/null +++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java @@ -0,0 +1,39 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +package org.qtproject.qt.android.bluetooth; + +import android.bluetooth.BluetoothGattDescriptor; +import android.os.Build; + +import java.util.UUID; + +public class QtBluetoothGattDescriptor extends BluetoothGattDescriptor { + public QtBluetoothGattDescriptor(UUID uuid, int permissions) { + super(uuid, permissions); + } + // Starting from API 33 Android Bluetooth deprecates descriptor local value caching by + // deprecating the getValue() and setValue() accessors. For peripheral role we store the value + // locally in the descriptor as a convenience - looking up the value on the C++ side would + // be somewhat complicated. This should be safe as all accesses to this class are synchronized. + // For clarity: For API levels below 33 we still need to use the setValue() of the base class + // because Android internally uses getValue() with APIs below 33. + public boolean setLocalValue(byte[] value) { + if (Build.VERSION.SDK_INT >= 33) { + m_localValue = value; + return true; + } else { + return setValue(value); + } + } + + public byte[] getLocalValue() + { + if (Build.VERSION.SDK_INT >= 33) + return m_localValue; + else + return getValue(); + } + + private byte[] m_localValue = null; +} diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java index 57accf3b..08527385 100644 --- a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java +++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java @@ -470,7 +470,7 @@ public class QtBluetoothLE { private synchronized void handleOnDescriptorRead(android.bluetooth.BluetoothGatt gatt, android.bluetooth.BluetoothGattDescriptor descriptor, - int status) + int status, byte[] newValue) { int foundHandle = handleForDescriptor(descriptor); if (foundHandle == -1 || foundHandle >= entries.size() ) { @@ -504,7 +504,7 @@ public class QtBluetoothLE { leDescriptorRead(qtObject, descriptor.getCharacteristic().getService().getUuid().toString(), descriptor.getCharacteristic().getUuid().toString(), foundHandle + 1, - descriptor.getUuid().toString(), descriptor.getValue()); + descriptor.getUuid().toString(), newValue); } else { if (isServiceDiscoveryRun) { // Cannot read but still advertise the fact that we found a descriptor @@ -516,7 +516,7 @@ public class QtBluetoothLE { leDescriptorRead(qtObject, descriptor.getCharacteristic().getService().getUuid().toString(), descriptor.getCharacteristic().getUuid().toString(), foundHandle + 1, - descriptor.getUuid().toString(), descriptor.getValue()); + descriptor.getUuid().toString(), newValue); } else { // This must be in sync with QLowEnergyService::DescriptorReadError final int descriptorReadError = 6; @@ -539,7 +539,7 @@ public class QtBluetoothLE { * up here. */ if (descriptor.getUuid().compareTo(clientCharacteristicUuid) == 0) { - byte[] bytearray = descriptor.getValue(); + byte[] bytearray = newValue; final int value = (bytearray != null && bytearray.length > 0) ? bytearray[0] : 0; // notification or indication bit set? if ((value & 0x03) > 0) { @@ -585,9 +585,10 @@ public class QtBluetoothLE { errorCode = 3; break; // DescriptorWriteError } + byte[] value = pendingJob.newValue; pendingJob = null; - leDescriptorWritten(qtObject, handle+1, descriptor.getValue(), errorCode); + leDescriptorWritten(qtObject, handle+1, value, errorCode); performNextIO(); } @@ -700,12 +701,24 @@ public class QtBluetoothLE { handleOnCharacteristicChanged(gatt, characteristic, value); } + // API < 33 public void onDescriptorRead(android.bluetooth.BluetoothGatt gatt, android.bluetooth.BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); - handleOnDescriptorRead(gatt, descriptor, status); + handleOnDescriptorRead(gatt, descriptor, status, descriptor.getValue()); + } + + // API >= 33 + public void onDescriptorRead(android.bluetooth.BluetoothGatt gatt, + android.bluetooth.BluetoothGattDescriptor descriptor, + int status, + byte[] value) + { + // Note: here we don't call the super implementation as it calls the old "< API 33" + // callback, and the callback would be handled twice + handleOnDescriptorRead(gatt, descriptor, status, value); } public void onDescriptorWrite(android.bluetooth.BluetoothGatt gatt, @@ -1565,7 +1578,7 @@ public class QtBluetoothLE { entry.descriptor.getCharacteristic().getService().getUuid().toString(), entry.descriptor.getCharacteristic().getUuid().toString(), handle + 1, entry.descriptor.getUuid().toString(), - entry.descriptor.getValue()); + null); break; case CharacteristicValue: // for more details see scheduleServiceDetailDiscovery(int, boolean) @@ -1676,9 +1689,15 @@ public class QtBluetoothLE { Log.d(TAG, "Enable notifications: " + enableNotifications); } + if (Build.VERSION.SDK_INT >= 33) { + int writeResult = mBluetoothGatt.writeDescriptor( + nextJob.entry.descriptor, nextJob.newValue); + return (writeResult != BluetoothStatusCodes.SUCCESS); + } result = nextJob.entry.descriptor.setValue(nextJob.newValue); if (!result || !mBluetoothGatt.writeDescriptor(nextJob.entry.descriptor)) return true; + break; case Service: case CharacteristicValue: diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java index 6d4a1fa7..94601403 100644 --- a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java +++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java @@ -468,13 +468,14 @@ public class QtBluetoothLEServer { return; } - byte[] dataArray = descriptor.getValue(); + byte[] dataArray = ((QtBluetoothGattDescriptor)descriptor).getLocalValue(); + try { if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) { dataArray = clientCharacteristicManager.valueFor( descriptor.getCharacteristic(), device); if (dataArray == null) - dataArray = descriptor.getValue(); + dataArray = ((QtBluetoothGattDescriptor)descriptor).getLocalValue(); } dataArray = Arrays.copyOfRange(dataArray, offset, dataArray.length); @@ -521,8 +522,7 @@ public class QtBluetoothLEServer { descriptor.getCharacteristic(), device, value); } - - descriptor.setValue(value); + ((QtBluetoothGattDescriptor)descriptor).setLocalValue(value); leServerDescriptorWritten(qtObject, descriptor, value); } else { // This should not really happen as per Bluetooth spec @@ -564,7 +564,7 @@ public class QtBluetoothLEServer { // The target can be a descriptor or a characteristic byte[] currentValue = (entry.target instanceof BluetoothGattCharacteristic) ? ((QtBluetoothGattCharacteristic)entry.target).getLocalValue() - : ((BluetoothGattDescriptor)entry.target).getValue(); + : ((QtBluetoothGattDescriptor)entry.target).getLocalValue(); // Iterate writes and apply them to the currentValue in received order for (Pair<byte[], Integer> write : entry.writes) { @@ -615,7 +615,7 @@ public class QtBluetoothLEServer { leServerCharacteristicChanged( qtObject, (BluetoothGattCharacteristic)entry.target, newValue); } else { - ((BluetoothGattDescriptor)entry.target).setValue(newValue); + ((QtBluetoothGattDescriptor)entry.target).setLocalValue(newValue); leServerDescriptorWritten( qtObject, (BluetoothGattDescriptor)entry.target, newValue); } @@ -930,7 +930,7 @@ public class QtBluetoothLEServer { // to interpret the server's call as a change of the default value. synchronized (this) // a value update might be in progress { - foundDesc.setValue(newValue); + ((QtBluetoothGattDescriptor)foundDesc).setLocalValue(newValue); } return true; diff --git a/src/bluetooth/android/jni_android_p.h b/src/bluetooth/android/jni_android_p.h index c51b14e7..bb3fd341 100644 --- a/src/bluetooth/android/jni_android_p.h +++ b/src/bluetooth/android/jni_android_p.h @@ -27,6 +27,8 @@ Q_DECLARE_JNI_CLASS(QtBtBroadcastReceiver, "org/qtproject/qt/android/bluetooth/QtBluetoothBroadcastReceiver"); Q_DECLARE_JNI_CLASS(QtBtGattCharacteristic, "org/qtproject/qt/android/bluetooth/QtBluetoothGattCharacteristic"); +Q_DECLARE_JNI_CLASS(QtBtGattDescriptor, + "org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor"); Q_DECLARE_JNI_CLASS(QtBtInputStreamThread, "org/qtproject/qt/android/bluetooth/QtBluetoothInputStreamThread") Q_DECLARE_JNI_CLASS(QtBtSocketServer, "org/qtproject/qt/android/bluetooth/QtBluetoothSocketServer") diff --git a/src/bluetooth/qlowenergycontroller_android.cpp b/src/bluetooth/qlowenergycontroller_android.cpp index 0350b163..d01833e8 100644 --- a/src/bluetooth/qlowenergycontroller_android.cpp +++ b/src/bluetooth/qlowenergycontroller_android.cpp @@ -1227,13 +1227,13 @@ void QLowEnergyControllerPrivateAndroid::addToGenericAttributeList(const QLowEne const QList<QLowEnergyDescriptorData> descriptorList = charData.descriptors(); for (const auto &descData: descriptorList) { - QJniObject javaDesc = QJniObject::construct<QtJniTypes::BluetoothGattDescriptor>( + QJniObject javaDesc = QJniObject::construct<QtJniTypes::QtBtGattDescriptor>( javaUuidfromQtUuid(descData.uuid()).object<QtJniTypes::UUID>(), setupDescPermissions(descData)); jb = env->NewByteArray(descData.value().size()); env->SetByteArrayRegion(jb, 0, descData.value().size(), (jbyte*)descData.value().data()); - success = javaDesc.callMethod<jboolean>("setValue", jb); + success = javaDesc.callMethod<jboolean>("setLocalValue", jb); if (!success) { qCWarning(QT_BT_ANDROID) << "Cannot setup initial descriptor value for " << descData.uuid() << "(char" << charData.uuid() |