Provides a Kotlin Coroutines powered interaction with Android's Bluetooth Low Energy (BLE) framework.
See Recipes page for usage examples.
When feasible, the API closely matches the Android Bluetooth Low Energy API, replacing methods that
traditionally rely on BluetoothGattCallback
calls with suspension functions.
Android BluetoothDevice |
Able Device |
|
|
1 Suspends until STATE_CONNECTED
or non-GATT_SUCCESS
is received, then returns
ConnectGattResult
:
sealed class ConnectGattResult {
data class Success(val gatt: Gatt) : ConnectGattResult()
data class Canceled(val cause: CancellationException) : ConnectGattResult()
data class Failure(val cause: Throwable) : ConnectGattResult()
}
Android BluetoothGatt |
Able Gatt |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 Suspends until STATE_CONNECTED
or non-GATT_SUCCESS
is received.
2 Suspends until STATE_DISCONNECTED
or non-GATT_SUCCESS
is received.
3 Throws RemoteException
if underlying BluetoothGatt
call returns false
.
3 Throws GattClosed
if Gatt
is closed while method is executing.
3 Throws GattConnectionLost
if Gatt
is disconnects while method is executing.
The primary entry point is the
BluetoothDevice.connectGatt(context: Context, autoConnect: Boolean): ConnectGattResult
extension
function. This extension function acts as a replacement for Android's
BluetoothDevice.connectGatt(context: Context, autoConnect: Boolean, callback: BluetoothCallback): BluetoothGatt?
method (which relies on a BluetoothGattCallback
).
Able expects that Android Bluetooth Low Energy is supported
(BluetoothAdapter.getDefaultAdapter()
returns non-null
) and usage prerequisites
(e.g. bluetooth permissions) are satisfied prior to use; failing to do so will result in
RemoteException
for most Able methods.
Kotlin Coroutines 0.26.0
introduced structured concurrency.
When establishing a connection (e.g. via
BluetoothDevice.connectGatt(context: Context, autoConnect: Boolean): ConnectGattResult
extension
function), if the Coroutine is cancelled then the in-flight connection attempt will be cancelled and
corresponding BluetoothGatt
will be closed:
fun connect(context: Context, device: BluetoothDevice) {
val deferred = async {
device.connectGatt(context, autoConnect = false)
}
launch {
delay(1000L) // Assume, for this example, that BLE connection takes more than 1 second.
// Cancels the `async` Coroutine and automatically closes the underlying `BluetoothGatt`.
deferred.cancel()
}
val result = deferred.await() // `result` will be `ConnectGattResult.Canceled`.
}
Note that in the above example, if the BLE connection takes less than 1 second, then the
established connection will not be cancelled (and Gatt
will not be closed), and result
will be ConnectGattResult.Success
.
Able's Gatt
provides a CoroutineScope
, allowing any Coroutine builders to be scoped to the
Gatt
instance. For example, you can continually read a characteristic and the Coroutine will
automatically cancel when the Gatt
is closed (error handling omitted for simplicity):
fun continuallyReadCharacteristic(gatt: Gatt, serviceUuid: UUID, characteristicUuid: UUID) {
val characteristic = gatt.getService(serviceUuid)!!.getCharacteristic(characteristicUuid)!!
// This Coroutine will automatically cancel when `gatt.close()` is called.
gatt.launch {
while (isActive) {
println("value = ${gatt.readCharacteristic(characteristic).value}")
}
}
}
To use Able in your Android project, setup your build.gradle
as follows:
dependencies {
implementation "com.juul.able:core:0.7.1"
}
Able provides a number of packages to help extend it's functionality:
Package | Functionality |
---|---|
processor |
A Processor adds the ability to process (and optionally modify) GATT datapre-write or post-read. |
retry |
Retry wraps a Gatt to add I/O retry functionality and on-demand connectionestablishment. |
throw |
Adds extension functions that throw exceptions on failures for various BLEoperations. |
timber-logger |
Routes Able logging through Timber. |
device |
Provides BluetoothDevice extension functions as a single access point forconnectivity and communication. |
Copyright 2018 JUUL Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.