Skip to content

Repository files navigation

KAN / I IN

An experimental Android screen-habit tracker that measures active phone time and time away without relying on a remote backend.

Overview

KAN is the repository name for an app currently labeled I IN on Android. I built it to explore how an always-on, device-local tracker can make two behaviors visible: time spent actively using the phone and uninterrupted time spent away from it.

The app combines a foreground service, screen-state broadcasts, persistent local state, a floating system overlay, and a lock-screen challenge flow. Its dashboard turns those signals into a daily budget, streak, absence records, session history, and a multi-day chart.

Features

  • Tracks active phone time, daily time away, budget progress, streaks, and absence records.
  • Shows history for completed days, phone sessions, and lock-screen challenge attempts.
  • Provides an optional draggable overlay with bar, dot, and ring visualizations.
  • Displays an optional lock-screen timer and timed stay-away challenges.
  • Persists settings and tracking state across app restarts, device boots, and app updates.
  • Includes first-run onboarding, notification and overlay permission flows, and Compose previews.

Technical Highlights

  • Event-driven background tracking: ScreenTimeService reacts to screen-on, screen-off, user-present, and unlock events. A one-second coroutine ticker records active time only while the device is interactive.
  • Defensive elapsed-time accounting: repository calculations combine wall-clock time with Android's monotonic elapsed-realtime clock. Restart recovery is capped at 60 seconds to avoid crediting an unobserved locked interval after the service is killed.
  • Day-boundary handling: daily rollover archives budget results and splits an ongoing absence at midnight, preserving the session while assigning time to the correct date.
  • Layered local persistence: aggregate state and settings use SharedPreferences; potentially larger phone-session and challenge logs use bounded append-only files. A migration path imports earlier preference-backed logs.
  • Service-owned overlay: OverlayController builds native Android views through WindowManager, separates taps from drags, snaps the timer to a screen edge, persists its position, and updates its visual state against the daily budget.
  • Reactive UI boundary: the repository exposes an immutable StateFlow<KanSnapshot>. Activities and Compose screens observe the same snapshot rather than maintaining separate tracking state.
  • Lifecycle recovery: a boot receiver restarts tracking after boot or package replacement, but only after onboarding has been completed.
  • Build automation: GitHub Actions provisions JDK 17 and the Android SDK, builds a clean debug APK, and publishes it as a workflow artifact. The workflow currently builds only; automated test and lint gates are not implemented.

Architecture

flowchart LR
    OS[Android screen, unlock, boot events] --> Service[ScreenTimeService]
    Boot[BootCompletedReceiver] --> Service
    Service <--> Repo[ScreenTimeRepository]
    Repo --> Prefs[SharedPreferences\naggregates and settings]
    Repo --> Logs[Bounded append-only logs\nsessions and challenges]
    Repo --> Flow[StateFlow of KanSnapshot]
    Flow --> UI[Compose app and lock-screen UI]
    Service --> Overlay[WindowManager overlay]
    Service --> Notify[Foreground and record notifications]
    UI --> Repo
Loading

ScreenTimeRepository is the state boundary. The service writes time and lifecycle events to it; UI surfaces observe its snapshot and send settings or challenge actions back. Overlay and notification presentation remain service-owned so they can continue when the main activity is closed.

Tech Stack

  • Kotlin 2.0.21 and Java 17
  • Android SDK 35 (minSdk 26, targetSdk 35)
  • Jetpack Compose with Material 3
  • Android foreground services, broadcast receivers, notifications, and WindowManager overlays
  • Kotlin coroutines and StateFlow
  • Gradle 8.9 with the checked-in wrapper
  • GitHub Actions for debug APK builds

Getting Started

Prerequisites

  • JDK 17
  • Android SDK Platform 35
  • Android Studio with Android SDK support, or command-line Android tooling
  • An Android 8.0 / API 26 or newer device or emulator for installation

Clone the repository, open it in Android Studio, and allow Gradle to sync. For command-line builds, configure the Android SDK through your environment or a local, uncommitted local.properties, then run from the repository root:

./gradlew :app:assembleDebug

On Windows PowerShell, use:

.\gradlew.bat :app:assembleDebug

The debug APK is written to app/build/outputs/apk/debug/app-debug.apk. The checked-in GitHub Actions workflow also runs this build on pushes to main or master and can be started manually; its debug-apk artifact contains the APK.

The repository defines standard verification tasks:

./gradlew test
./gradlew connectedAndroidTest
./gradlew :app:lintRelease

connectedAndroidTest requires a device or emulator. No unit or instrumentation test source sets are currently present, and the workflow does not run these verification tasks yet.

Demo

Screenshot coming soon.

For an in-repository UI tour, open the Compose previews in app/src/main/java/com/kan/app/ui/. Preview fixtures cover onboarding, the dashboard, history/settings, the app shell, and lock-timer states.

Project Status

Experimental. The core tracking, persistence, overlay, lock-screen, history, onboarding, and debug-build workflow are implemented. Production work—including automated tests, release verification, privacy documentation, Play Console validation, and broader device testing—is tracked in PRODUCTION_ROADMAP.md.

What I Learned

  • Background time tracking is primarily a lifecycle and clock-consistency problem: process death, reboot, screen transitions, and midnight rollover all need explicit recovery rules.
  • A monotonic clock is safer for elapsed durations, while wall time is still required for calendar grouping; reconciling both avoids common reboot and clock-change errors.
  • Keeping one repository-owned snapshot simplifies coordination between a foreground service, activities, Compose screens, overlays, and notifications.
  • High-frequency event logs and small configuration values have different storage needs; separating append-only logs from preference-backed aggregates keeps each persistence path simple.
  • Android's overlay, notification, full-screen intent, and boot behaviors require permission-aware fallbacks and real-device validation before any production-readiness claim is justified.

About

Android screen habit tracker with event-driven foreground tracking and local persistence.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages