### Gradle Dependency Setup for Android BLE Library Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Add the core library and any optional modules to your `build.gradle` file. Choose modules based on your project's needs, such as Kotlin extensions or common profile parsers. ```groovy // Core BLE library (required) implementation 'no.nordicsemi.android:ble:2.11.0' ``` ```groovy // Kotlin coroutines + Flow extensions (optional) implementation 'no.nordicsemi.android:ble-ktx:2.11.0' ``` ```groovy // Parsers for standard Bluetooth SIG profiles (optional) implementation 'no.nordicsemi.android:ble-common:2.11.0' ``` ```groovy // LiveData-based connection/bond state observers (optional) implementation 'no.nordicsemi.android:ble-livedata:2.11.0' ``` -------------------------------- ### Deprecated getGattCallback() Method Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md The `getGattCallback()` method is deprecated. Instead, move the inner methods directly into the `BleManager` class. Refer to the provided PR for an example. ```java getGattCallback() ``` -------------------------------- ### Get BluetoothGattCharacteristic by Properties and Instance ID in Kotlin Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Helper methods are available in `BluetoothGattService` to retrieve a `BluetoothGattCharacteristic` based on required properties and instance ID. This simplifies characteristic discovery. ```kotlin BluetoothGattService.getCharacteristic(properties, instanceId) ``` -------------------------------- ### Sample BleManager Implementation in Java Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Provides a sample implementation of the BleManager class, demonstrating how to handle logging, service discovery, initialization, and defining a public API for device interaction. ```java class MyBleManager extends BleManager { private static final String TAG = "MyBleManager"; public MyBleManager(@NonNull final Context context) { super(context); } // ==== Logging ===== @Override public int getMinLogPriority() { // Use to return minimal desired logging priority. return Log.VERBOSE; } @Override public void log(int priority, @NonNull String message) { // Log from here. Log.println(priority, TAG, message); } // ==== Required implementation ==== // This is a reference to a characteristic that the manager will use internally. private BluetoothGattCharacteristic fluxCapacitorControlPoint; @Override protected boolean isRequiredServiceSupported(@NonNull BluetoothGatt gatt) { // Here obtain instances of your characteristics. // Return false if a required service has not been discovered. BluetoothGattService fluxCapacitorService = gatt.getService(FLUX_SERVICE_UUID); if (fluxCapacitorService != null) { fluxCapacitorControlPoint = fluxCapacitorService.getCharacteristic(FLUX_CHAR_UUID); } return fluxCapacitorControlPoint != null; } @Override protected void initialize() { // Initialize your device. // This means e.g. enabling notifications, setting notification callbacks, or writing // something to a Control Point characteristic. // Kotlin projects should not use suspend methods here, as this method does not suspend. requestMtu(517) .enqueue(); } @Override protected void onServicesInvalidated() { // This method is called when the services get invalidated, i.e. when the device // disconnects. // References to characteristics should be nullified here. fluxCapacitorControlPoint = null; } // ==== Public API ==== // Here you may add some high level methods for your device: public void enableFluxCapacitor() { // Do the magic. writeCharacteristic(fluxCapacitorControlPoint, Flux.enable(), BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) .enqueue(); } } ``` -------------------------------- ### Migrate initGatt to initialize Source: https://github.com/nordicsemi/android-ble-library/blob/main/MIGRATION.md Replace the old `initGatt(BluetoothGatt)` method with the new `initialize()` method. Remember to call `.enqueue()` for initialization requests. ```java protected Deque initGatt(final BluetoothGatt gatt) { final LinkedList requests = new LinkedList<>(); requests.add(Request.newEnableNotificationsRequest(characteristic)); return requests; } ``` ```java protected void initialize() { setNotificationCallback(characteristic) .with(new DataReceivedCallback() { @Override public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { ... } }); enableNotifications(characteristic) .enqueue(); } ``` -------------------------------- ### Connecting to a BLE Device (Java) Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Demonstrates how to connect to a Bluetooth LE device using the BleManager in Java. It includes options for automatic retries, connection timeouts, auto-connect feature, preferred PHY, and callbacks for different stages of the connection process. ```APIDOC ## connect(bluetoothDevice) ### Description Connects to a Bluetooth LE device with configurable options. ### Method ```java connect(bluetoothDevice) ``` ### Parameters - **bluetoothDevice** (BluetoothDevice) - The device to connect to. ### Options - **retry(times, interval)**: Configures automatic retries for connection errors (e.g., error 133). - **times** (int): Number of retries. - **interval** (long): Interval between retries in milliseconds. - **timeout(timeoutMillis)**: Sets a connection timeout. This is in addition to the Android system's default connection timeout. - **timeoutMillis** (long): Timeout duration in milliseconds. - **useAutoConnect(enable)**: Enables or disables the auto-connect feature. - **enable** (boolean): True to enable auto-connect, false otherwise. - **usePreferredPhy(phyMask)**: Selects the preferred PHY (Physical Layer) for the connection. Only used on Android 8+ devices with PHY support. - **phyMask** (int): A bitmask of PHY types (e.g., `PhyRequest.PHY_LE_1M_MASK | PhyRequest.PHY_LE_2M_MASK | PhyRequest.PHY_LE_CODED_MASK`). ### Callbacks - **before(device -> ...)**: Called just before the connection request is executed. - **done(device -> ...)**: Called when the device has connected, required services are discovered, and initialization is complete. - **fail(device, status -> ...)**: Called when the connection request fails. - **then(device -> ...)**: Called when the connection request finishes, regardless of success or failure. ### Execution - **enqueue()**: Enqueues the connection request to be executed sequentially with other requests. ``` -------------------------------- ### Implement BleServerManager to Host a GATT Server Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Extend BleServerManager to create a local GATT server. Use initializeServer() to define services and characteristics. The server can then be opened and clients can connect to it. ```java class MyBleServerManager extends BleServerManager { private static final UUID MY_SERVICE_UUID = UUID.fromString("AAAAAAAA-0000-1000-8000-00805f9b34fb"); private static final UUID DATA_CHAR_UUID = UUID.fromString("AAAAAAAA-0001-1000-8000-00805f9b34fb"); BluetoothGattCharacteristic dataCharacteristic; public MyBleServerManager(@NonNull Context context) { super(context); } @Override protected List initializeServer() { BluetoothGattCharacteristic dataChr = new BluetoothGattCharacteristic( DATA_CHAR_UUID, BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ ); // Add CCCD descriptor to allow clients to subscribe dataChr.addDescriptor(new BluetoothGattDescriptor( UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"), BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE )); dataCharacteristic = dataChr; BluetoothGattService service = new BluetoothGattService( MY_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY ); service.addCharacteristic(dataChr); return Collections.singletonList(service); } @Override public void log(int priority, @NonNull String message) { Log.println(priority, "BleServer", message); } } ``` ```java MyBleServerManager serverManager = new MyBleServerManager(context); serverManager.setServerObserver(new ServerObserver() { @Override public void onServerReady() { Log.i(TAG, "GATT server ready"); } @Override public void onDeviceConnectedToServer(@NonNull BluetoothDevice device) { // Create a manager for this specific client MyBleManager clientManager = new MyBleManager(context); clientManager.useServer(serverManager); clientManager.attachClientConnection(device); } @Override public void onDeviceDisconnectedFromServer(@NonNull BluetoothDevice device) { Log.i(TAG, "Client disconnected: " + device.getAddress()); } }); boolean started = serverManager.open(); Log.i(TAG, "Server started: " + started); // Send a notification to a connected client: // sendNotification(serverManager.dataCharacteristic, "Hello".getBytes()).enqueue(); ``` -------------------------------- ### Importing BLE Library as a Module Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Instructions for cloning the library and including it as a module in your project's settings.gradle. ```groovy if (file('../Android-BLE-Library').exists()) { includeBuild('../Android-BLE-Library') } ``` -------------------------------- ### Connecting to a BLE Device (Kotlin) Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Shows how to connect to a Bluetooth LE device using the BleManager with Kotlin extensions. Utilizes suspending functions for asynchronous operations. ```APIDOC ## connect(bluetoothDevice) (Kotlin Extensions) ### Description Connects to a Bluetooth LE device using Kotlin extensions, providing suspending functions for easier asynchronous handling. ### Method ```kotlin connect(bluetoothDevice) ``` ### Parameters - **bluetoothDevice** (BluetoothDevice) - The device to connect to. ### Options - **retry(times, interval)**: Configures automatic retries for connection errors. - **times** (Int): Number of retries. - **interval** (Long): Interval between retries in milliseconds. - **timeout(timeoutMillis)**: Sets a connection timeout. - **timeoutMillis** (Long): Timeout duration in milliseconds. - **useAutoConnect(enable)**: Enables or disables the auto-connect feature. - **enable** (Boolean): True to enable auto-connect, false otherwise. - **usePreferredPhy(phyMask)**: Selects the preferred PHY for the connection. - **phyMask** (Int): A bitmask of PHY types. ### Execution - **suspend()**: Suspends the coroutine until the connection and initialization are complete. Callbacks like `before()`, `done()`, `fail()`, etc., are not used when `suspend()` is called; instead, place code before or after the suspending call. ``` -------------------------------- ### Quick Migration: Extend LegacyBleManager Source: https://github.com/nordicsemi/android-ble-library/blob/main/MIGRATION.md For a rapid transition from version 2.1 to 2.2, extend `LegacyBleManager` and ensure `getGattCallback()` returns a non-null object. This approach uses deprecated APIs for a faster, albeit temporary, solution. ```java class MyBleManager extends LegacyBleManager { // [...] @NonNull @Override protected BleManagerGattCallback getGattCallback() { // Before 2.2 it was allowed to return a class property here, but properties are initiated // after the constructor, so they would still be null here. Instead, create a new object: return new MyBleManagerGattCallback(); } // [...] } ``` -------------------------------- ### Connect to BLE Device (Java) Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Initiates a connection to a BluetoothDevice with configurable retries, timeouts, and PHY settings. The `done` callback is invoked upon successful connection and initialization. ```java MyBleManager manager = new MyBleManager(context); manager.connect(bluetoothDevice) .retry(3, 100 /* ms between retries */) .timeout(15_000 /* ms, additional to Android's 30-second system timeout */) .useAutoConnect(false) .usePreferredPhy(PhyRequest.PHY_LE_1M_MASK | PhyRequest.PHY_LE_2M_MASK) .before(device -> Log.d(TAG, "Connecting to " + device.getAddress())) .done(device -> Log.i(TAG, "Device ready: " + device.getName())) .fail((device, status) -> { // status: GattError constant, e.g. 133 = GATT_ERROR Log.e(TAG, "Connection failed, status: " + status); }) .then(device -> Log.d(TAG, "Request finished (success or fail)")) .enqueue(); ``` -------------------------------- ### Connection and Bonding State as Flow in Kotlin Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Connection and bonding states are now available as Kotlin Flows, providing a reactive way to observe the device's connection status. ```kotlin Connection and bonding state available as Flow ``` -------------------------------- ### Set Indication Callback and Enable Indications (Java) Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Sets a callback for indications and then enables them for a characteristic. Indications require client acknowledgment. ```java @Override protected void initialize() { setIndicationCallback(serviceChangedCharacteristic) .with((device, data) -> Log.i(TAG, "Service changed indication received")); enableIndications(serviceChangedCharacteristic) .fail((device, status) -> Log.w(TAG, "Failed to enable indications: " + status)) .enqueue(); } ``` -------------------------------- ### Connect to BLE Device (Java) Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Connect to a BLE device with options for retries, timeouts, auto-connect, and preferred PHY. Callbacks are provided for different stages of the connection process. Requests must be enqueued. ```java connect(bluetoothDevice) // Automatic retries are supported, in case of 133 error. .retry(3 /* times, with */, 100 /* ms interval */) // A connection timeout can be set. This is additional to the Android's connection timeout which is 30 seconds. .timeout(15_000 /* ms */) // The auto connect feature from connectGatt is available as well .useAutoConnect(true) // This API can be set on any Android version, but will only be used on devices running Android 8+ with // support to the selected PHY. .usePreferredPhy(PhyRequest.PHY_LE_1M_MASK | PhyRequest.PHY_LE_2M_MASK | PhyRequest.PHY_LE_CODED_MASK) // A connection timeout can be also set. This is additional to the Android's connection timeout which is 30 seconds. .timeout(15_000 /* ms */) // Each request has number of callbacks called in different situations: .before(device -> { /* called when the request is about to be executed */ }) .done(device -> { /* called when the device has connected, has required services and has been initialized */ }) .fail(device, status -> { /* called when the request has failed */ }) .then(device -> { /* called when the request was finished with either success, or a failure */ }) // Each request must be enqueued. // Kotlin projects can use suspend() or suspendForResult() instead. // Java projects can also use await() which is blocking. .enqueue() ``` -------------------------------- ### Reading with Progress Flow Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Demonstrates reading from a characteristic and obtaining progress updates as a Kotlin Flow. ```APIDOC ## Reading with Progress Flow ### Description This operation reads data from a BLE characteristic and provides progress updates as a Kotlin Flow. It supports custom merging of incoming data. ### Method `readCharacteristic` followed by `.mergeWithProgressAsFlow()` ### Parameters - `someCharacteristic` (BluetoothGattCharacteristic): The characteristic to read from. - `customMerger` (DataMerger): Optional custom merger for incoming data. ### Request Example ```kotlin // Kotlin projects can use .mergeWithProgressAsFlow(customMerger) to get the progress as Flow. val progressFlow = readCharacteristic(someCharacteristic).mergeWithProgressAsFlow(customMerger) ``` ### Response - `Flow`: A Kotlin Flow emitting progress updates. ``` -------------------------------- ### connect() - Kotlin Coroutines (ble-ktx) Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Connects to a device using Kotlin Coroutines. The '.suspend()' function waits for the full connection and initialization sequence. Exceptions are mapped to typed BLE exceptions. ```APIDOC ## connect() with Kotlin Coroutines ### Description Connects to a device using Kotlin Coroutines. The '.suspend()' function waits for the full connection and initialization sequence. Exceptions are mapped to typed BLE exceptions. ### Method Signature `suspend()` (called on the ConnectRequest object) ### Request Example (Kotlin) ```kotlin class MyViewModel(context: Application) : AndroidViewModel(context) { private val manager = MyBleManager(context) fun connect(device: BluetoothDevice) = viewModelScope.launch { try { manager.connect(device) .retry(3, 100) .timeout(15_000) .useAutoConnect(false) .suspend() // suspends until device is ready Log.i(TAG, "Device ready: ${device.name}") } catch (e: DeviceDisconnectedException) { Log.e(TAG, "Device disconnected during connection") } catch (e: RequestFailedException) { Log.e(TAG, "Connection failed with status: ${e.status}") } catch (e: BluetoothDisabledException) { Log.e(TAG, "Bluetooth is disabled") } } } ``` ``` -------------------------------- ### Connection and Bonding State as Flow Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Exposes connection and bonding states as Kotlin `Flow`s, allowing for reactive observation of device status changes. Multiple calls to these methods return the same shared flow instance. ```APIDOC ## stateAsFlow() / bondingStateAsFlow() ### Description Observe connection and bonding state changes as Kotlin `Flow`s. Multiple calls return the same shared flow instance. ### Methods `stateAsFlow()`: Returns a `Flow`. `bondingStateAsFlow()`: Returns a `Flow`. ### Parameters None ### Request Example (Kotlin) ```kotlin class DeviceViewModel(app: Application) : AndroidViewModel(app) { val manager = MyBleManager(app) // Emits: Disconnected → Connecting → Initializing → Ready val connectionState: Flow = manager.stateAsFlow() // Emits: NotBonded → Bonding → Bonded val bondState: Flow = manager.bondingStateAsFlow() init { viewModelScope.launch { connectionState.collect { state -> when (state) { is ConnectionState.Ready -> Log.i(TAG, "Device ready") is ConnectionState.Disconnected -> Log.w(TAG, "Disconnected: ${state.reason}") else -> Log.d(TAG, "State: $state") } } } } } ``` ### Response #### Success Response These methods return Kotlin `Flow` objects that emit the respective state changes (`ConnectionState` or `BondState`). #### Response Example See Request Example for usage within a ViewModel. ``` -------------------------------- ### Implement Heart Rate Measurement Callback (BLE Library) Source: https://github.com/nordicsemi/android-ble-library/blob/main/BLE-COMMON.md This code shows how to implement a data received callback for the Heart Rate Measurement characteristic using the base BLE Library. Manual parsing of flags and data is required. ```java class HrmBleManager extends BleManager { // [...] @NonNull @Override protected BleManagerGattCallback getGattCallback() { return new HrmBleManagerGattCallbacks(); } private class HrmBleManagerGattCallbacks extends BleManagerGattCallbacks { @Override protected void initialize() { // ... setNotificationCallback(heartRateCharacteristic) .with(new DataReceivedCallback() { @Override void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { // Read flags final int flags = data.getIntValue(Data.FORMAT_UINT8, 0); final int hearRateType = (flags & 0x01) == 0 ? Data.FORMAT_UINT8 : Data.FORMAT_UINT16; final int sensorContactStatus = (flags & 0x06) >> 1; // Parsing and validation skipped // [...] // Show received data to the user... } }); enableNotifications(heartRateCharacteristic).enqueue(); } // [...] } } ``` -------------------------------- ### State and Bonding State as Flow in BleManager Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md The `.stateAsFlow()` and `.bondingStateAsFlow()` methods in `BleManager` now return the same Flow instance when called multiple times, ensuring consistent state observation. ```kotlin .stateAsFlow() .bondingStateAsFlow() ``` -------------------------------- ### Observe Connection and Bonding State as Kotlin Flows Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Expose BLE connection and bonding states as Kotlin `Flow`s for reactive observation. Multiple calls to `stateAsFlow()` or `bondingStateAsFlow()` return the same shared flow instance, simplifying state management in Android applications. ```kotlin class DeviceViewModel(app: Application) : AndroidViewModel(app) { val manager = MyBleManager(app) // Emits: Disconnected → Connecting → Initializing → Ready val connectionState: Flow = manager.stateAsFlow() // Emits: NotBonded → Bonding → Bonded val bondState: Flow = manager.bondingStateAsFlow() init { viewModelScope.launch { connectionState.collect { state -> when (state) { is ConnectionState.Ready -> Log.i(TAG, "Device ready") is ConnectionState.Disconnected -> Log.w(TAG, "Disconnected: ${state.reason}") else -> Log.d(TAG, "State: $state") } } } } } ``` -------------------------------- ### Writing to a BLE Characteristic (Kotlin) Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Demonstrates writing data to a BLE characteristic in Kotlin using extension functions, including options for data splitting. ```APIDOC ## writeCharacteristic(characteristic, data, writeType) (Kotlin Extensions) ### Description Writes data to a Bluetooth LE characteristic using Kotlin extensions. ### Method ```kotlin writeCharacteristic(someCharacteristic, someData, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) ``` ### Parameters - **characteristic** (BluetoothGattCharacteristic) - The characteristic to write to. - **data** (ByteArray) - The data to be written. - **writeType** (Int) - The type of write operation. ### Options - **split(splitter, progressCallback)**: Enables automatic splitting of outgoing data. For progress reporting as a Flow, use `splitWithProgressAsFlow()`. - **splitter**: A custom splitter implementation. - **progressCallback** (optional): A callback to report progress during splitting. ``` -------------------------------- ### Set Notification Callback and Enable Notifications (Java) Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Sets a callback to handle incoming notification data and then enables notifications for a characteristic. Requires manual parsing of raw bytes. ```java // Java - set callback before enabling notifications inside initialize() @Override protected void initialize() { setNotificationCallback(heartRateCharacteristic) .with((device, data) -> { // Parse raw bytes manually or use ble-common HeartRateMeasurementDataCallback int flags = data.getIntValue(Data.FORMAT_UINT8, 0); int hrFormat = (flags & 0x01) == 0 ? Data.FORMAT_UINT8_LE : Data.FORMAT_UINT16_LE; Integer hr = data.getIntValue(hrFormat, 1); Log.i(TAG, "Heart rate: " + hr + " bpm"); }); enableNotifications(heartRateCharacteristic) .done(d -> Log.i(TAG, "Subscribed to HR notifications")) .fail((d, s) -> Log.e(TAG, "Subscription failed: " + s)) .enqueue(); } ``` -------------------------------- ### Configure Java Compatibility for Module Import Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Ensure your build.gradle includes this configuration for Java 1.17 compatibility when importing the library as a module. ```groovy compileOptions { sourceCompatibility JavaVersion.VERSION_1_17 targetCompatibility JavaVersion.VERSION_1_17 } // For Kotlin projects additionally: kotlinOptions { jvmTarget = "1.17" } ``` -------------------------------- ### Progress Indications for Data Transfer in Kotlin Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Observe progress for split outgoing data and merged incoming data using Flows with `splitWithProgressFlow(...)` and `mergeWithProgressFlow(...)` in `:ble-ktx`. ```kotlin splitWithProgressFlow(...) mergeWithProgressFlow(...) ``` -------------------------------- ### Connect to BLE Device (Kotlin) Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Connect to a BLE device using Kotlin extensions, supporting retries, timeouts, auto-connect, and preferred PHY. The suspend() method can be used to pause execution until connection and initialization are complete. ```kotlin connect(bluetoothDevice) // Automatic retries are supported, in case of 133 error. .retry(3 /* times, with */, 100 /* ms interval */) // A connection timeout can be set. This is additional to the Android's connection timeout which is 30 seconds. .timeout(15_000 /* ms */) // The auto connect feature from connectGatt is available as well .useAutoConnect(true) // This API can be set on any Android version, but will only be used on devices running Android 8+ with // support to the selected PHY. .usePreferredPhy(PhyRequest.PHY_LE_1M_MASK | PhyRequest.PHY_LE_2M_MASK | PhyRequest.PHY_LE_CODED_MASK) // A connection timeout can be also set. This is additional to the Android's connection timeout which is 30 seconds. .timeout(15_000 /* ms */) // To suspend until the connection AND initialization is complete, call suspend(). .suspend() ``` -------------------------------- ### connect() - Java API Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Connects to a BluetoothDevice and returns a ConnectRequest. This request supports retries, timeouts, PHY selection, and auto-connect. The 'done' callback is triggered after successful connection and initialization. ```APIDOC ## connect(BluetoothDevice) ### Description Connects to a BluetoothDevice and returns a ConnectRequest. This request supports retries, timeouts, PHY selection, and auto-connect. The 'done' callback is triggered after successful connection and initialization. ### Method Signature `ConnectRequest connect(BluetoothDevice)` ### Parameters - **bluetoothDevice** (BluetoothDevice) - The device to connect to. ### Request Example (Java) ```java MyBleManager manager = new MyBleManager(context); manager.connect(bluetoothDevice) .retry(3, 100 /* ms between retries */) .timeout(15_000 /* ms, additional to Android's 30-second system timeout */) .useAutoConnect(false) .usePreferredPhy(PhyRequest.PHY_LE_1M_MASK | PhyRequest.PHY_LE_2M_MASK) .before(device -> Log.d(TAG, "Connecting to " + device.getAddress())) .done(device -> Log.i(TAG, "Device ready: " + device.getName())) .fail((device, status) -> { // status: GattError constant, e.g. 133 = GATT_ERROR Log.e(TAG, "Connection failed, status: " + status); }) .then(device -> Log.d(TAG, "Request finished (success or fail)")) .enqueue(); ``` ``` -------------------------------- ### Migrate :ble-livedata to Java with API Changes Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md The `:ble-livedata` module has been migrated to Java, resulting in some API changes due to the unavailability of sealed classes in Java. ```java :ble-livedata migrated to Java ``` -------------------------------- ### Register Custom Connection and Bonding Observers Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Implement `ConnectionObserver` and `BondingObserver` to receive typed lifecycle events outside of `LiveData` or `Flow`. Handle specific reasons for disconnection, such as link loss. ```java manager.setConnectionObserver(new ConnectionObserver() { @Override public void onDeviceConnecting(@NonNull BluetoothDevice device) { /* ... */ } @Override public void onDeviceConnected(@NonNull BluetoothDevice device) { /* ... */ } @Override public void onDeviceFailedToConnect(@NonNull BluetoothDevice device, int reason) { Log.e(TAG, "Failed: " + GattError.parse(reason)); } @Override public void onDeviceReady(@NonNull BluetoothDevice device) { Log.i(TAG, "Ready: " + device.getName()); } @Override public void onDeviceDisconnecting(@NonNull BluetoothDevice device) { /* ... */ } @Override public void onDeviceDisconnected(@NonNull BluetoothDevice device, int reason) { if (reason == ConnectionObserver.REASON_LINK_LOSS) { Log.w(TAG, "Link loss detected — reconnect if needed"); } } }); manager.setBondingObserver(new BondingObserver() { @Override public void onBondingRequired(@NonNull BluetoothDevice device) { Log.i(TAG, "Bonding..."); } @Override public void onBonded(@NonNull BluetoothDevice device) { Log.i(TAG, "Bonded!"); } @Override public void onBondingFailed(@NonNull BluetoothDevice device) { Log.e(TAG, "Bond failed"); } }); ``` -------------------------------- ### Manage Device Bonding Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Handle device pairing and bonding. `ensureBond()` guarantees an encrypted link by forcing re-bonding if necessary, recommended for sensitive data. `removeBond()` deletes existing bond information. ```java // Ensure bond AND link encryption (recommended for sensitive data) ensureBond() .done(device -> Log.i(TAG, "Bonded and link encrypted")) .fail((device, status) -> Log.e(TAG, "Bonding failed: " + status)) .enqueue(); // Remove existing bond information from Android removeBond() .done(device -> Log.i(TAG, "Bond removed, device will disconnect")) .enqueue(); ``` -------------------------------- ### Data Provider for Server-Side Read Requests Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md A data provider has been added for server-side read requests, enabling custom data retrieval logic when the device acts as a server. ```java Data provider for read requests (server side) ``` -------------------------------- ### Request High and Balanced Connection Priority (Java) Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Requests a high connection priority for low-latency transfers, then returns to a balanced priority after the transfer is complete. ```java // Request high priority (low latency) for time-sensitive transfers requestConnectionPriority(ConnectionPriorityRequest.CONNECTION_PRIORITY_HIGH) .done(d -> Log.i(TAG, "High priority connection set")) .enqueue(); // Return to balanced priority after transfer requestConnectionPriority(ConnectionPriorityRequest.CONNECTION_PRIORITY_BALANCED) .enqueue(); ``` -------------------------------- ### Add BLE Library with Common Parsers Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Use this dependency to add the BLE library with parsers for common Bluetooth SIG characteristics. ```groovy implementation 'no.nordicsemi.android:ble-common:2.11.0' ``` -------------------------------- ### Implement Heart Rate Measurement Callback (Common Library) Source: https://github.com/nordicsemi/android-ble-library/blob/main/BLE-COMMON.md This code demonstrates using the HeartRateMeasurementDataCallback from the common library to simplify parsing of Heart Rate Measurement characteristic data. It abstracts away flag parsing and provides direct values for heart rate, contact status, energy expanded, and RR intervals. ```java class HrmBleManager extends BleManager { // [...] @NonNull @Override protected BleManagerGattCallback getGattCallback() { return new HrmBleManagerGattCallbacks(); } private class HrmBleManagerGattCallbacks extends BleManagerGattCallbacks { @Override protected void initialize() { // ... setNotificationCallback(heartRateCharacteristic) .with(new HeartRateMeasurementDataCallback() { @Override public void onHeartRateMeasurementReceived(@NonNull final BluetoothDevice device, @IntRange(from = 0) final int heartRate, @Nullable final Boolean contactDetected, @Nullable final Integer energyExpanded, @Nullable final List rrIntervals) { // Show received data to the user... } @Override public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { // [...] } }); enableNotifications(heartRateCharacteristic).enqueue(); } // [...] } } ``` -------------------------------- ### Attach Client Connection for Server-Only Mode Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md To use the device as a server-only, call `attachClientConnection(BluetoothDevice)` instead of `connect(BluetoothDevice)`. This is useful for specific server implementations. ```java attachClientConnection(BluetoothDevice) ``` -------------------------------- ### Writing to a Characteristic Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Demonstrates how to write data to a BLE characteristic. It shows the use of `.suspend()` for asynchronous operations and exception handling. ```APIDOC ## Writing to a Characteristic ### Description This operation writes data to a BLE characteristic. It supports automatic splitting of outgoing data using a default or custom splitter and requires suspending the operation for completion. ### Method `writeCharacteristic` followed by `.split()` and `.suspend()` ### Parameters - `someCharacteristic` (BluetoothGattCharacteristic): The characteristic to write to. - `someData` (ByteArray): The data to be written. - `BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE` (Int): The write type. - `customSplitter` (DataSplitter): Optional custom splitter for outgoing data. - `progressCallback` (ProgressCallback): Optional callback for progress updates. ### Request Example ```kotlin try { writeCharacteristic(someCharacteristic, someData, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) .split(customSplitter, progressCallback) .suspend() } catch (e: Exception) { handleException(e) } ``` ### Response This operation does not return a specific response object upon successful completion, but exceptions are thrown on failure. ``` -------------------------------- ### Reading from a Characteristic Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Illustrates how to read data from a BLE characteristic. It includes options for merging incoming data, filtering, and suspending for a response. ```APIDOC ## Reading from a Characteristic ### Description This operation reads data from a BLE characteristic. It supports automatic merging of incoming data, filtering of raw data packets, and filtering of complete packets. The operation is suspended until a response is received. ### Method `readCharacteristic` followed by `.merge()`, `.filter()`, `.filterPacket()`, and `.suspendForResponse()` ### Parameters - `someCharacteristic` (BluetoothGattCharacteristic): The characteristic to read from. - `customMerger` (DataMerger): Optional custom merger for incoming data. - `progressCallback` (ProgressCallback): Optional callback for progress updates during merging. - `dataFilter` (DataFilter): Optional filter for incoming data packets. - `packetFilter` (PacketFilter): Optional filter for complete data packets. ### Request Example ```kotlin val response: MyResponse = readCharacteristic(someCharacteristic) .merge(customMerger, progressCallback) .filter(dataFilter) .filterPacket(packetFilter) .suspendForResponse() ``` ### Response - `MyResponse` (MyResponse): The response object containing the merged and filtered data. ``` -------------------------------- ### Reading from a BLE Characteristic (Java) Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Explains how to read data from a Bluetooth LE characteristic using the BleManager in Java. Features automatic data merging, filtering, and callbacks. ```APIDOC ## readCharacteristic(characteristic) ### Description Reads data from a specified Bluetooth LE characteristic. ### Method ```java readCharacteristic(someCharacteristic) ``` ### Parameters - **characteristic** (BluetoothGattCharacteristic) - The characteristic to read from. ### Options - **merge(merger, progressCallback)**: Enables automatic merging of incoming data. If no merger is provided, the default merger is used. - **merger**: A custom merger implementation. - **progressCallback** (optional): A callback to report progress during merging. - **filter(dataFilter)**: Filters incoming raw data packets before they are passed to the merger. - **dataFilter**: A filter function for raw data. - **filterPacket(packetFilter)**: Filters complete, merged data packets. - **packetFilter**: A filter function for merged packets. ### Callbacks - **with((device, data) -> ...)**: Called when data has been received. ### Execution - **enqueue()**: Enqueues the read request. ``` -------------------------------- ### Asynchronous connect and disconnect calls Source: https://github.com/nordicsemi/android-ble-library/blob/main/MIGRATION.md For asynchronous use, the `connect()` and `disconnect()` methods now require calling `.enqueue()`. ```java connect(device).useAutConnect(true).enqueue()/await() ``` -------------------------------- ### User Callbacks Wrapped in Try-Catch Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md All user callbacks (e.g., `before`, `with`, `then`, `fail`) are now automatically wrapped in try-catch blocks to prevent unexpected crashes due to errors in user-provided code. ```java try-catch blocks ``` -------------------------------- ### PHY Management Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Allows setting preferred PHY for a connection (1M, 2M, or Coded) and reading the active PHY. Requires Android 8.0 (Oreo) or higher. ```APIDOC ## setPhy() / readPhy() ### Description Set the preferred PHY for a connection (1M, 2M, or Coded) and read back the active PHY. ### Method `setPhy(int txPhy, int rxPhy, int phyOptions)` `readPhy()` ### Parameters for setPhy #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example (Java) ```java // Set preferred PHY to 2M for higher throughput (Android Oreo+) setPhy(PhyRequest.PHY_LE_2M_MASK, PhyRequest.PHY_LE_2M_MASK, PhyRequest.PHY_OPTION_NO_PREFERRED) .with((device, txPhy, rxPhy) -> Log.i(TAG, "PHY updated: TX=" + txPhy + " RX=" + rxPhy)) .fail((device, status) -> Log.w(TAG, "PHY set failed: " + status)) .enqueue(); // Read the current PHY readPhy() .with((device, txPhy, rxPhy) -> Log.i(TAG, "Current PHY: TX=" + txPhy + " RX=" + rxPhy)) .enqueue(); ``` ### Response #### Success Response Callbacks provide the device, TX PHY, and RX PHY values. #### Response Example See Request Example for callback usage. ``` -------------------------------- ### Add BLE Library with Kotlin Extensions Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Include this dependency for BLE library support with Kotlin extensions, offering coroutines and Flow. ```groovy implementation 'no.nordicsemi.android:ble-ktx:2.11.0' ``` -------------------------------- ### Connect with Kotlin Coroutines (ble-ktx) Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Connects to a BluetoothDevice using Kotlin Coroutines, suspending until the device is ready. Handles various BLE exceptions like disconnection, request failures, and Bluetooth being disabled. ```kotlin class MyViewModel(context: Application) : AndroidViewModel(context) { private val manager = MyBleManager(context) fun connect(device: BluetoothDevice) = viewModelScope.launch { try { manager.connect(device) .retry(3, 100) .timeout(15_000) .useAutoConnect(false) .suspend() // suspends until device is ready Log.i(TAG, "Device ready: ${device.name}") } catch (e: DeviceDisconnectedException) { Log.e(TAG, "Device disconnected during connection") } catch (e: RequestFailedException) { Log.e(TAG, "Connection failed with status: ${e.status}") } catch (e: BluetoothDisabledException) { Log.e(TAG, "Bluetooth is disabled") } } } ``` -------------------------------- ### Filter Logs by Priority Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Logs can be filtered by priority. By default, only logs with `Log.INFO` or higher are shown. Use `getMinLogPriority()` to adjust this. Lower priority logs are not produced to improve performance. ```java getMinLogPriority() ``` -------------------------------- ### Bonding Management Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Provides methods to manage device pairing, including ensuring a secure bond with link encryption or creating an insecure bond, and removing existing bond information. ```APIDOC ## createBondInsecure() / ensureBond() / removeBond() ### Description Manage device pairing. Use `ensureBond()` to guarantee the link is encrypted (forces re-bonding if needed), or `createBondInsecure()` for a faster bond that only checks local Android bond state. ### Methods `ensureBond()` `createBondInsecure()` `removeBond()` ### Parameters None for these methods directly. ### Request Example (Java) ```java // Ensure bond AND link encryption (recommended for sensitive data) ensureBond() .done(device -> Log.i(TAG, "Bonded and link encrypted")) .fail((device, status) -> Log.e(TAG, "Bonding failed: " + status)) .enqueue(); // Remove existing bond information from Android removeBond() .done(device -> Log.i(TAG, "Bond removed, device will disconnect")) .enqueue(); ``` ### Response #### Success Response Callbacks provide the bonded or removed device. #### Response Example See Request Example for callback usage. ``` -------------------------------- ### Add BLE Library Dependency Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Add this dependency to your project's build.gradle file to include the main BLE library. ```groovy implementation 'no.nordicsemi.android:ble:2.11.0' ``` -------------------------------- ### Writing to a Characteristic with Response Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Shows how to write data to a BLE characteristic and wait for a response. It utilizes `.suspendForResponse()` for this purpose. ```APIDOC ## Writing to a Characteristic with Response ### Description This operation writes data to a BLE characteristic and waits for a response. It supports automatic splitting of outgoing data and requires suspending the operation for a response. ### Method `writeCharacteristic` followed by `.split()` and `.suspendForResponse()` ### Parameters - `someCharacteristic` (BluetoothGattCharacteristic): The characteristic to write to. - `someData` (ByteArray): The data to be written. - `BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE` (Int): The write type. - `customSplitter` (DataSplitter): Optional custom splitter for outgoing data. - `progressCallback` (ProgressCallback): Optional callback for progress updates. ### Request Example ```kotlin try { val request: MyRequest = writeCharacteristic(someCharacteristic, someData, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) .split(customSplitter, progressCallback) .suspendForResponse() } catch (e: Exception) { // The request has failed. } ``` ### Response - `MyRequest` (MyRequest): The response object received after the write operation. ``` -------------------------------- ### Add BLE Library with LiveData Extension Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md Integrate this dependency for an extension that provides LiveData support for BLE manager states. ```groovy implementation 'no.nordicsemi.android:ble-livedata:2.11.0' ``` -------------------------------- ### Support for onServicesChanged() Callback (API 31+) Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md The library now supports the `onServicesChanged()` callback, which was added in API 31 (Android 12), allowing handling of service discovery changes. ```java onServicesChanged() ``` -------------------------------- ### Proper Migration: Extend BleManager Source: https://github.com/nordicsemi/android-ble-library/blob/main/MIGRATION.md For a proper migration, remove the type parameter from your `BleManager` implementation class. This involves updating callback mechanisms and potentially using LiveData for state management. ```java class MyBleManager extends BleManager { // [...] } ``` -------------------------------- ### Add :ble-ktx Module for Coroutines and Flow Source: https://github.com/nordicsemi/android-ble-library/blob/main/README.md The new `:ble-ktx` module provides support for Kotlin coroutines and Flow, enabling more modern and reactive BLE interactions. ```kotlin :ble-ktx module ``` -------------------------------- ### Writing to a BLE Characteristic (Java) Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Details how to write data to a Bluetooth LE characteristic using the BleManager in Java. Supports automatic data splitting and various callbacks. ```APIDOC ## writeCharacteristic(characteristic, data, writeType) ### Description Writes data to a specified Bluetooth LE characteristic. ### Method ```java writeCharacteristic(someCharacteristic, someData, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) ``` ### Parameters - **characteristic** (BluetoothGattCharacteristic) - The characteristic to write to. - **data** (byte[]) - The data to be written. - **writeType** (int) - The type of write operation (e.g., `BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE`). ### Options - **split(splitter, progressCallback)**: Enables automatic splitting of outgoing data. If no splitter is provided, the default MTU splitter is used. - **splitter**: A custom splitter implementation. - **progressCallback** (optional): A callback to report progress during splitting. ### Callbacks - **before(device -> ...)**: Called just before the write request is executed. - **with((device, data) -> ...)**: Called when the write request has been executed. - **done(device -> ...)**: Called when the write operation completes successfully. - **fail(device, status -> ...)**: Called when the write operation fails. - **invalid(...)**: Called when the request is invalid (e.g., null device or characteristic). - **then(device -> ...)**: Called when the write operation finishes, regardless of success or failure. ### Execution - **enqueue()**: Enqueues the write request. ``` -------------------------------- ### Send Data with Automatic Splitting Source: https://github.com/nordicsemi/android-ble-library/blob/main/USAGE.md Use `.suspend()` to send data. The library automatically handles splitting data based on the MTU. Remember to call `suspend()` after setting up the request. ```kotlin try { val request: MyRequest = writeCharacteristic(someCharacteristic, someData, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) // Outgoing data can use automatic splitting. .split(customSplitter, progressCallback /* optional */) // .split() with no parameters uses the default MTU splitter. .suspend() doSomethingWith(dataSent) } catch (e: Exception) { // The request has failed. handleException(e) } ``` -------------------------------- ### Create an Atomic Request Queue Source: https://context7.com/nordicsemi/android-ble-library/llms.txt Group multiple BLE requests into a single atomic operation. If any request within the queue fails, the entire sequence is aborted, ensuring data integrity for critical write operations. ```java // Java — send a multi-step initialization atomically beginAtomicRequestQueue() .add(writeCharacteristic(configCharacteristic, Config.setMode(1), BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)) .add(writeCharacteristic(configCharacteristic, Config.setInterval(500), BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)) .add(writeCharacteristic(controlPoint, Commands.start(), BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)) .done(device -> Log.i(TAG, "Atomic sequence complete")) .fail((device, status) -> Log.e(TAG, "Atomic sequence failed: " + status)) .enqueue(); ```