diff --git a/app/src/main/java/com/welie/blessedexample/BluetoothHandler.kt b/app/src/main/java/com/welie/blessedexample/BluetoothHandler.kt index 79aeff9..0bc7e83 100644 --- a/app/src/main/java/com/welie/blessedexample/BluetoothHandler.kt +++ b/app/src/main/java/com/welie/blessedexample/BluetoothHandler.kt @@ -1,5 +1,6 @@ package com.welie.blessedexample +import android.bluetooth.BluetoothAdapter import android.content.Context import com.welie.blessed.* import kotlinx.coroutines.* @@ -22,7 +23,7 @@ internal class BluetoothHandler private constructor(context: Context) { val weightChannel = Channel(UNLIMITED) private fun handlePeripheral(peripheral: BluetoothPeripheral) { - scope.launch(Dispatchers.IO) { + scope.launch { try { val mtu = peripheral.requestMtu(185) Timber.i("MTU is $mtu") @@ -307,6 +308,12 @@ internal class BluetoothHandler private constructor(context: Context) { } } + central.observeAdapterState { state -> + when(state) { + BluetoothAdapter.STATE_ON -> startScanning() + } + } + startScanning() } } \ No newline at end of file diff --git a/app/src/main/java/com/welie/blessedexample/MainActivity.kt b/app/src/main/java/com/welie/blessedexample/MainActivity.kt index 666bda2..5fb5284 100644 --- a/app/src/main/java/com/welie/blessedexample/MainActivity.kt +++ b/app/src/main/java/com/welie/blessedexample/MainActivity.kt @@ -226,7 +226,7 @@ class MainActivity : AppCompatActivity() { if (missingPermissions.isNotEmpty()) { requestPermissions(missingPermissions, ACCESS_LOCATION_REQUEST) } else { - permissionsGranted() + checkIfLocationIsNeeded() } } @@ -250,10 +250,10 @@ class MainActivity : AppCompatActivity() { } else arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION) } - private fun permissionsGranted() { - // Check if Location services are on because they are required to make scanning work for SDK < 31 + private fun checkIfLocationIsNeeded() { val targetSdkVersion = applicationInfo.targetSdkVersion if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && targetSdkVersion < Build.VERSION_CODES.S) { + // Check if Location services are on because they are required to make scanning work for SDK < 31 if (checkLocationServices()) { initBluetoothHandler() } @@ -313,7 +313,7 @@ class MainActivity : AppCompatActivity() { } } if (allGranted) { - permissionsGranted() + checkIfLocationIsNeeded() } else { AlertDialog.Builder(this@MainActivity) .setTitle("Location permission is required for scanning Bluetooth peripherals") diff --git a/blessed/build.gradle b/blessed/build.gradle index a36b7c4..bed313d 100644 --- a/blessed/build.gradle +++ b/blessed/build.gradle @@ -8,8 +8,6 @@ android { defaultConfig { minSdkVersion 26 targetSdkVersion 31 - versionCode 1 - versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/blessed/src/main/java/com/welie/blessed/BluetoothCentralManager.kt b/blessed/src/main/java/com/welie/blessed/BluetoothCentralManager.kt index 8eb58fe..ae76dca 100644 --- a/blessed/src/main/java/com/welie/blessed/BluetoothCentralManager.kt +++ b/blessed/src/main/java/com/welie/blessed/BluetoothCentralManager.kt @@ -23,6 +23,7 @@ package com.welie.blessed import android.Manifest +import android.annotation.SuppressLint import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.bluetooth.BluetoothManager @@ -50,6 +51,8 @@ import kotlin.coroutines.suspendCoroutine /** * Central Manager class to scan and connect with bluetooth peripherals. */ +@SuppressLint("MissingPermission") +@Suppress("unused") class BluetoothCentralManager(private val context: Context) { private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private val bluetoothAdapter: BluetoothAdapter @@ -74,6 +77,7 @@ class BluetoothCentralManager(private val context: Context) { private var disconnectRunnable: Runnable? = null private val pinCodes: MutableMap = ConcurrentHashMap() private var currentResultCallback : ((BluetoothPeripheral, ScanResult) -> Unit)? = null + private var adapterStateCallback: (state: Int) -> Unit = {} private val scanByNameCallback: ScanCallback = object : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult) { @@ -254,7 +258,7 @@ class BluetoothCentralManager(private val context: Context) { setScanTimer() currentCallback = scanCallback currentFilters = filters - bluetoothScanner!!.startScan(filters, scanSettings, scanCallback) + bluetoothScanner?.startScan(filters, scanSettings, scanCallback) Logger.i(TAG, "scan started") } else { Logger.e(TAG, "starting scan failed") @@ -590,11 +594,11 @@ class BluetoothCentralManager(private val context: Context) { throw IllegalArgumentException(message) } return if (connectedPeripherals.containsKey(peripheralAddress)) { - Objects.requireNonNull(connectedPeripherals[peripheralAddress])!! + requireNotNull(connectedPeripherals[peripheralAddress]) } else if (unconnectedPeripherals.containsKey(peripheralAddress)) { - Objects.requireNonNull(unconnectedPeripherals[peripheralAddress])!! + requireNotNull(unconnectedPeripherals[peripheralAddress]) } else if (scannedPeripherals.containsKey(peripheralAddress)) { - Objects.requireNonNull(scannedPeripherals[peripheralAddress])!! + requireNotNull(scannedPeripherals[peripheralAddress]) } else { val peripheral = BluetoothPeripheral(context, bluetoothAdapter.getRemoteDevice(peripheralAddress), internalCallback) scannedPeripherals[peripheralAddress] = peripheral @@ -857,14 +861,17 @@ class BluetoothCentralManager(private val context: Context) { } } - @JvmField - val adapterStateReceiver: BroadcastReceiver = object : BroadcastReceiver() { + fun observeAdapterState(callback: (state: Int) -> Unit) { + this.adapterStateCallback = callback + } + + private val adapterStateReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val action = intent.action ?: return if (action == BluetoothAdapter.ACTION_STATE_CHANGED) { val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR) - // scope.launch { bluetoothCentralManagerCallback.onBluetoothAdapterStateChanged(state) } handleAdapterState(state) + adapterStateCallback.invoke(state) } } } @@ -873,7 +880,7 @@ class BluetoothCentralManager(private val context: Context) { when (state) { BluetoothAdapter.STATE_OFF -> { // Check if there are any connected peripherals or connections in progress - if (connectedPeripherals.size > 0 || unconnectedPeripherals.size > 0) { + if (connectedPeripherals.isNotEmpty() || unconnectedPeripherals.isNotEmpty()) { // See if they are automatically disconnect expectingBluetoothOffDisconnects = true startDisconnectionTimer() @@ -881,6 +888,24 @@ class BluetoothCentralManager(private val context: Context) { Logger.d(TAG, "bluetooth turned off") } BluetoothAdapter.STATE_TURNING_OFF -> { + // Stop all scans so that we are back in a clean state + if (isScanning) { + // Note that we can't call stopScan if the adapter is off + // On some phones like the Nokia 8, the adapter will be already off at this point + // So add a try/catch to handle any exceptions + try { + stopScan() + } catch (ignored: java.lang.Exception) { + } + } + + if (isAutoScanning) { + try { + stopAutoconnectScan() + } catch (ignored: java.lang.Exception) { + } + } + expectingBluetoothOffDisconnects = true // Stop all scans so that we are back in a clean state @@ -890,9 +915,15 @@ class BluetoothCentralManager(private val context: Context) { currentCallback = null currentFilters = null autoConnectScanner = null + bluetoothScanner = null Logger.d(TAG, "bluetooth turning off") } BluetoothAdapter.STATE_ON -> { + // On some phones like Nokia 8, this scanner may still have an older active scan from us + // This happens when bluetooth is toggled. So make sure it is gone. + bluetoothScanner = bluetoothAdapter.bluetoothLeScanner + bluetoothScanner?.stopScan(defaultScanCallback) + expectingBluetoothOffDisconnects = false Logger.d(TAG, "bluetooth turned on") } @@ -903,11 +934,11 @@ class BluetoothCentralManager(private val context: Context) { } } - fun disableLogging(): Unit { + fun disableLogging() { Logger.enabled = false } - fun enableLogging(): Unit { + fun enableLogging() { Logger.enabled = false } @@ -921,20 +952,12 @@ class BluetoothCentralManager(private val context: Context) { private const val NO_VALID_PERIPHERAL_CALLBACK_SPECIFIED = "no valid peripheral callback specified" } - /** - * Construct a new BluetoothCentralManager object - * - * @param context Android application environment. - * @param bluetoothCentralManagerCallback the callback to call for updates - * @param handler Handler to use for callbacks. - */ init { val manager = context.getSystemService(BLUETOOTH_SERVICE) as BluetoothManager bluetoothAdapter = manager.adapter autoConnectScanSettings = getScanSettings(ScanMode.LOW_POWER) scanSettings = getScanSettings(ScanMode.LOW_LATENCY) - // Register for broadcasts on BluetoothAdapter state change val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) context.registerReceiver(adapterStateReceiver, filter) } diff --git a/blessed/src/main/java/com/welie/blessed/BluetoothPeripheral.kt b/blessed/src/main/java/com/welie/blessed/BluetoothPeripheral.kt index f7f68d5..3c11710 100644 --- a/blessed/src/main/java/com/welie/blessed/BluetoothPeripheral.kt +++ b/blessed/src/main/java/com/welie/blessed/BluetoothPeripheral.kt @@ -22,6 +22,7 @@ */ package com.welie.blessed +import android.annotation.SuppressLint import android.bluetooth.* import android.bluetooth.BluetoothGattDescriptor.* import android.content.BroadcastReceiver @@ -46,6 +47,8 @@ import kotlin.coroutines.suspendCoroutine * This class is a wrapper around the [BluetoothDevice] and [BluetoothGatt] classes. * It takes care of operation queueing, some Android bugs, and provides several convenience functions. */ +@SuppressLint("MissingPermission") +@Suppress("unused") class BluetoothPeripheral internal constructor( private val context: Context, private var device: BluetoothDevice, @@ -286,10 +289,11 @@ class BluetoothPeripheral internal constructor( } } + @SuppressLint("MissingPermission") private fun discoverServices() { discoverJob = scope.launch { Logger.d(TAG, "discovering services of '%s'", name) - if (bluetoothGatt != null && bluetoothGatt!!.discoverServices()) { + if (bluetoothGatt != null && (bluetoothGatt?.discoverServices() == true)) { discoveryStarted = true } else { Logger.e(TAG, "discoverServices failed to start") @@ -405,6 +409,7 @@ class BluetoothPeripheral internal constructor( } private val pairingRequestBroadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() { + @SuppressLint("MissingPermission") override fun onReceive(context: Context, intent: Intent) { val receivedDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) ?: return if (!receivedDevice.address.equals(address, ignoreCase = true)) return @@ -437,9 +442,16 @@ class BluetoothPeripheral internal constructor( registerBondingBroadcastReceivers() state = BluetoothProfile.STATE_CONNECTING discoveryStarted = false - bluetoothGatt = device.connectGatt(context, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE) - connectTimestamp = SystemClock.elapsedRealtime() - startConnectionTimer(this@BluetoothPeripheral) + bluetoothGatt = try { + device.connectGatt(context, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE) + } catch (e: SecurityException) { + Logger.d(TAG, "exception") + null + } + bluetoothGatt?.let { + connectTimestamp = SystemClock.elapsedRealtime() + startConnectionTimer(this@BluetoothPeripheral) + } } } else { Logger.e(TAG, "peripheral '%s' not yet disconnected, will not connect", name) @@ -459,8 +471,15 @@ class BluetoothPeripheral internal constructor( registerBondingBroadcastReceivers() state = BluetoothProfile.STATE_CONNECTING discoveryStarted = false - bluetoothGatt = device.connectGatt(context, true, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE) - connectTimestamp = SystemClock.elapsedRealtime() + bluetoothGatt = try { + device.connectGatt(context, true, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE) + } catch (e: SecurityException) { + Logger.d(TAG, "exception") + null + } + bluetoothGatt?.let { + connectTimestamp = SystemClock.elapsedRealtime() + } } } else { Logger.e(TAG, "peripheral '%s' not yet disconnected, will not connect", name) @@ -482,6 +501,7 @@ class BluetoothPeripheral internal constructor( * * @return true if bonding was started/enqueued, false if not */ + fun createBond(): Boolean { // Check if we have a Gatt object if (bluetoothGatt == null) { @@ -787,7 +807,7 @@ class BluetoothPeripheral internal constructor( require(characteristic.supportsReading()) { "characteristic does not have read property" } require(isConnected) { PERIPHERAL_NOT_CONNECTED } - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { currentResultCallback = resultCallback if (bluetoothGatt!!.readCharacteristic(characteristic)) { @@ -802,16 +822,11 @@ class BluetoothPeripheral internal constructor( resultCallback.onCharacteristicRead(this@BluetoothPeripheral, ByteArray(0), characteristic, GattStatus.CONNECTION_CANCELLED) completedCommand() } - }) - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue read characteristic command") } - return result } + suspend fun writeCharacteristic(serviceUUID: UUID, characteristicUUID: UUID, value: ByteArray, writeType: WriteType): ByteArray { require(isConnected) { PERIPHERAL_NOT_CONNECTED } @@ -881,7 +896,7 @@ class BluetoothPeripheral internal constructor( // Copy the value to avoid race conditions val bytesToWrite = copyOf(value) - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { currentResultCallback = resultCallback currentWriteBytes = bytesToWrite @@ -908,13 +923,7 @@ class BluetoothPeripheral internal constructor( resultCallback.onCharacteristicWrite(this@BluetoothPeripheral, ByteArray(0), characteristic, GattStatus.CONNECTION_CANCELLED) completedCommand() } - }) - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue write characteristic command") } - return result } private fun willCauseLongWrite(value: ByteArray, writeType: WriteType): Boolean { @@ -952,10 +961,10 @@ class BluetoothPeripheral internal constructor( private fun readDescriptor(descriptor: BluetoothGattDescriptor, resultCallback: BluetoothPeripheralCallback): Boolean { require(isConnected) { PERIPHERAL_NOT_CONNECTED } - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { currentResultCallback = resultCallback - if (bluetoothGatt!!.readDescriptor(descriptor)) { + if (bluetoothGatt?.readDescriptor(descriptor) == true) { Logger.d(TAG, "reading descriptor <%s>", descriptor.uuid) nrTries++ } else { @@ -967,13 +976,7 @@ class BluetoothPeripheral internal constructor( resultCallback.onDescriptorRead(this@BluetoothPeripheral, ByteArray(0), descriptor, GattStatus.CONNECTION_CANCELLED) completedCommand() } - }) - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue read descriptor command") } - return result } suspend fun writeDescriptor(descriptor: BluetoothGattDescriptor, value: ByteArray): ByteArray = @@ -1015,12 +1018,12 @@ class BluetoothPeripheral internal constructor( // Copy the value to avoid race conditions val bytesToWrite = copyOf(value) - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { currentResultCallback = resultCallback currentWriteBytes = bytesToWrite descriptor.value = bytesToWrite - if (bluetoothGatt!!.writeDescriptor(descriptor)) { + if (bluetoothGatt?.writeDescriptor(descriptor) == true) { Logger.d(TAG, "writing <%s> to descriptor <%s>", BluetoothBytesParser.bytes2String(bytesToWrite), descriptor.uuid) nrTries++ } else { @@ -1032,14 +1035,7 @@ class BluetoothPeripheral internal constructor( resultCallback.onDescriptorWrite(this@BluetoothPeripheral, ByteArray(0), descriptor, GattStatus.CONNECTION_CANCELLED) completedCommand() } - }) - - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue write descriptor command") } - return result } @@ -1137,37 +1133,28 @@ class BluetoothPeripheral internal constructor( } val finalValue = if (enable) value else DISABLE_NOTIFICATION_VALUE - val result = commandQueue.add(Runnable { + return enqueue { if (notConnected()) { resultCallback.onDescriptorWrite(this@BluetoothPeripheral, ByteArray(0), descriptor, GattStatus.CONNECTION_CANCELLED) completedCommand() - return@Runnable - } - - // First try to set notification for Gatt object - currentResultCallback = resultCallback - if (!bluetoothGatt!!.setCharacteristicNotification(characteristic, enable)) { - Logger.e(TAG, "setCharacteristicNotification failed for characteristic: %s", characteristic.uuid) - completedCommand() - return@Runnable - } - - currentWriteBytes = finalValue - descriptor.value = finalValue - if (bluetoothGatt!!.writeDescriptor(descriptor)) { - nrTries++ } else { - Logger.e(TAG, "writeDescriptor failed for descriptor: %s", descriptor.uuid) - resultCallback.onDescriptorWrite(this@BluetoothPeripheral, ByteArray(0), descriptor, GattStatus.WRITE_NOT_PERMITTED) - completedCommand() + currentResultCallback = resultCallback + if (bluetoothGatt?.setCharacteristicNotification(characteristic, enable) == false) { + Logger.e(TAG, "setCharacteristicNotification failed for characteristic: %s", characteristic.uuid) + completedCommand() + } else { + currentWriteBytes = finalValue + descriptor.value = finalValue + if (bluetoothGatt?.writeDescriptor(descriptor) == true) { + nrTries++ + } else { + Logger.e(TAG, "writeDescriptor failed for descriptor: %s", descriptor.uuid) + resultCallback.onDescriptorWrite(this@BluetoothPeripheral, ByteArray(0), descriptor, GattStatus.WRITE_NOT_PERMITTED) + completedCommand() + } + } } - }) - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue setNotify command") } - return result } suspend fun readRemoteRssi(): Int = @@ -1198,10 +1185,10 @@ class BluetoothPeripheral internal constructor( private fun readRemoteRssi(resultCallback: BluetoothPeripheralCallback): Boolean { require(isConnected) { PERIPHERAL_NOT_CONNECTED } - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { currentResultCallback = resultCallback - if (!bluetoothGatt!!.readRemoteRssi()) { + if (bluetoothGatt?.readRemoteRssi() == false) { Logger.e(TAG, "readRemoteRssi failed") resultCallback.onReadRemoteRssi(this@BluetoothPeripheral, 0, GattStatus.ERROR) completedCommand() @@ -1210,13 +1197,7 @@ class BluetoothPeripheral internal constructor( resultCallback.onReadRemoteRssi(this@BluetoothPeripheral, 0, GattStatus.CONNECTION_CANCELLED) completedCommand() } - }) - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue readRemoteRssi command") } - return result } suspend fun requestMtu(mtu: Int): Int = @@ -1260,10 +1241,10 @@ class BluetoothPeripheral internal constructor( require(mtu in DEFAULT_MTU..MAX_MTU) { "mtu must be between 23 and 517" } require(isConnected) { PERIPHERAL_NOT_CONNECTED } - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { currentResultCallback = resultCallback - if (bluetoothGatt!!.requestMtu(mtu)) { + if (bluetoothGatt?.requestMtu(mtu) == true) { currentCommand = REQUEST_MTU_COMMAND Logger.d(TAG, "requesting MTU of %d", mtu) } else { @@ -1275,13 +1256,7 @@ class BluetoothPeripheral internal constructor( resultCallback.onMtuChanged(this@BluetoothPeripheral, 0, GattStatus.CONNECTION_CANCELLED) completedCommand() } - }) - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue requestMtu command") } - return result } @@ -1311,10 +1286,10 @@ class BluetoothPeripheral internal constructor( private fun requestConnectionPriority(priority: ConnectionPriority, resultCallback: BluetoothPeripheralCallback): Boolean { require(isConnected) { PERIPHERAL_NOT_CONNECTED } - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { currentResultCallback = resultCallback - if (bluetoothGatt!!.requestConnectionPriority(priority.value)) { + if (bluetoothGatt?.requestConnectionPriority(priority.value) == true) { Logger.d(TAG, "requesting connection priority %s", priority) } else { Logger.e(TAG, "could not request connection priority") @@ -1326,14 +1301,7 @@ class BluetoothPeripheral internal constructor( currentResultCallback.onRequestedConnectionPriority(this@BluetoothPeripheral) completedCommand() } - }) - - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue request connection priority command") } - return result } /** @@ -1366,7 +1334,7 @@ class BluetoothPeripheral internal constructor( private fun setPreferredPhy(txPhy: PhyType, rxPhy: PhyType, phyOptions: PhyOptions, resultCallback: BluetoothPeripheralCallback): Boolean { require(isConnected) { PERIPHERAL_NOT_CONNECTED } - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { Logger.d(TAG, "setting preferred Phy: tx = %s, rx = %s, options = %s", txPhy, rxPhy, phyOptions) currentResultCallback = resultCallback @@ -1376,14 +1344,7 @@ class BluetoothPeripheral internal constructor( resultCallback.onPhyUpdate(this@BluetoothPeripheral, txPhy, rxPhy, GattStatus.CONNECTION_CANCELLED) completedCommand() } - }) - - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue setPreferredPhy command") } - return result } /** @@ -1411,7 +1372,7 @@ class BluetoothPeripheral internal constructor( private fun readPhy(resultCallback: BluetoothPeripheralCallback): Boolean { require(isConnected) { PERIPHERAL_NOT_CONNECTED } - val result = commandQueue.add(Runnable { + return enqueue { if (isConnected) { currentResultCallback = resultCallback bluetoothGatt?.readPhy() @@ -1420,14 +1381,7 @@ class BluetoothPeripheral internal constructor( resultCallback.onPhyUpdate(this@BluetoothPeripheral, PhyType.UNKNOWN_PHY_TYPE, PhyType.UNKNOWN_PHY_TYPE, GattStatus.CONNECTION_CANCELLED) completedCommand() } - }) - - if (result) { - nextCommand() - } else { - Logger.e(TAG, "could not enqueue readyPhy command") } - return result } /** @@ -1439,7 +1393,7 @@ class BluetoothPeripheral internal constructor( if (bluetoothGatt == null) return false var result = false try { - val refreshMethod = bluetoothGatt!!.javaClass.getMethod("refresh") + val refreshMethod = bluetoothGatt?.javaClass?.getMethod("refresh") if (refreshMethod != null) { result = refreshMethod.invoke(bluetoothGatt) as Boolean } @@ -1450,6 +1404,21 @@ class BluetoothPeripheral internal constructor( return result } + /** + * Enqueue a command + * + * Return true if the command was enqueued, otherwise false + */ + private fun enqueue(command: Runnable) : Boolean { + val result = commandQueue.add(command) + if (result) { + nextCommand() + } else { + Logger.e(TAG, "could not enqueue command") + } + return result + } + /** * The current command has been completed, move to the next command in the queue (if any) */ diff --git a/blessed/src/main/java/com/welie/blessed/BluetoothPeripheralManager.kt b/blessed/src/main/java/com/welie/blessed/BluetoothPeripheralManager.kt index 5ace389..f823c0c 100644 --- a/blessed/src/main/java/com/welie/blessed/BluetoothPeripheralManager.kt +++ b/blessed/src/main/java/com/welie/blessed/BluetoothPeripheralManager.kt @@ -22,6 +22,7 @@ */ package com.welie.blessed +import android.annotation.SuppressLint import android.bluetooth.* import android.bluetooth.le.AdvertiseCallback import android.bluetooth.le.AdvertiseData @@ -42,6 +43,7 @@ import java.util.concurrent.ConcurrentLinkedQueue /** * This class represent a peripheral running on the local phone */ +@SuppressLint("MissingPermission") class BluetoothPeripheralManager(private val context: Context, private val bluetoothManager: BluetoothManager, private val callback: BluetoothPeripheralManagerCallback) { // private val context: Context private val mainHandler = Handler(Looper.getMainLooper()) diff --git a/build.gradle b/build.gradle index a1674a4..3db15fd 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.0.3' + classpath 'com.android.tools.build:gradle:7.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong