Fully offline Android app that warns drivers when approaching AES/AWAS enforcement cameras in Malaysia - highway speed cameras and red-light junction cameras. Runs as a persistent foreground GPS service.
| Running on car head unit | Alert overlay |
|---|---|
![]() |
![]() |
| Dashboard — PASSED state | Dashboard — CLEAR (sim mode) |
![]() |
![]() |
- Real-time GPS tracking via foreground service
- Proximity detection using Haversine distance + bearing-aware directional filtering
- Full-screen alert overlay when approaching a camera - shows camera name, highway, distance, speed limit vs current speed
- Junction cameras (red light + speed) show a dedicated traffic-compliance warning
- Audio alert: 3-beep sequence on approach, silenced once passing
- Dashboard with large speed readout, GPS lock status, current area name, and next camera info
- 47 AES/AWAS cameras: 33 highway speed + 14 red-light junction sites (JPJ list 15.07.2024)
- Configurable alert distance (500 m - 5 km), per-camera mute, and per-category alert toggles
- In-app camera database browser with edit capability
- Now Playing bar showing current media via notification listener
- Route simulator for testing without driving (Kajang, JB, RLC KL routes)
- Auto-starts on device boot
GPS location update (every second)
|
v
ProximityEngine
- Haversine distance to each camera
- Bearing match: is the user heading toward the camera's monitored direction?
- Ahead check: is the camera in front, not behind?
|
v
Alert state machine
CLEAR -> DETECTED -> APPROACHING -> PASSING -> PASSED -> (30s cooldown) -> CLEAR
|
v
AlertManager (3-beep audio) + AlertOverlay (full-screen visual)
An alert only fires when all three conditions are met:
- Within scan radius
- Travel direction matches the camera's monitored bearing (within tolerance)
- Camera is ahead, not already passed
| Highway / Road | Cameras | States |
|---|---|---|
| PLUS E2 (Southern) | 10 | Johor, Melaka, N. Sembilan, Selangor |
| PLUS E1 (Northern) | 11 | Perak, Pulau Pinang, Kedah, Selangor |
| ELITE E6 | 2 | Selangor |
| GCE E35 | 2 | Selangor |
| SKVE E26 | 1 | Selangor |
| LEKAS E21 | 2 | Negeri Sembilan |
| Lebuh Sentosa | 1 | WP Putrajaya |
| Federal Route 1 | 1 | Perak |
| Federal Route 8 | 1 | Kelantan |
| LPT2 E8 | 2 | Terengganu |
| Red-light junctions | 14 | Perak, Kedah, WP Kuala Lumpur |
| Total | 47 |
Sources: JPJ official AWAS list (15.07.2024), OpenStreetMap Overpass API, paultan.org calibration reports.
com.aesalert.app/
|
+-- data/
| AESCamera.kt Room entity (lat, lng, speed limit, bearing, type, status)
| CameraDao.kt Room DAO (CRUD operations)
| AESDatabase.kt Room database with prepopulation on first launch
| CameraData.kt Hardcoded camera seed list (47 cameras)
| AreaData.kt Offline area zones for current-location display
| AppSettings.kt SharedPreferences wrapper (distance, toggles, mutes)
|
+-- logic/
| ProximityEngine.kt Core detection: Haversine + bearing + ahead + filters
| AlertManager.kt Audio alerts via ToneGenerator (3-beep sequence)
| OverlayLogic.kt Overlay visibility, dismissal, overspeed, warning text
| Heading.kt GPS heading resolution (hasBearing-aware)
| RouteSimulator.kt Fake GPS routes for testing (Kajang, JB, RLC KL)
|
+-- service/
| LocationTrackingService.kt Foreground service, GPS updates, StateFlow emission
| NowPlayingService.kt Notification listener for media info
|
+-- ui/
| MainScreen.kt Dashboard — speed display, GPS status, camera info
| AlertOverlay.kt Full-screen warning overlay (APPROACHING state)
| CameraListScreen.kt View, edit, and mute cameras
| SettingsDialog.kt Alert distance, alert toggles, now playing, simulation
| theme/Theme.kt Dark theme (Material 3)
|
+-- MainActivity.kt Entry point, runtime permissions, service binding
+-- BootReceiver.kt BroadcastReceiver — auto-start service on boot
| Language | Kotlin |
| UI | Jetpack Compose + Material 3 |
| Database | Room (SQLite) |
| Concurrency | Kotlin Coroutines + StateFlow |
| Build | Gradle Kotlin DSL, KSP |
| Tests | JUnit 4 (49 unit tests) |
| Min SDK | 26 (Android 8.0 Oreo) |
| Target SDK | 35 |
Download the latest APK from the Releases tab.
- Transfer the APK to your Android device via USB or any storage
- On your device: Settings > Security > Unknown Sources (or Install unknown apps) - enable for your file manager
- Open the APK with your file manager and install
- Grant location permissions when prompted
Tested on Android car head units and tablets (Android 8.0+)
# Debug APK
./gradlew assembleDebug
# Install directly to connected device
./gradlew installDebug
# Release APK (minified + obfuscated)
./gradlew assembleReleaseRequires Android Studio with Android SDK 35.
| Permission | Purpose |
|---|---|
ACCESS_FINE_LOCATION |
Precise GPS tracking |
ACCESS_BACKGROUND_LOCATION |
Continue tracking when screen is off |
FOREGROUND_SERVICE |
Persistent GPS service |
FOREGROUND_SERVICE_LOCATION |
Location-type foreground service (Android 14+) |
POST_NOTIFICATIONS |
Foreground service notification (Android 13+) |
RECEIVE_BOOT_COMPLETED |
Auto-start service on device boot |
WAKE_LOCK |
Keep CPU active while service is running |
This app is for informational purposes only. It is the driver's sole responsibility to obey all traffic laws and speed limits at all times.
Speed displayed is GPS-derived and may differ from your vehicle's speedometer. This is normal - most speedometers are calibrated to read slightly higher than actual speed by design.



.png)