Know when your cellular signal was jammed, not just lost.
An open-source Android app that detects active RF jamming of cellular bands — distinct from IMSI-catcher/fake-base-station attacks — by fusing on-device radio signals with local, serverless peer corroboration over Bluetooth. No backend, no telemetry, no account.
Cellular jammers block 3G/4G/5G broadband; 2.4GHz BLE/WiFi keeps working. That means offline-mesh apps stay usable through a jamming event — but only if you know it's happening and switch to one. A phone showing "no service" looks the same whether you're in a jammed zone or just standing in a basement.
Existing tools don't cover this. IMSI-catcher/StingRay detectors (AIMSICD, EFF Rayhunter) target a different attack — fake base stations, not RF jamming — and are largely unmaintained or need hardware/root access modern Android blocks. Generic consumer "jammer detector" apps exist but are closed-source and single-signal ("no bars = jammed"), which is indistinguishable from an ordinary dead zone.
Important: jamwarden reports a confidence tier, not a certainty. No detector running on non-rooted commodity hardware can distinguish a real jamming event from a sufficiently similar coincidental outage with 100% certainty — jamwarden says so, out loud, in the UI, rather than presenting a false binary "safe/jammed" signal.
Single-signal detection ("zero bars") is indistinguishable from walking into a basement, so jamwarden fuses five on-device signals, then checks for corroboration from nearby phones over a bare, unpaired BLE broadcast — no pairing, no identity, no relay, no server:
Monitor (TelephonyManager + WiFi/BLE)
│
▼
Abrupt signal drop across visible carriers
│
▼
Fuse: abruptness · breadth · neighbor-cell collapse · cross-radio contrast · baseline deviation
│
▼
Broadcast + listen for nearby peers ("lost cellular, just now")
│
▼
Confidence gate: local-only signals vs. corroborated by N nearby peers
│
▼
Confidence tier + plain-language reason ── never a bare "you are jammed" claim
│
▼
On-screen alert: calm styling at low confidence, distinct color/haptic at "likely active jamming"
The second screenshot's tier can't be produced organically on a bare emulator (no real jammer, no
real nearby BLE peer to corroborate), so it was captured via a debug-build-only test seam in
MainActivity that lets a debuggable build only render a forced ConfidenceTier from a launch
Intent extra — see the seam's doc comment in app/src/main/kotlin/dev/jamwarden/app/MainActivity.kt
for exactly how it's gated. It has no effect in a release build and makes no network call, same as
everywhere else in this app. Full Maestro E2E flows covering both screenshots, the Settings screen,
alert toggles, and baseline reset live in e2e/maestro/.
No server, no analytics SDK, no crash reporting service, no ad network, no network egress of any kind — the app should not link an HTTP client at all. Detection state and the on-device location-signal baseline never leave the phone, and the peer-corroboration broadcast is local radio range only, un-relayed, with no persistence beyond a short TTL. This is an architectural constraint, not a settings toggle.
Reading cell-tower info on Android 10+ requires ACCESS_FINE_LOCATION — a real tension for a tool
aimed at people who don't want to be tracked. jamwarden uses it only to compute a local
signal-quality baseline per location; that data is never logged to a shareable file, never
reverse-geocoded to a human-readable address, and never transmitted, because there is nowhere for
it to be transmitted to. You can view and wipe all locally-stored baseline data from inside the
app at any time.
Android only, for now. Android exposes real signal/cell telemetry
(TelephonyManager/CellInfo) to normal apps; iOS has sandboxed that away from third-party access
since iOS 13, so an iOS build could only ever offer a materially weaker "total service loss + peer
corroboration" signal. Rather than ship an iOS app that visually mirrors this one while silently
offering a fraction of its reliability, iOS support is deferred until it can be built and labeled
honestly.
jamwarden/
├── app/ Android application module (Kotlin, Jetpack Compose)
│ ├── src/main/kotlin/ Detection engine, BLE peer broadcast, Compose UI
│ └── src/test/kotlin/ Unit tests for the signal-fusion/confidence-tier logic
├── e2e/maestro/ Maestro E2E flows (cold launch, tiers, settings, baseline reset)
├── .github/
│ └── media/ README diagrams and screenshots
├── CONTRIBUTING.md
├── LICENSE
├── README.md
└── SECURITY.md
PRs and issues welcome — see CONTRIBUTING.md. Given the safety stakes, changes to the fusion/confidence-tier logic or anything touching permissions/network egress get an elevated review bar.
MIT — use this however you want, but this is a confidence signal, not a safety guarantee; verify it holds up for your own threat model before relying on it.

