FireWatch Australia
An Android app tracking NSW bushfires live, even when coverage drops.
- Role
- Android Engineer, solo build
- Year
- 2026
- Status
- In development
- Stack
- Kotlin · Jetpack Compose · Room · Hilt · Firebase Test Lab

Impact
The results, in brief.
- Shows real NSW fires live from the Rural Fire Service, and keeps working with no signal.
- 80 automated tests across every layer, feed to map.
- Every build is tested on a real Pixel 8 before it can reach Google Play.
My role
FireWatch is a solo build. I built every layer, from the live fire feed to the release pipeline.
What I owned
- Kotlin & Jetpack Compose app, end to end
- Offline-first cache in Room, cleaned up daily
- CI/CD: 80 tests, Firebase Test Lab, Google Play
Calls I made
- Offline first: fires cut coverage when it matters most
- Data age always shown, so old fires never look live
- Built to be tested: Hilt and an interface at every layer
How it’s built
The main parts of the system, in the order work flows through them.
A public feed in
The app reads the NSW Rural Fire Service's public incident feed and decodes its GeoJSON, fire perimeters included, into typed Kotlin models.
An offline-first repository
When the phone is online, every fetch is saved to a Room cache. When it isn't, the repository serves the last synced incidents instead of an error.
One-way UI state
A ViewModel turns each result into a single loading, success or error state that the Compose screens simply render, with a banner showing when data last synced.
A list and a live map
Incidents appear as a list and on a Google Map, with markers coloured by alert level and perimeters drawn around each fire.
Hilt through every layer
Dependency injection wires the app together, so tests swap in fakes for the network, the cache and the connection without touching app code.
A release pipeline, ready to ship
Every push to main runs the unit tests and builds the app. UI tests then run on a real device in Firebase Test Lab, and only a build that passes there is signed and uploaded to the Play Store internal track. The pipeline is built and ready; the app hasn't been released yet.
Why it’s built this way
The choices that shaped it, and the reason behind each one.
Offline is the point
Bushfires cut mobile coverage exactly when people need information most, so the last known incidents have to stay on the phone.
Cache every successful fetch
Saving each fresh response means the offline view is only ever as old as the last time the phone had signal, with no separate sync to schedule.
Always show how old the data is
When the phone is offline, a banner shows exactly when incidents were last synced, so old fires are never shown as live.
One source of UI truth
The list and the map read the same loading, success or error state, so they never show different fires.
Built to be tested
Interfaces for the network, the connection and the repository let each layer be tested on its own, from JSON parsing through to the map screen.
Keep the cache lean
A background job runs every 24 hours and deletes incidents older than 30 days, so the phone never fills up with fires that are long out.
Let’s connect
I am always open to discussing new projects, creative ideas, or opportunities to be part of your visions. Just reach out!