Last active
December 3, 2025 12:48
-
-
Save ElianFabian/12d97e2569bb2eb3c1f0f39bea5bc58c to your computer and use it in GitHub Desktop.
Idea for an Android Bluetooth Classic library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import kotlin.reflect.KClass | |
| import java.util.UUID | |
| // Definition of the BluetoothApi interface | |
| interface BluetoothApi { | |
| suspend fun getBatteryLevel(): Int | |
| suspend fun getAppVersion(): String | |
| // For all functions, when we try to send data, but there's no client socket or something went wrong | |
| // Then we could throw an exception or return an error result | |
| suspend fun sendMessage(message: String) | |
| fun observeLocation(): Flow<Location> | |
| } | |
| // Implementation of the BluetoothApi interface for the server side | |
| // here is where we would handle incoming Bluetooth connections and requests | |
| class BluetoothServer : BluetoothApi { | |
| override suspend fun getBatteryLevel(): Int { | |
| TODO("Not yet implemented") | |
| } | |
| override suspend fun getAppVersion(): String { | |
| TODO("Not yet implemented") | |
| } | |
| override suspend fun sendMessage(message: String) { | |
| TODO("Not yet implemented") | |
| } | |
| override fun observeLocation(): Flow<Location> { | |
| TODO("Not yet implemented") | |
| } | |
| } | |
| interface BluetoothHelper { | |
| val connectedDevices: StateFlow<List<BluetoothDevice>> | |
| val events: SharedFlow<Event> | |
| val bluetoothDeviceName: StateFlow<String?> | |
| val isBluetoothSupported: Boolean | |
| val canEnableBluetooth: Boolean | |
| val state: StateFlow<BluetoothState> | |
| val isScanning: StateFlow<Boolean> | |
| val isWaitingForConnection: StateFlow<Boolean> | |
| fun <T> getOrCreateBluetoothApiClient(deviceAddress: String): T? | |
| fun <T : Any> registerBluetoothApiServer(server: T) | |
| fun unregisterBluetoothApiServer(server: Any) | |
| suspend fun startBluetoothServer(): ConnectionResult | |
| suspend fun startInsecureBluetoothServer(): ConnectionResult | |
| fun stopBluetoothServer() | |
| suspend fun connectToDevice(address: String): ConnectionResult | |
| suspend fun connectToDeviceInsecurely(address: String): ConnectionResult | |
| suspend fun disconnectFromDevice(deviceAddress: String): Boolean | |
| suspend fun cancelConnectionAttempt(address: String): Boolean | |
| suspend fun sendDataToDevice(deviceAddress: String, data: ByteArray): Boolean | |
| fun observeDataFromDevice(deviceAddress: String): Flow<ByteArray> | |
| enum class BluetoothState { | |
| On, | |
| TurningOn, | |
| Off, | |
| TurningOff; | |
| val isOn: Boolean get() = this == On | |
| } | |
| sealed interface ConnectionResult { | |
| data class ConnectionEstablished(val device: BluetoothDevice) : ConnectionResult | |
| data object CouldNotConnect : ConnectionResult | |
| } | |
| sealed interface Event { | |
| data class OnDeviceConnected( | |
| val connectedDevice: BluetoothDevice, | |
| // This indicates whether you connected to a device as a server or intentionally chose which one to connect to | |
| val manuallyConnected: Boolean, | |
| ) : Event | |
| data class OnDeviceDisconnected( | |
| val disconnectedDevice: BluetoothDevice, | |
| // This indicates if was the current user who intentionally disconnected the device | |
| // In the case the user intentionally disconnects from the device but it was the other device | |
| // who disconnected from us it will count as not manually disconnected | |
| val manuallyDisconnected: Boolean, | |
| ) : Event | |
| } | |
| } | |
| interface BluetoothTypeSerializer<T> { | |
| val typeUuid: UUID | |
| fun serialize(outputStream: OutputStream, data: T) | |
| fun deserialize(inputStream: InputStream): T | |
| } | |
| object UuidBluetoothTypeSerializer : BluetoothTypeSerializer<UUID> { | |
| override val typeId: UUID = UUID.fromString("00000000-0000-0000-0000-000000000001") | |
| override fun serialize(data: UUID, outputStream: OutputStream) { | |
| val dataOutputStream = DataOutputStream(outputStream) | |
| dataOutputStream.writeLong(data.mostSignificantBits) | |
| dataOutputStream.writeLong(data.leastSignificantBits) | |
| } | |
| override fun deserialize(inputStream: InputStream): UUID { | |
| val dataInputStream = DataInputStream(inputStream) | |
| val mostSignificantBits = dataInputStream.readLong() | |
| val leastSignificantBits = dataInputStream.readLong() | |
| return UUID(mostSignificantBits, leastSignificantBits) | |
| } | |
| } | |
| // We could also implement interceptors | |
| suspend fun main() { | |
| // This represents the backend of another bluetooth device | |
| val bluetoothHelper: BluetoothHelper = TODO() | |
| val bluetoothApiClient: BluetoothApi = | |
| bluetoothHelper.getOrCreateBluetoothApiClient<BluetoothApi>(deviceAddress = "00:11:22:33:44:55") ?: error("Could not create Bluetooth API client.") | |
| val bluetoothServer = BluetoothServer() | |
| bluetoothHelper.registerBluetoothApiServer(bluetoothServer) | |
| bluetoothApiClient.sendMessage("Hello, Bluetooth Device!") | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment