From 9f4aa88b59ea11527cdec25f023eb52b62e885a5 Mon Sep 17 00:00:00 2001 From: Philip Peitsch Date: Sun, 14 Jul 2024 16:36:28 +1000 Subject: [PATCH 1/5] Use Android v33 writeCharacteristic (#985) --- src/android/Peripheral.java | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/android/Peripheral.java b/src/android/Peripheral.java index a69ff5f1..a9d8c81b 100644 --- a/src/android/Peripheral.java +++ b/src/android/Peripheral.java @@ -18,6 +18,7 @@ import android.app.Activity; import android.bluetooth.*; +import android.os.Build; import android.os.Handler; import android.util.Base64; import org.apache.cordova.CallbackContext; @@ -802,16 +803,25 @@ private void writeCharacteristic(CallbackContext callbackContext, UUID serviceUU boolean success = false; - characteristic.setValue(data); - characteristic.setWriteType(writeType); synchronized(this) { writeCallback = callbackContext; - - if (gatt.writeCharacteristic(characteristic)) { - success = true; + if (Build.VERSION.SDK_INT >= 33) { + int status = gatt.writeCharacteristic(characteristic, data, writeType); + success = status == BluetoothStatusCodes.SUCCESS; + if (!success) { + LOG.d(TAG,"BLE Write failed: %s", status); + writeCallback = null; + callbackContext.error("Write failed with status code " + status); + } } else { - writeCallback = null; - callbackContext.error("Write failed"); + characteristic.setValue(data); + characteristic.setWriteType(writeType); + success = gatt.writeCharacteristic(characteristic); + if (!success) { + LOG.d(TAG,"BLE Write failed"); + writeCallback = null; + callbackContext.error("Write failed"); + } } } From 01d189a82cbcbada79619c0cc56327c19e6e106b Mon Sep 17 00:00:00 2001 From: Philip Peitsch Date: Sun, 14 Jul 2024 16:59:54 +1000 Subject: [PATCH 2/5] Use Android v33 writeDescriptor --- src/android/Peripheral.java | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/android/Peripheral.java b/src/android/Peripheral.java index a9d8c81b..c322729b 100644 --- a/src/android/Peripheral.java +++ b/src/android/Peripheral.java @@ -588,17 +588,35 @@ private void registerNotifyCallback(CallbackContext callbackContext, UUID servic return; } + byte[] value; // prefer notify over indicate if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) { - descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE; } else if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) { - descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); + value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE; } else { LOG.w(TAG, "Characteristic %s does not have NOTIFY or INDICATE property set", characteristicUUID); + callbackContext.error("Set notification failed for " + characteristicUUID + "(missing NOTIFY or INDICATE property)"); + notificationCallbacks.remove(key); + commandCompleted(); + return; } - if (!gatt.writeDescriptor(descriptor)) { - callbackContext.error("Failed to set client characteristic notification for " + characteristicUUID); + if (Build.VERSION.SDK_INT >= 33) { + int status = gatt.writeDescriptor(descriptor, value); + success = status == BluetoothStatusCodes.SUCCESS; + if (!success) { + callbackContext.error("Failed to set client characteristic notification for " + characteristicUUID + " (status code " + status + ")"); + } + } else { + descriptor.setValue(value); + success = gatt.writeDescriptor(descriptor); + if (!success) { + callbackContext.error("Failed to set client characteristic notification for " + characteristicUUID); + } + } + + if (!success) { notificationCallbacks.remove(key); commandCompleted(); } @@ -636,8 +654,12 @@ private void removeNotifyCallback(CallbackContext callbackContext, UUID serviceU if (gatt.setCharacteristicNotification(characteristic, false)) { BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID); if (descriptor != null) { - descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); - gatt.writeDescriptor(descriptor); + if (Build.VERSION.SDK_INT >= 33) { + gatt.writeDescriptor(descriptor, BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); + } else { + descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); + gatt.writeDescriptor(descriptor); + } } callbackContext.success(); } else { From 7a13a1692a2ff84b769325fc2026124fbe99e5f1 Mon Sep 17 00:00:00 2001 From: Philip Peitsch Date: Sun, 14 Jul 2024 17:06:29 +1000 Subject: [PATCH 3/5] Use Android v33 getParcelableExtra call --- src/android/BLECentralPlugin.java | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/android/BLECentralPlugin.java b/src/android/BLECentralPlugin.java index 7a693e5c..25108f40 100644 --- a/src/android/BLECentralPlugin.java +++ b/src/android/BLECentralPlugin.java @@ -840,7 +840,14 @@ public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) { - BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + BluetoothDevice bluetoothDevice; + if (Build.VERSION.SDK_INT >= 33) { + bluetoothDevice = intent.getParcelableExtra( + BluetoothDevice.EXTRA_DEVICE, + android.bluetooth.BluetoothDevice.class); + } else { + bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + } int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR); if (type == BluetoothDevice.PAIRING_VARIANT_PIN) { @@ -1500,8 +1507,15 @@ private void addBondStateListener() { public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (ACTION_BOND_STATE_CHANGED.equals(action)) { - BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - Peripheral peripheral = peripherals.get(device.getAddress()); + BluetoothDevice device; + if (Build.VERSION.SDK_INT >= 33) { + device = intent.getParcelableExtra( + BluetoothDevice.EXTRA_DEVICE, + android.bluetooth.BluetoothDevice.class); + } else { + device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + } + Peripheral peripheral = device != null ? peripherals.get(device.getAddress()) : null; if (peripheral != null) { int bondState = intent.getIntExtra(EXTRA_BOND_STATE, BluetoothDevice.ERROR); From 4350caf7d2943cd1e14b50a8d7086aecb7c69a1d Mon Sep 17 00:00:00 2001 From: Philip Peitsch Date: Sun, 14 Jul 2024 17:19:49 +1000 Subject: [PATCH 4/5] Use Android v33 onCharacteristicChanged & onCharacteristicRead --- src/android/Peripheral.java | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/android/Peripheral.java b/src/android/Peripheral.java index c322729b..58be826c 100644 --- a/src/android/Peripheral.java +++ b/src/android/Peripheral.java @@ -15,6 +15,7 @@ package com.megster.cordova.ble.central; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.app.Activity; import android.bluetooth.*; @@ -33,6 +34,9 @@ import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicBoolean; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.annotation.RequiresPermission; /** @@ -432,9 +436,15 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState } + @TargetApi(32 /*S_V2*/) @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); + if (Build.VERSION.SDK_INT >= 33) { + // handled by new callback below + return; + } + LOG.d(TAG, "onCharacteristicChanged %s", characteristic); SequentialCallbackContext callback = notificationCallbacks.get(generateHashKey(characteristic)); @@ -444,9 +454,28 @@ public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteris } } + @RequiresApi(api = 33 /*TIRAMISU*/) + @Override + public void onCharacteristicChanged(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] data) { + super.onCharacteristicChanged(gatt, characteristic, data); + LOG.d(TAG, "onCharacteristicChanged (api:33) %s", characteristic); + + SequentialCallbackContext callback = notificationCallbacks.get(generateHashKey(characteristic)); + + if (callback != null) { + callback.sendSequentialResult(data); + } + } + + @TargetApi(32 /*S_V2*/) @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); + if (Build.VERSION.SDK_INT >= 33) { + // handled by new callback below + return; + } + LOG.d(TAG, "onCharacteristicRead %s", characteristic); synchronized(this) { @@ -464,6 +493,27 @@ public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic commandCompleted(); } + @RequiresApi(api = 33 /*TIRAMISU*/) + @Override + public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) { + super.onCharacteristicRead(gatt, characteristic, value, status); + LOG.d(TAG, "onCharacteristicRead (api:33) %s", characteristic); + + synchronized(this) { + if (readCallback != null) { + if (status == BluetoothGatt.GATT_SUCCESS) { + readCallback.success(value); + } else { + readCallback.error("Error reading " + characteristic.getUuid() + " status=" + status); + } + + readCallback = null; + } + } + + commandCompleted(); + } + @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); From 1cb040a9fb25c6d1069635aac8aa1380ab85c1ca Mon Sep 17 00:00:00 2001 From: Philip Peitsch Date: Sun, 14 Jul 2024 20:23:07 +1000 Subject: [PATCH 5/5] Tune build targets - add cordova 11 with cordova-android 11 - add capacitor 5 (latest is now 6) --- .github/workflows/capacitor.yaml | 4 ++ .github/workflows/cordova.yaml | 101 +++++++++++++++++++++++++++++++ .github/workflows/cordova.yml | 96 ----------------------------- 3 files changed, 105 insertions(+), 96 deletions(-) create mode 100644 .github/workflows/cordova.yaml delete mode 100644 .github/workflows/cordova.yml diff --git a/.github/workflows/capacitor.yaml b/.github/workflows/capacitor.yaml index 7a9b0a09..3661f940 100644 --- a/.github/workflows/capacitor.yaml +++ b/.github/workflows/capacitor.yaml @@ -14,11 +14,15 @@ jobs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: include: - jdk: 17 capacitor: latest node: 18.x + - jdk: 17 + capacitor: 5 + node: 18.x - jdk: 11 capacitor: 4 node: 14.x diff --git a/.github/workflows/cordova.yaml b/.github/workflows/cordova.yaml new file mode 100644 index 00000000..e0373e9a --- /dev/null +++ b/.github/workflows/cordova.yaml @@ -0,0 +1,101 @@ +name: Cordova + +on: + workflow_dispatch: + push: + branches: ['master'] + pull_request: + branches: ['master'] + +jobs: + cordova-android: + name: cordova@${{ matrix.cordova }} android@${{ matrix.platform }} + runs-on: ubuntu-${{ matrix.ubuntu }} + + strategy: + fail-fast: false + matrix: + include: + - jdk: 17 + cordova: latest + platform: latest + node: 18.x + ubuntu: 22.04 + android-cmdline-tools-version: 10406996 + - jdk: 16 + cordova: 12 + platform: 12 + node: 18.x + ubuntu: 22.04 + android-cmdline-tools-version: 9862592 + - jdk: 11 + cordova: 11 + platform: 11 + node: 14.x + ubuntu: 20.04 + android-cmdline-tools-version: 9862592 + - jdk: 11 + cordova: 11 + platform: 10 + node: 14.x + ubuntu: 20.04 + android-cmdline-tools-version: 9862592 + - jdk: 8 + cordova: 10 + platform: 10 + node: 14.x + ubuntu: 20.04 + android-cmdline-tools-version: 8512546 + + steps: + - uses: actions/checkout@v3 + - name: Setup JDK ${{ matrix.jdk }} + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.jdk }} + distribution: 'temurin' + - name: Setup Node.js ${{ matrix.node }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + with: + cmdline-tools-version: ${{ matrix.android-cmdline-tools-version }} + - name: Build test app + run: | + sdkmanager "build-tools;30.0.3" + sdkmanager "build-tools;34.0.0" + npm install -g cordova@${{ matrix.cordova }} + cordova create temp + cd temp + cordova platform add android@${{ matrix.platform }} + cordova plugin add .. --noregistry --force --link + cordova build android + + cordova-ios: + name: cordova@${{ matrix.cordova }} ios@${{ matrix.platform }} + + runs-on: macos-latest + + strategy: + matrix: + include: + - cordova: latest + platform: latest + node: 18.x + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + - name: Build test app + run: | + npm install -g cordova@${{ matrix.cordova }} + cordova create temp + cd temp + cordova platform add ios@${{ matrix.platform }} + cordova plugin add .. --noregistry --force --link + cordova build ios diff --git a/.github/workflows/cordova.yml b/.github/workflows/cordova.yml deleted file mode 100644 index d5fe86b0..00000000 --- a/.github/workflows/cordova.yml +++ /dev/null @@ -1,96 +0,0 @@ -name: Cordova - -on: - workflow_dispatch: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -jobs: - cordova-android: - name: android@${{ matrix.platform }} cordova@${{ matrix.cordova }} - - runs-on: ubuntu-${{ matrix.ubuntu }} - - strategy: - fail-fast: false - matrix: - include: - - jdk: 17 - cordova: latest - platform: latest - node: 18.x - ubuntu: 22.04 - android-cmdline-tools-version: 10406996 - - jdk: 16 - cordova: 12 - platform: 12 - node: 18.x - ubuntu: 22.04 - android-cmdline-tools-version: 9862592 - - jdk: 11 - cordova: 11 - platform: 10 - node: 14.x - ubuntu: 20.04 - android-cmdline-tools-version: 9862592 - - jdk: 8 - cordova: 10 - platform: 10 - node: 14.x - ubuntu: 20.04 - android-cmdline-tools-version: 8512546 - - steps: - - uses: actions/checkout@v3 - - name: Setup JDK ${{ matrix.jdk }} - uses: actions/setup-java@v3 - with: - java-version: ${{ matrix.jdk }} - distribution: 'temurin' - - name: Setup Node.js ${{ matrix.node }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node }} - - name: Setup Android SDK - uses: android-actions/setup-android@v3 - with: - cmdline-tools-version: ${{ matrix.android-cmdline-tools-version }} - - name: Build test app - run: | - sdkmanager "build-tools;30.0.3" - sdkmanager "build-tools;34.0.0" - npm install -g cordova@${{ matrix.cordova }} - cordova create temp - cd temp - cordova platform add android@${{ matrix.platform }} - cordova plugin add .. --noregistry --force --link - cordova build android - - cordova-ios: - name: ios@${{ matrix.platform }} cordova@${{ matrix.cordova }} - - runs-on: macos-latest - - strategy: - matrix: - include: - - cordova: latest - platform: latest - node: 18.x - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node }} - - name: Build test app - run: | - npm install -g cordova@${{ matrix.cordova }} - cordova create temp - cd temp - cordova platform add ios@${{ matrix.platform }} - cordova plugin add .. --noregistry --force --link - cordova build ios