ConnectionStateMachine

class ConnectionStateMachine(context: Context, device: BluetoothDevice, bondManager: BondManager? = null, autoReconnect: Boolean = true, reconnectDelayMs: Long = DEFAULT_RECONNECT_DELAY_MS, maxReconnectDelayMs: Long = DEFAULT_MAX_RECONNECT_DELAY_MS, maxReconnectAttempts: Int = DEFAULT_MAX_RECONNECT_ATTEMPTS, operationTimeoutMs: Long = DEFAULT_OPERATION_TIMEOUT_MS)

A finite state machine that manages Bluetooth Low Energy (BLE) connections and operations.

This class implements the State Machine pattern to handle the complex lifecycle of BLE connections, ensuring that operations are performed in the correct sequence and providing clear state transitions that can be observed via connectionStateFlow.

State Transitions

The state machine follows this primary flow:

[Disconnected] --> [Connecting] --> [Connected] --> [DiscoveringServices] --> [Ready]
^ |
| |
+--------------------------------------------------------------------------+
(on disconnect)
  • Disconnected: Initial state, or after a connection is closed/lost.

  • Connecting: Connection attempt is in progress via connect.

  • Connected: Physical connection established; automatically triggers service discovery.

  • DiscoveringServices: GATT service discovery is in progress (implicit during Connected -> Ready).

  • Ready: Services discovered successfully; the device is ready for read/write/notify operations.

  • Error: An error occurred; contains an error message. May trigger auto-reconnect if enabled.

Features

  • Automatic Reconnection: When autoReconnect is enabled, the state machine will automatically attempt to reconnect after a disconnection or error, with a configurable delay.

  • Operation Timeouts: All BLE operations (MTU requests, PHY updates, read/write) have configurable timeouts to prevent indefinite waiting.

  • Bond Management: Optional integration with BondManager for handling device pairing.

  • Reactive State Observation: Connection state changes are exposed via connectionStateFlow, allowing UI and other components to reactively observe state changes.

Thread Safety

BLE callbacks are dispatched on the Android Bluetooth thread. This class uses coroutines with Dispatchers.IO for timeout handling and reconnection scheduling.

Usage Example

val stateMachine = ConnectionStateMachine(
context = applicationContext,
device = bluetoothDevice,
autoReconnect = true
)

// Observe connection state
lifecycleScope.launch {
stateMachine.connectionStateFlow.collect { state ->
when (state) {
is ConnectionState.Ready -> { /* Device ready for operations */}
is ConnectionState.Error -> { /* Handle error */}
else -> { /* Handle other states */}
}
}
}

// Initiate connection
stateMachine.connect()

Parameters

context

The Android context used for GATT connection.

device

The BluetoothDevice to connect to.

bondManager

Optional BondManager for handling device bonding/pairing.

autoReconnect

If true, automatically attempts reconnection on disconnection or error. Defaults to true.

reconnectDelayMs

Base delay in milliseconds for exponential backoff reconnection. The actual delay increases exponentially with each attempt. Defaults to DEFAULT_RECONNECT_DELAY_MS (1000ms).

maxReconnectDelayMs

Maximum delay in milliseconds between reconnection attempts. The exponential backoff will be capped at this value. Defaults to DEFAULT_MAX_RECONNECT_DELAY_MS (30000ms).

maxReconnectAttempts

Maximum number of reconnection attempts before giving up. When this limit is reached, the state transitions to ConnectionState.Error. Defaults to DEFAULT_MAX_RECONNECT_ATTEMPTS (10).

operationTimeoutMs

Timeout in milliseconds for BLE operations (MTU, PHY, read, write). Defaults to DEFAULT_OPERATION_TIMEOUT_MS (10000ms).

See also

Constructors

Link copied to clipboard
constructor(context: Context, device: BluetoothDevice, bondManager: BondManager? = null, autoReconnect: Boolean = true, reconnectDelayMs: Long = DEFAULT_RECONNECT_DELAY_MS, maxReconnectDelayMs: Long = DEFAULT_MAX_RECONNECT_DELAY_MS, maxReconnectAttempts: Int = DEFAULT_MAX_RECONNECT_ATTEMPTS, operationTimeoutMs: Long = DEFAULT_OPERATION_TIMEOUT_MS)

Types

Link copied to clipboard
object Companion

Companion object containing default configuration values, standard BLE UUIDs, and the global service cache.

Properties

Link copied to clipboard

The underlying BluetoothGatt instance for this connection.

Link copied to clipboard

A StateFlow that emits the current ConnectionState of this state machine.

Functions

Link copied to clipboard
fun close()

Closes the GATT connection and releases all associated resources.

Link copied to clipboard
fun connect()

Initiates a connection to the Bluetooth device.

Link copied to clipboard
fun disableNotifications(serviceUuid: UUID, characteristicUuid: UUID, onComplete: (Int) -> Unit? = null)

Disables notifications for a GATT characteristic.

Link copied to clipboard

Gracefully disconnects from the Bluetooth device.

Link copied to clipboard
fun enableNotifications(serviceUuid: UUID, characteristicUuid: UUID, onNotification: (ByteArray) -> Unit, onComplete: (Int) -> Unit)

Enables notifications for a GATT characteristic.

Link copied to clipboard

Gets the list of cached GATT services for this device.

Link copied to clipboard

Checks whether services are cached for this device.

Link copied to clipboard
fun readCharacteristic(serviceUuid: UUID, characteristicUuid: UUID, callback: (Int, ByteArray?) -> Unit)

Reads the value of a GATT characteristic from the connected device.

Link copied to clipboard
fun requestMtu(mtu: Int, callback: (Int, Int) -> Unit)

Requests an MTU (Maximum Transmission Unit) change with timeout handling.

Link copied to clipboard

Resets the reconnect attempt counter to zero.

Link copied to clipboard
fun setPreferredPhy(txPhy: Int, rxPhy: Int, phyOptions: Int, callback: (Int, Int, Int) -> Unit)

Requests a PHY (Physical Layer) update with timeout handling.

Link copied to clipboard
fun writeCharacteristic(serviceUuid: UUID, characteristicUuid: UUID, value: ByteArray, callback: (Int) -> Unit)

Writes a value to a GATT characteristic on the connected device.

Link copied to clipboard
fun writeLongCharacteristic(serviceUuid: UUID, characteristicUuid: UUID, value: ByteArray, callback: (Int) -> Unit)

Writes a large value to a characteristic using sequential chunked writes.