Android client for Daycompass, a self-hosted, open-source screen time backend for students.
Status: first complete flow, not yet tested on a real device. Pairing, usage collection and sync are built and covered by unit tests, but nothing has run on a phone or against a real server yet. There is no release build.
- Pair the device with your server: enter the server URL and a pairing code from the Daycompass dashboard by hand, or scan the dashboard's QR code (or open its pairing link) to fill both in automatically. Either way, a device name (prefilled with the device model) and an explicit confirmation of the server are needed before pairing happens — scanning or opening a link never pairs the device by itself. Camera access is asked for only when you tap "Scan QR code", and is entirely optional: typing the server and code always works, with or without a camera.
- Allow usage access in the Android settings. The app explains first what is collected and what is not.
- Collect which app is in the foreground and for how long, from the moment of pairing onwards. One entry per app session; this app and the launcher are left out. Collection runs hourly and works offline.
- Sync the collected entries to your server whenever it is reachable: right away when the app is opened, hourly in the background, and with backoff after a failure. There is no Wi-Fi detection, so the home network, a VPN such as Tailscale and public servers all work. Offline entries stay on the device until the server has confirmed them.
- Check the local buffer from the connected screen: a list of the entries still waiting to be sent (package name, collected time, duration). This reads only the device's own buffer — the app never reads events back from the server.
The connected screen always says in words when the device last synced, how many entries are waiting, and whether the device clock is off.
Per app session: the app's package name (for example org.mozilla.firefox),
the start time and the duration. Nothing else: no app names, no website
domains, no content, no location, no categories, nothing from before pairing.
- No Google Play Services, no Firebase, no analytics, no crash reporting, no telemetry.
- The only network destination is the Daycompass server you configure
yourself, over HTTPS. Only certificates trusted by the system are
accepted; cleartext traffic is disabled, including for QR/link pairing: a
pairing link pointing at an
http://server is refused. - QR scanning is done fully on-device (no cloud or Play Services barcode API); scanning or opening a pairing link never sends anything anywhere by itself, and never pairs without an explicit confirmation step.
- The device token is encrypted with an Android Keystore key and excluded from backups, like all other app data.
- Dependencies are free and open source (F-Droid friendly).
- Android 8.0 (API 26) or newer.
- A Daycompass server reachable over HTTPS with a certificate the device trusts (for example from Let's Encrypt). Self-signed certificates and user-installed CAs are not accepted.
The API this client talks to is documented in the backend repository:
docs/wire-format.md (normative) and docs/openapi-wire-v1.json.
AGPL-3.0-only. Bundled fonts: Fredoka and Nunito (SIL Open Font
License 1.1). Icon: Phosphor Icons (MIT). The license texts ship in the app
under assets/licenses/.
Requirements: JDK 21 and an Android SDK (set sdk.dir in local.properties).
./gradlew ktlintCheck detekt lint testDebugUnitTest assembleDebug
See CLAUDE.md for conventions and for how to regenerate
gradle/verification-metadata.xml after changing dependencies.