Roadmap¶
This page is deliberately concrete about what exists today and what does not, including the parts that are blocked by the platform rather than by effort.
Shipped in 0.1.0¶
| Area | Status |
|---|---|
| Domain layer | Models, validation, MTU and retry policies, scan quota governor, connection and adapter state machines, error taxonomy — pure Kotlin, no Android imports |
| Permissions | Full matrix from Android 5 to 17, including denied vs never declared, neverForLocation support |
| Scanning | Legacy and extended scan settings, software fallback filters, presence tracking (Observed/Lost), scan quota with platform-throttle feedback, single-scan enforcement |
| Advertising | Legacy sets on API 21+, extended sets on API 26+, payload budget validation against the device maximum, discoverable flag on API 34+, cancellation-safe start |
| GATT client | Connect procedure with transport/auto-connect/opportunistic settings, Android 17 BluetoothGattConnectionSettings, MTU negotiation, connection priority (including DCK), PHY requests, profile discovery, reads/writes/long writes, descriptor access, subscriptions with automatic re-arming, one session per device |
| GATT server | Local services, automatic request answering with an autoRespond = false opt-out, CCCD tracking, long write prepare/execute, notifications and indications, MTU reporting |
| Bluetooth Classic | BR/EDR discovery with RSSI on API 30+, bonding with Android 16.1 bond-loss reasons and Android 17 autonomous re-pairing awareness, RFCOMM sockets, L2CAP channels, BluetoothSocketSettings on API 36+, Companion Device Manager based unbonding on API 36+ (the first release with a public removeBond) |
| Diagnostics | One event stream for operations, state changes, capability probes and errors, with platform status codes preserved |
| Testing | bluelib-testing fakes for every port, JVM tests for the domain and for the platform logic that is genuinely pure |
| Docs | This site, the generated compatibility matrix, the research notes and the ADR set |
Next¶
1. Ranging module (bluelib-ranging, API 36+)¶
Android 16 introduced the android.ranging module with Bluetooth Channel Sounding
(RangingManager, BleCsRangingParams) and RSSI ranging, guarded by android.permission.RANGING.
BlueLib currently reports the capability (LE_CHANNEL_SOUNDING, LE_RSSI_RANGING) so an application can
decide, but does not wrap the API yet.
What the module needs before it ships:
- a
RangingPortinbluelib-corewith aRangingResultmodel that does not leakandroid.rangingtypes; - capability gating through
PlatformReportplus theandroid.hardware.bluetooth.le.channel_soundingfeature flag, which some devices miss even on API 36; - a decision on result streaming: Channel Sounding produces distance, angle and quality per procedure, which is closer to a sampling API than to a request/response one;
- on-device tests with two devices that both support Channel Sounding — hard to run in CI, so the module would ship with a documented device matrix instead of a green CI badge.
2. LE Audio / Auracast module¶
Capability reporting is shipped. Controlling broadcasts is not, and the reason is a privilege boundary, not an API gap:
| Role | API | Privilege |
|---|---|---|
| Broadcast source (start an Auracast stream) | BluetoothLeBroadcast |
system app / privileged permission |
| Broadcast assistant (help a user join a broadcast) | BluetoothLeBroadcastAssistant |
system app / privileged permission |
| Capability queries | BluetoothAdapter.isLeAudio*Supported() |
none (Android 13+) |
Shipping a wrapper that cannot work for ordinary apps would be worse than not shipping one, so the plan is
a bluelib-auracast module that is explicit about its requirement: it either stays documentation-only for
third-party apps, or targets system-app builds with a clearly marked @RequiresSystemApp API.
3. Richer connection recovery¶
BlueLibConfig.reconnectPolicy exists and the state machine models RECONNECTING, but the library does
not yet own the reconnect loop. The next step is a ConnectionSupervisor that:
- retries with the configured backoff, respecting
isRetryable; - backs off harder on repeated status 133 and escalates to "close and reopen" rather than retrying forever;
- re-arms subscriptions after every successful reconnect (already implemented inside the session) and re-reads the characteristics an application declares as required.
4. Payload helpers¶
AdvertisingPayload validates sizes. The natural follow-up is a builder for the AD structures themselves
(flags, complete/partial UUID lists, local name, service data, manufacturer data) shared between
advertising and scan-result parsing, so applications can construct and inspect payloads with one API.
5. Sample applications¶
A peripheral app (advertising + GATT server) and a central app (scan + connect + subscribe) in one Compose project, used as the fixture for instrumentation tests and as the reference for the documentation.
Explicitly out of scope¶
| Idea | Why not |
|---|---|
| Clearing the GATT service cache on demand | BluetoothGatt.refresh() is hidden API; rediscovery after GATT_DATABASE_OUT_OF_SYNC is the supported path |
| Unbonding a device the app is not associated with | No public API exists; the user must forget it in system settings |
| Enabling Bluetooth programmatically | Deprecated and privileged; ACTION_REQUEST_ENABLE is the supported flow |
| Thread-safety guarantees beyond one platform thread | Android's Bluetooth stack does not offer them; pretending otherwise would be a lie in the type system |
| A cross-platform (non-Android) implementation | bluelib-core is portable by design, but a real KMP target is a project, not a feature |