From 792538105335fe9779c15d624d330efaf399a2d2 Mon Sep 17 00:00:00 2001 From: Philip Peitsch Date: Sat, 8 Jun 2024 09:34:28 +1000 Subject: [PATCH] Suppress permission-related lint warnings on Android --- README.md | 2 +- src/android/BLECentralPlugin.java | 156 +++++++++++++++++------------- src/android/BLECommand.java | 25 +---- src/android/L2CAPContext.java | 4 +- src/android/Peripheral.java | 50 ++++++---- 5 files changed, 129 insertions(+), 108 deletions(-) diff --git a/README.md b/README.md index 662fd083..c6f26da0 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ See the [examples](https://github.com/don/cordova-plugin-ble-central/tree/master ## Supported Platforms - iOS -- Android (likely supports 6+, but 8.1 or greater recommended) +- Android 6+ (8.1 or greater recommended) - Browser (where navigator.bluetooth is supported) # Installing diff --git a/src/android/BLECentralPlugin.java b/src/android/BLECentralPlugin.java index ec755343..bd039cb7 100644 --- a/src/android/BLECentralPlugin.java +++ b/src/android/BLECentralPlugin.java @@ -15,6 +15,7 @@ package com.megster.cordova.ble.central; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -170,6 +171,7 @@ protected void pluginInitialize() { } } + @SuppressLint("MissingPermission") @Override public void onDestroy() { removeStateListener(); @@ -180,6 +182,7 @@ public void onDestroy() { } } + @SuppressLint("MissingPermission") @Override public void onReset() { removeStateListener(); @@ -196,7 +199,7 @@ public boolean execute(String action, CordovaArgs args, CallbackContext callback if (bluetoothAdapter == null) { Activity activity = cordova.getActivity(); - boolean hardwareSupportsBLE = activity.getApplicationContext() + @SuppressLint("ObsoleteSdkInt") boolean hardwareSupportsBLE = activity.getApplicationContext() .getPackageManager() .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) && Build.VERSION.SDK_INT >= 18; @@ -434,79 +437,86 @@ public boolean execute(String action, CordovaArgs args, CallbackContext callback validAction = false; break; } - - switch (options.optString("callbackType", "")) { - case "": - break; - case "all": - scanSettings.setCallbackType( ScanSettings.CALLBACK_TYPE_ALL_MATCHES ); - break; - case "first": - scanSettings.setCallbackType( ScanSettings.CALLBACK_TYPE_FIRST_MATCH ); - break; - case "lost": - scanSettings.setCallbackType( ScanSettings.CALLBACK_TYPE_MATCH_LOST ); - break; - default: - callbackContext.error("callbackType must be one of: all | first | lost"); - validAction = false; - break; + if (Build.VERSION.SDK_INT >= 23) { + switch (options.optString("callbackType", "")) { + case "": + break; + case "all": + scanSettings.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES); + break; + case "first": + scanSettings.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH); + break; + case "lost": + scanSettings.setCallbackType(ScanSettings.CALLBACK_TYPE_MATCH_LOST); + break; + default: + callbackContext.error("callbackType must be one of: all | first | lost"); + validAction = false; + break; + } } - switch (options.optString("matchMode", "")) { - case "": - break; - case "aggressive": - scanSettings.setMatchMode( ScanSettings.MATCH_MODE_AGGRESSIVE ); - break; - case "sticky": - scanSettings.setMatchMode( ScanSettings.MATCH_MODE_STICKY ); - break; - default: - callbackContext.error("matchMode must be one of: aggressive | sticky"); - validAction = false; - break; + if (Build.VERSION.SDK_INT >= 23) { + switch (options.optString("matchMode", "")) { + case "": + break; + case "aggressive": + scanSettings.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE); + break; + case "sticky": + scanSettings.setMatchMode(ScanSettings.MATCH_MODE_STICKY); + break; + default: + callbackContext.error("matchMode must be one of: aggressive | sticky"); + validAction = false; + break; + } } - switch (options.optString("numOfMatches", "")) { - case "": - break; - case "one": - scanSettings.setNumOfMatches( ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT ); - break; - case "few": - scanSettings.setNumOfMatches( ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT ); - break; - case "max": - scanSettings.setNumOfMatches( ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT ); - break; - default: - callbackContext.error("numOfMatches must be one of: one | few | max"); - validAction = false; - break; + if (Build.VERSION.SDK_INT >= 23) { + switch (options.optString("numOfMatches", "")) { + case "": + break; + case "one": + scanSettings.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT); + break; + case "few": + scanSettings.setNumOfMatches(ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT); + break; + case "max": + scanSettings.setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT); + break; + default: + callbackContext.error("numOfMatches must be one of: one | few | max"); + validAction = false; + break; + } } - switch (options.optString("phy", "")) { - case "": - break; - case "1m": - scanSettings.setPhy( BluetoothDevice.PHY_LE_1M ); - break; - case "coded": - scanSettings.setPhy( BluetoothDevice.PHY_LE_CODED ); - break; - case "all": - scanSettings.setPhy( ScanSettings.PHY_LE_ALL_SUPPORTED ); - break; - default: - callbackContext.error("phy must be one of: 1m | coded | all"); - validAction = false; - break; + if (Build.VERSION.SDK_INT >= 26 /*O*/) { + switch (options.optString("phy", "")) { + case "": + break; + case "1m": + scanSettings.setPhy(BluetoothDevice.PHY_LE_1M); + break; + case "coded": + scanSettings.setPhy(BluetoothDevice.PHY_LE_CODED); + break; + case "all": + scanSettings.setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED); + break; + default: + callbackContext.error("phy must be one of: 1m | coded | all"); + validAction = false; + break; + } } if (validAction) { String LEGACY = "legacy"; - if (!options.isNull(LEGACY)) + if (Build.VERSION.SDK_INT >= 26 /*O*/ && !options.isNull(LEGACY)) scanSettings.setLegacy( options.getBoolean(LEGACY) ); long reportDelay = options.optLong("reportDelay", -1 ); @@ -573,6 +583,7 @@ private void enableBluetooth(CallbackContext callbackContext) { cordova.startActivityForResult(this, intent, REQUEST_ENABLE_BLUETOOTH); } + @SuppressLint("MissingPermission") private void getBondedDevices(CallbackContext callbackContext) { if (COMPILE_SDK_VERSION >= 31 && Build.VERSION.SDK_INT >= 31) { // (API 31) Build.VERSION_CODE.S if (!PermissionHelper.hasPermission(this, BLUETOOTH_CONNECT)) { @@ -610,6 +621,7 @@ private UUID[] parseServiceUUIDList(JSONArray jsonArray) throws JSONException { return serviceUUIDs.toArray(new UUID[jsonArray.length()]); } + @SuppressLint("MissingPermission") private void onBluetoothStateChange(Intent intent) { final String action = intent.getAction(); @@ -718,6 +730,7 @@ private void removeLocationStateListener() { this.locationStateReceiver = null; } + @SuppressLint("MissingPermission") private void connect(CallbackContext callbackContext, String macAddress) { if (COMPILE_SDK_VERSION >= 31 && Build.VERSION.SDK_INT >= 31) { // (API 31) Build.VERSION_CODE.S if (!PermissionHelper.hasPermission(this, BLUETOOTH_CONNECT)) { @@ -734,7 +747,7 @@ private void connect(CallbackContext callbackContext, String macAddress) { return; } - if (!peripherals.containsKey(macAddress) && BLECentralPlugin.this.bluetoothAdapter.checkBluetoothAddress(macAddress)) { + if (!peripherals.containsKey(macAddress) && BluetoothAdapter.checkBluetoothAddress(macAddress)) { BluetoothDevice device = BLECentralPlugin.this.bluetoothAdapter.getRemoteDevice(macAddress); Peripheral peripheral = new Peripheral(device); peripherals.put(macAddress, peripheral); @@ -751,6 +764,7 @@ private void connect(CallbackContext callbackContext, String macAddress) { } + @SuppressLint("MissingPermission") private void autoConnect(CallbackContext callbackContext, String macAddress) { if (COMPILE_SDK_VERSION >= 31 && Build.VERSION.SDK_INT >= 31) { // (API 31) Build.VERSION_CODE.S @@ -788,6 +802,7 @@ private void autoConnect(CallbackContext callbackContext, String macAddress) { } + @SuppressLint("MissingPermission") private void disconnect(CallbackContext callbackContext, String macAddress) { Peripheral peripheral = peripherals.get(macAddress); @@ -819,6 +834,7 @@ private void setPin(CallbackContext callbackContext, final String pin) { } broadCastReceiver = new BroadcastReceiver() { + @SuppressLint("MissingPermission") @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); @@ -846,6 +862,7 @@ public void onReceive(Context context, Intent intent) { } } + @SuppressLint("MissingPermission") private void bond(CallbackContext callbackContext, String macAddress, boolean usePairingDialog) { if (COMPILE_SDK_VERSION >= 31 && Build.VERSION.SDK_INT >= 31) { // (API 31) Build.VERSION_CODE.S List missingPermissions = new ArrayList(); @@ -879,6 +896,7 @@ private void bond(CallbackContext callbackContext, String macAddress, boolean us } } + @SuppressLint("MissingPermission") private void unbond(CallbackContext callbackContext, String macAddress) { if (COMPILE_SDK_VERSION >= 31 && Build.VERSION.SDK_INT >= 31) { // (API 31) Build.VERSION_CODE.S if (!PermissionHelper.hasPermission(this, BLUETOOTH_CONNECT)) { @@ -903,6 +921,7 @@ private void unbond(CallbackContext callbackContext, String macAddress) { } } + @SuppressLint("MissingPermission") private void readBondState(CallbackContext callbackContext, String macAddress) { if (COMPILE_SDK_VERSION >= 31 && Build.VERSION.SDK_INT >= 31) { // (API 31) Build.VERSION_CODE.S if (!PermissionHelper.hasPermission(this, BLUETOOTH_CONNECT)) { @@ -927,6 +946,7 @@ private void readBondState(CallbackContext callbackContext, String macAddress) { } } + @SuppressLint("MissingPermission") private void requestMtu(CallbackContext callbackContext, String macAddress, int mtuValue) { Peripheral peripheral = peripherals.get(macAddress); if (peripheral != null) { @@ -938,6 +958,7 @@ private void requestMtu(CallbackContext callbackContext, String macAddress, int } } + @SuppressLint("MissingPermission") private void requestConnectionPriority(CallbackContext callbackContext, String macAddress, String priority) { Peripheral peripheral = peripherals.get(macAddress); @@ -1031,6 +1052,7 @@ private void write(CallbackContext callbackContext, String macAddress, UUID serv } + @SuppressLint("MissingPermission") private void connectL2cap(CallbackContext callbackContext, String macAddress, int psm, boolean secureChannel) { Peripheral peripheral = peripherals.get(macAddress); if (peripheral == null) { @@ -1130,6 +1152,7 @@ private void removeNotifyCallback(CallbackContext callbackContext, String macAdd } private ScanCallback leScanCallback = new ScanCallback() { + @SuppressLint("MissingPermission") @Override public void onScanResult(int callbackType, ScanResult result) { LOG.w(TAG, "Scan Result"); @@ -1182,6 +1205,7 @@ public void onScanFailed(int errorCode) { }; + @SuppressLint("MissingPermission") private void findLowEnergyDevices(CallbackContext callbackContext, UUID[] serviceUUIDs, int scanSeconds, ScanSettings scanSettings) { if (!locationServicesEnabled() && Build.VERSION.SDK_INT < 31) { @@ -1281,6 +1305,7 @@ private void findLowEnergyDevices(CallbackContext callbackContext, UUID[] servic callbackContext.sendPluginResult(result); } + @SuppressLint("MissingPermission") private void stopScan() { stopScanHandler.removeCallbacks(stopScanRunnable); if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) { @@ -1305,6 +1330,7 @@ private boolean locationServicesEnabled() { return (locationMode > 0); } + @SuppressLint("MissingPermission") private void listKnownDevices(CallbackContext callbackContext) { if (COMPILE_SDK_VERSION >= 31 && Build.VERSION.SDK_INT >= 31) { // (API 31) Build.VERSION_CODE.S if (!PermissionHelper.hasPermission(this, BLUETOOTH_CONNECT)) { diff --git a/src/android/BLECommand.java b/src/android/BLECommand.java index e84ba2f7..1ddb4cb4 100644 --- a/src/android/BLECommand.java +++ b/src/android/BLECommand.java @@ -17,13 +17,11 @@ class BLECommand { // BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE // BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT - private CallbackContext callbackContext; - private UUID serviceUUID; - private UUID characteristicUUID; + private final CallbackContext callbackContext; + private final UUID serviceUUID; + private final UUID characteristicUUID; private byte[] data; - private int type; - private int psm; - + private final int type; public BLECommand(CallbackContext callbackContext, UUID serviceUUID, UUID characteristicUUID, int type) { this.callbackContext = callbackContext; @@ -40,19 +38,6 @@ public BLECommand(CallbackContext callbackContext, UUID serviceUUID, UUID charac this.type = type; } - public BLECommand(CallbackContext callbackContext, int psm, int type) { - this.callbackContext = callbackContext; - this.psm = psm; - this.type = type; - } - - public BLECommand(CallbackContext callbackContext, int psm, byte[] data, int type) { - this.callbackContext = callbackContext; - this.psm = psm; - this.data = data; - this.type = type; - } - public int getType() { return type; } @@ -72,6 +57,4 @@ public UUID getCharacteristicUUID() { public byte[] getData() { return data; } - - public int getPSM() { return psm; } } diff --git a/src/android/L2CAPContext.java b/src/android/L2CAPContext.java index f81df043..a9a7de73 100644 --- a/src/android/L2CAPContext.java +++ b/src/android/L2CAPContext.java @@ -3,7 +3,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.os.Build; -import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; import org.apache.cordova.CallbackContext; import org.apache.cordova.LOG; @@ -34,6 +34,7 @@ public L2CAPContext(BluetoothDevice device, int psm) { this.executor = Executors.newSingleThreadExecutor(); } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public void connectL2cap(CallbackContext callbackContext, boolean secureChannel) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { @@ -107,7 +108,6 @@ public void writeL2CapChannel(CallbackContext callbackContext, byte[] data) { } } - @RequiresApi(api = Build.VERSION_CODES.M) private void readL2CapData() { try { final BluetoothSocket lSocket = this.socket; diff --git a/src/android/Peripheral.java b/src/android/Peripheral.java index 43cddb5b..a69ff5f1 100644 --- a/src/android/Peripheral.java +++ b/src/android/Peripheral.java @@ -14,10 +14,10 @@ package com.megster.cordova.ble.central; +import android.annotation.SuppressLint; import android.app.Activity; import android.bluetooth.*; -import android.os.Build; import android.os.Handler; import android.util.Base64; import org.apache.cordova.CallbackContext; @@ -51,14 +51,14 @@ public class Peripheral extends BluetoothGattCallback { private static final int FAKE_PERIPHERAL_RSSI = 0x7FFFFFFF; - private BluetoothDevice device; + private final BluetoothDevice device; private byte[] advertisingData; private Boolean isConnectable = null; private int advertisingRSSI; private boolean autoconnect = false; private boolean connected = false; private boolean connecting = false; - private ConcurrentLinkedQueue commandQueue = new ConcurrentLinkedQueue(); + private final ConcurrentLinkedQueue commandQueue = new ConcurrentLinkedQueue(); private final Map l2capContexts = new HashMap(); private final AtomicBoolean bleProcessing = new AtomicBoolean(); @@ -72,7 +72,7 @@ public class Peripheral extends BluetoothGattCallback { private CallbackContext bondStateCallback; private Activity currentActivity; - private Map notificationCallbacks = new HashMap(); + private final Map notificationCallbacks = new HashMap(); public Peripheral(BluetoothDevice device) { @@ -91,6 +91,7 @@ public Peripheral(BluetoothDevice device, int advertisingRSSI, byte[] scanRecord this.isConnectable = isConnectable; } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") private void gattConnect() { closeGatt(); @@ -100,14 +101,10 @@ private void gattConnect() { callbackCleanup("Aborted by new connect call"); BluetoothDevice device = getDevice(); - if (Build.VERSION.SDK_INT < 23) { - gatt = device.connectGatt(currentActivity, autoconnect, this); - } else { - gatt = device.connectGatt(currentActivity, autoconnect, this, BluetoothDevice.TRANSPORT_LE); - } - + gatt = device.connectGatt(currentActivity, autoconnect, this, BluetoothDevice.TRANSPORT_LE); } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public void connect(CallbackContext callbackContext, Activity activity, boolean auto) { currentActivity = activity; autoconnect = auto; @@ -121,6 +118,7 @@ public void connect(CallbackContext callbackContext, Activity activity, boolean // the app requested the central disconnect from the peripheral // disconnect the gatt, do not call connectCallback.error + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public void disconnect() { connected = false; connecting = false; @@ -133,6 +131,7 @@ public void disconnect() { // the peripheral disconnected // always call connectCallback.error to notify the app + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public void peripheralDisconnected(String message) { connected = false; connecting = false; @@ -148,6 +147,7 @@ public void peripheralDisconnected(String message) { callbackCleanup(message); } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") private void closeGatt() { BluetoothGatt localGatt; synchronized (this) { @@ -161,6 +161,7 @@ private void closeGatt() { } // notify the phone that the peripheral disconnected + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") private void sendDisconnectMessage(String messageContent) { if (connectCallback != null) { JSONObject message = this.asJSONObject(messageContent); @@ -188,16 +189,13 @@ public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { requestMtuCallback = null; } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public void requestMtu(CallbackContext callback, int mtuValue) { LOG.d(TAG, "requestMtu mtu=%d", mtuValue); if (gatt == null) { callback.error("No GATT"); return; } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - callback.error("Android version does not support requestMtu"); - return; - } if (gatt.requestMtu(mtuValue)) { requestMtuCallback = callback; @@ -206,12 +204,11 @@ public void requestMtu(CallbackContext callback, int mtuValue) { } } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public void requestConnectionPriority(int priority) { if (gatt != null) { LOG.d(TAG, "requestConnectionPriority priority=" + priority); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - gatt.requestConnectionPriority(priority); - } + gatt.requestConnectionPriority(priority); } } @@ -219,7 +216,7 @@ public void requestConnectionPriority(int priority) { * Uses reflection to refresh the device cache. This *might* be helpful if a peripheral changes * services or characteristics and does not correctly implement Service Changed 0x2a05 * on Generic Attribute Service 0x1801. - * + *

* Since this uses an undocumented API it's not guaranteed to work. * */ @@ -237,6 +234,7 @@ public void refreshDeviceCache(CallbackContext callback, final long timeoutMilli Handler handler = new Handler(); LOG.d(TAG, "Waiting " + timeoutMillis + " milliseconds before discovering services"); handler.postDelayed(new Runnable() { + @SuppressLint("MissingPermission") @Override public void run() { if (gatt != null) { @@ -266,6 +264,7 @@ public boolean isUnscanned() { return advertisingData == null; } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public JSONObject asJSONObject() { JSONObject json = new JSONObject(); @@ -291,6 +290,7 @@ public JSONObject asJSONObject() { return json; } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public JSONObject asJSONObject(String errorMessage) { JSONObject json = new JSONObject(); @@ -306,6 +306,7 @@ public JSONObject asJSONObject(String errorMessage) { return json; } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public JSONObject asJSONObject(BluetoothGatt gatt) { JSONObject json = asJSONObject(); @@ -381,6 +382,7 @@ public BluetoothDevice getDevice() { return device; } + @SuppressLint("MissingPermission") @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); @@ -408,6 +410,7 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) { } } + @SuppressLint("MissingPermission") @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { @@ -537,6 +540,7 @@ public void updateRssi(int rssi) { } // This seems way too complicated + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") private void registerNotifyCallback(CallbackContext callbackContext, UUID serviceUUID, UUID characteristicUUID) { if (gatt == null) { @@ -599,6 +603,7 @@ private void registerNotifyCallback(CallbackContext callbackContext, UUID servic } } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") private void removeNotifyCallback(CallbackContext callbackContext, UUID serviceUUID, UUID characteristicUUID) { if (gatt == null) { @@ -676,6 +681,7 @@ private BluetoothGattCharacteristic findNotifyCharacteristic(BluetoothGattServic return characteristic; } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") private void readCharacteristic(CallbackContext callbackContext, UUID serviceUUID, UUID characteristicUUID) { if (gatt == null) { @@ -718,6 +724,7 @@ private void readCharacteristic(CallbackContext callbackContext, UUID serviceUUI } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") private void readRSSI(CallbackContext callbackContext) { if (gatt == null) { @@ -768,6 +775,7 @@ private BluetoothGattCharacteristic findReadableCharacteristic(BluetoothGattServ return characteristic; } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") private void writeCharacteristic(CallbackContext callbackContext, UUID serviceUUID, UUID characteristicUUID, byte[] data, int writeType) { if (gatt == null) { @@ -887,6 +895,7 @@ public void writeL2CapChannel(CallbackContext callbackContext, int psm, byte[] d getOrAddL2CAPContext(psm).writeL2CapChannel(callbackContext, data); } + @SuppressLint("MissingPermission") private void callbackCleanup(String message) { synchronized(this) { if (readCallback != null) { @@ -923,6 +932,7 @@ private void queueCommand(BLECommand command) { } // command finished, queue the next command + @SuppressLint("MissingPermission") private void commandCompleted() { LOG.d(TAG,"Processing Complete"); bleProcessing.set(false); @@ -930,6 +940,7 @@ private void commandCompleted() { } // process the queue + @SuppressLint("MissingPermission") private void processCommands() { final boolean canProcess = bleProcessing.compareAndSet(false, true); if (!canProcess) { return; } @@ -975,6 +986,7 @@ private String generateHashKey(UUID serviceUUID, BluetoothGattCharacteristic cha return serviceUUID + "|" + characteristic.getUuid() + "|" + characteristic.getInstanceId(); } + @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public void connectL2cap(CallbackContext callbackContext, int psm, boolean secureChannel) { getOrAddL2CAPContext(psm).connectL2cap(callbackContext, secureChannel); } @@ -1009,7 +1021,7 @@ private L2CAPContext getOrAddL2CAPContext(int psm) { } } - @RequiresPermission("android.permission.BLUETOOTH_CONNECT") + @RequiresPermission(allOf = { "android.permission.BLUETOOTH_CONNECT", "android.permission.BLUETOOTH_SCAN" }) public void bond(CallbackContext callbackContext, BluetoothAdapter bluetoothAdapter, boolean usePairingDialog) { if (bondStateCallback != null) { bondStateCallback.error("Aborted by new bond call");