Architecture - HmnDev-Tech/BLE-Droid GitHub Wiki
Architecture
Single-module Android app (app/), Kotlin + Jetpack Compose, version catalog in
gradle/libs.versions.toml.
app/src/main/java/com/bledroid/
BleDroidApp.kt Application entry
MainActivity.kt Compose host, nav stack
engine/BleAdvertiserEngine.kt advertise loop + radar scan + classifier
generators/ per-protocol payload builders
FastPairGenerator.kt service data 0xFE2C
AppleDevicePopupGenerator.kt mfr data 0x004C type 0x07
AppleActionModalGenerator.kt mfr data 0x004C type 0x0F
SamsungBudsGenerator.kt mfr data 0x0075
SamsungWatchGenerator.kt mfr data 0x0075 (watch)
SwiftPairGenerator.kt mfr data 0x0006
LovespouseGenerator.kt mfr data 0x00FF
SpamGenerator.kt Mix All: interleaves the above
helpers/HexUtils.kt hex encode/decode
models/Models.kt shared data classes
service/SpamForegroundService.kt foreground notification + control
ui/BleDroidViewModel.kt single ViewModel, app state
ui/components/Components.kt shared Compose components
ui/navigation/Routes.kt nav routes
ui/screens/ Dashboard, spam screens, CustomBle,
SpamRadar, Settings, MixAll
ui/theme/ Material 3 Expressive theme
Data flow
UI (Compose screen)
-> BleDroidViewModel
-> SpamForegroundService (when foreground service enabled)
-> BleAdvertiserEngine
-> generator (protocol payload)
-> BluetoothLeAdvertiser
<- scan callback -> classifier -> radar state -> SpamRadarScreen
- Engine owns the advertise loop (interval, TX power, packet counter) and the scan loop that classifies incoming advertisements by manufacturer ID and payload.
- Generators are pure functions: input = selected devices/preset, output = raw payload bytes. No Android APIs inside — easy to unit test.
- ViewModel is the single source of truth for UI state; the service publishes counters back to it.
Conventions
- Kotlin official style (ktlint defaults), no hardcoded strings in UI —
add them to
res/values/strings.xml. - State flows down, events flow up through the ViewModel.
- New protocol = new generator + registration in
SpamGenerator+ a screen/route.
See Contributing before opening a PR.