Skip to content

feat: usage collection into a local buffer - #15

Merged
mikahatdichlieb merged 5 commits into
mainfrom
feat/usage-collection
Oct 26, 2026
Merged

mikahatdichlieb merged 5 commits into
mainfrom
feat/usage-collection

Conversation

@mikahatdichlieb

Copy link
Copy Markdown
Contributor

Closes #12

What

Reads foreground app sessions from UsageStatsManager and keeps them in a local Room buffer, independent of the network. Nothing is uploaded yet; that is #13.

  • Start at pairing: a successful pairing sets the starting point. Before that there is none, so nothing from before pairing is ever read.
  • Hourly run: WorkManager runs collection every hour with no network constraint, because Android keeps raw usage events only for a few days. Each run reads the UsageEvents since the last run, builds sessions and stores the events together with the new starting point in one Room transaction.
  • Sessions: a session ends on pause, when another app comes to the front, screen off, keyguard or shutdown. A pause and resume of the same app within 2 seconds (switching its own activities) stays one session. A session still running at the end of a run is finished in a later run.
  • Events: Unix-second start_ts, duration_secs up to 86400 (longer sessions are split, under 1 s dropped), package name as app_id. No label, no domain, never a category. The event_id is a hash of app and start time, so re-reading a window never duplicates anything locally or on the server.
  • Filters: this app itself and the current launcher are skipped.
  • Without usage access the run does nothing. The permission screen comes with Usage access permission screen #14.
  • Re-pairing needed: collection keeps running while the device waits to be paired again.
  • Clock set back: collection waits until the clock passes the last stored point again.

Security / privacy relevant

  • The manifest declares PACKAGE_USAGE_STATS (a special access the user grants in the settings) and a <queries> entry for the HOME intent, used only to find the launcher.
  • Stored per event: package name, start time and duration. The buffer lives in the app database, which is excluded from backups. There is no size cap on the buffer.

Dependencies

Room 2.8.5, WorkManager 2.12.0 and KSP 2.3.12, each more than two weeks old. Most of the new verification-metadata entries are compile-time tooling for the Room compiler (Guava, kotlinpoet, sqlite-jdbc). The release runtime classpath gains only androidx modules (Room, SQLite, WorkManager, Lifecycle parts), and contains nothing from Play Services or Firebase. All CI tasks pass one at a time with a cold GRADLE_USER_HOME. The Room schema is committed under app/schemas/.

Tests

UsageSessionsTest, SessionEventsTest and UsageCollectorTest (against a fake DAO). The Room DAO itself and the Android side have not been exercised on a device yet: UsageEvents types, launcher detection and the WorkManager schedule are all untested.

A session ends on pause, another app, screen off or shutdown; activity
switches inside one app stay one session. Events are Unix seconds, at
most a day each, with an event_id derived from app and start time so
re-reading a window never duplicates anything. No label, no domain.
Collection starts at pairing, so nothing from before is read. Each run
stores its events and the new cursor in one transaction; a session still
running at the end of a run is finished in a later one.
Reads UsageEvents with the usage access the user grants, skips this app
and the launcher, and runs through WorkManager without a network
constraint because Android keeps raw events only for a few days.
@mikahatdichlieb
mikahatdichlieb merged commit a48ae27 into main Oct 26, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Usage collection into a local buffer

1 participant