From 9798e0f68b5c3c2416ebff36545c6f1d0665b31c Mon Sep 17 00:00:00 2001 From: pwespi Date: Sun, 1 Oct 2023 09:34:15 +0200 Subject: [PATCH] fix(android): use new methods from API level 33 --- .../plugins/bluetoothle/BluetoothLe.kt | 3 +- .../community/plugins/bluetoothle/Device.kt | 140 +++++++++++++++--- package.json | 2 +- 3 files changed, 120 insertions(+), 25 deletions(-) diff --git a/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/BluetoothLe.kt b/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/BluetoothLe.kt index c504361..a088da6 100644 --- a/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/BluetoothLe.kt +++ b/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/BluetoothLe.kt @@ -98,8 +98,7 @@ class BluetoothLe : Plugin() { @PluginMethod fun initialize(call: PluginCall) { - // Build.VERSION_CODES.S = 31 - if (Build.VERSION.SDK_INT >= 31) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val neverForLocation = call.getBoolean("androidNeverForLocation", false) as Boolean aliases = if (neverForLocation) { arrayOf( diff --git a/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/Device.kt b/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/Device.kt index a8039dd..5ee4d97 100644 --- a/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/Device.kt +++ b/android/src/main/java/com/capacitorjs/community/plugins/bluetoothle/Device.kt @@ -1,6 +1,7 @@ package com.capacitorjs.community.plugins.bluetoothle import android.annotation.SuppressLint +import android.annotation.TargetApi import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothGatt @@ -9,6 +10,7 @@ import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothGattDescriptor import android.bluetooth.BluetoothGattService import android.bluetooth.BluetoothProfile +import android.bluetooth.BluetoothStatusCodes import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -16,6 +18,7 @@ import android.content.IntentFilter import android.os.Build import android.os.Handler import android.os.Looper +import androidx.annotation.RequiresApi import com.getcapacitor.Logger import java.util.UUID import java.util.concurrent.ConcurrentLinkedQueue @@ -125,9 +128,15 @@ class Device( } } + @TargetApi(Build.VERSION_CODES.S_V2) override fun onCharacteristicRead( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // handled by new callback below + return + } + Logger.verbose(TAG, "Using deprecated onCharacteristicRead.") super.onCharacteristicRead(gatt, characteristic, status) val key = "read|${characteristic.service.uuid}|${characteristic.uuid}" if (status == BluetoothGatt.GATT_SUCCESS) { @@ -143,6 +152,24 @@ class Device( } } + @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) + override fun onCharacteristicRead( + gatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + data: ByteArray, + status: Int + ) { + Logger.verbose(TAG, "Using onCharacteristicRead from API level 33.") + super.onCharacteristicRead(gatt, characteristic, data, status) + val key = "read|${characteristic.service.uuid}|${characteristic.uuid}" + if (status == BluetoothGatt.GATT_SUCCESS) { + val value = bytesToString(data) + resolve(key, value) + } else { + reject(key, "Reading characteristic failed.") + } + } + override fun onCharacteristicWrite( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int ) { @@ -156,9 +183,15 @@ class Device( } + @TargetApi(Build.VERSION_CODES.S_V2) override fun onCharacteristicChanged( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // handled by new callback below + return + } + Logger.verbose(TAG, "Using deprecated onCharacteristicChanged.") super.onCharacteristicChanged(gatt, characteristic) val notifyKey = "notification|${characteristic.service.uuid}|${characteristic.uuid}" val data = characteristic.value @@ -168,9 +201,26 @@ class Device( } } + @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) + override fun onCharacteristicChanged( + gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, data: ByteArray + ) { + Logger.verbose(TAG, "Using onCharacteristicChanged from API level 33.") + super.onCharacteristicChanged(gatt, characteristic, data) + val notifyKey = "notification|${characteristic.service.uuid}|${characteristic.uuid}" + val value = bytesToString(data) + callbackMap[notifyKey]?.invoke(CallbackResponse(true, value)) + } + + @TargetApi(Build.VERSION_CODES.S_V2) override fun onDescriptorRead( gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // handled by new callback below + return + } + Logger.verbose(TAG, "Using deprecated onDescriptorRead.") super.onDescriptorRead(gatt, descriptor, status) val key = "readDescriptor|${descriptor.characteristic.service.uuid}|${descriptor.characteristic.uuid}|${descriptor.uuid}" @@ -187,6 +237,22 @@ class Device( } } + @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) + override fun onDescriptorRead( + gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int, data: ByteArray + ) { + Logger.verbose(TAG, "Using onDescriptorRead from API level 33.") + super.onDescriptorRead(gatt, descriptor, status, data) + val key = + "readDescriptor|${descriptor.characteristic.service.uuid}|${descriptor.characteristic.uuid}|${descriptor.uuid}" + if (status == BluetoothGatt.GATT_SUCCESS) { + val value = bytesToString(data) + resolve(key, value) + } else { + reject(key, "Reading descriptor failed.") + } + } + override fun onDescriptorWrite( gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int ) { @@ -290,7 +356,14 @@ class Device( if (action == BluetoothDevice.ACTION_BOND_STATE_CHANGED) { val key = "createBond" val updatedDevice = - intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + intent.getParcelableExtra( + BluetoothDevice.EXTRA_DEVICE, + BluetoothDevice::class.java + ) + } else { + intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) + } // BroadcastReceiver receives bond state updates from all devices, need to filter by device if (device.address == updatedDevice?.address) { val bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1) @@ -419,18 +492,20 @@ class Device( } val bytes = stringToBytes(value) - val result = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val statusCode = bluetoothGatt?.writeCharacteristic(characteristic, bytes, writeType) - statusCode == 0 + if (statusCode != BluetoothStatusCodes.SUCCESS) { + reject(key, "Writing characteristic failed with status code $statusCode.") + return + } } else { characteristic.value = bytes characteristic.writeType = writeType - bluetoothGatt?.writeCharacteristic(characteristic) - } - - if (result != true) { - reject(key, "Writing characteristic failed.") - return + val result = bluetoothGatt?.writeCharacteristic(characteristic) + if (result != true) { + reject(key, "Writing characteristic failed.") + return + } } setTimeout(key, "Write timeout.", timeout) } @@ -467,20 +542,32 @@ class Device( return } - if (enable) { + val value = if (enable) { if ((characteristic.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) { - descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE } else if ((characteristic.properties and BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) { - descriptor.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE + BluetoothGattDescriptor.ENABLE_INDICATION_VALUE + } else { + BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE } } else { - descriptor.value = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE + BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE } - val resultDesc = bluetoothGatt?.writeDescriptor(descriptor) - if (resultDesc != true) { - reject(key, "Setting notification failed.") - return + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val statusCode = bluetoothGatt?.writeDescriptor(descriptor, value) + if (statusCode != BluetoothStatusCodes.SUCCESS) { + reject(key, "Setting notification failed with status code $statusCode.") + return + } + } else { + descriptor.value = value + val resultDesc = bluetoothGatt?.writeDescriptor(descriptor) + if (resultDesc != true) { + reject(key, "Setting notification failed.") + return + } + } // wait for onDescriptorWrite } @@ -535,11 +622,20 @@ class Device( return } val bytes = stringToBytes(value) - descriptor.value = bytes - val result = bluetoothGatt?.writeDescriptor(descriptor) - if (result != true) { - reject(key, "Writing characteristic failed.") - return + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val statusCode = bluetoothGatt?.writeDescriptor(descriptor, bytes) + if (statusCode != BluetoothStatusCodes.SUCCESS) { + reject(key, "Writing descriptor failed with status code $statusCode.") + return + } + } else { + descriptor.value = bytes + val result = bluetoothGatt?.writeDescriptor(descriptor) + if (result != true) { + reject(key, "Writing descriptor failed.") + return + } } setTimeout(key, "Write timeout.", timeout) } diff --git a/package.json b/package.json index 9057d75..3669185 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "verify:ios": "set -o pipefail && cd ios && pod install && xcodebuild clean build test -workspace Plugin.xcworkspace -scheme Plugin -destination \"platform=iOS Simulator,name=iPhone 14\" | xcpretty && cd ..", "verify:android": "cd android && ./gradlew clean build test && cd ..", "verify:web": "npm run test:coverage && npm run build", - "lint": "npm run eslint && npm run prettier -- --check && npm run lint:ios && npm run lint:android", + "lint": "npm run eslint && npm run prettier -- --check && npm run lint:ios", "lint:ios": "npm run swiftlint -- lint ios", "lint:android": "cd android && ./gradlew clean lint && cd ..", "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- lint --fix --format ios",