Skip to content

Instantly share code, notes, and snippets.

@ElianFabian
Last active December 3, 2025 12:48
Show Gist options
  • Select an option

  • Save ElianFabian/12d97e2569bb2eb3c1f0f39bea5bc58c to your computer and use it in GitHub Desktop.

Select an option

Save ElianFabian/12d97e2569bb2eb3c1f0f39bea5bc58c to your computer and use it in GitHub Desktop.
Idea for an Android Bluetooth Classic library
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