Sleep8 is an offline Android alarm app that schedules a wake alarm based on when you actually fall asleep.
When armed (from the app or Quick Settings tile), Sleep8 monitors screen on/off events only during the configured night window. If the screen remains off for the confirmation period (default 20 minutes), it schedules an app-owned exact alarm for:
trigger_at = screen_off_time + configured_duration
Default duration is 8h 0m, and valid duration range is 0-720 minutes.
- Arms/disarms manually from Home and Quick Settings tile.
- Runs
NightMonitorServiceonly while armed and inside the night window. - Tracks screen-off confirmation with an exact timer (
setExactAndAllowWhileIdle). - Schedules alarms with
AlarmManager.setAlarmClock(app-owned alarms, no OS clock delegation). - Enforces a single active scheduled alarm at a time.
- Provides:
- Home alarm list section (toggle enabled/disabled for existing records).
- Alarm history (full local audit trail, with clear-all action).
- Full-screen ringing UI for lockscreen context and high-priority ringing notifications when device is in use.
- Restores state and reconciles alarms after reboot.
- Uses boundary backstops and periodic health checks to self-heal monitoring start.
- Persists monitoring start telemetry for postmortem diagnosis.
- Works offline only (no
INTERNETpermission).
- User arms Sleep8.
- If current local time is inside night window, monitoring is active.
- On each
SCREEN_OFFevent in-window:- candidate screen-off timestamp is updated
- 20-minute confirmation timer is (re)started
- If
SCREEN_ONoccurs before confirmation, timer is cancelled. - If confirmation expires while still off:
- new alarm record is created (
SCHEDULED) - previous scheduled alarms are cancelled (
REPLACED_BY_NEW_ALARM) - exact alarm is scheduled with
setAlarmClock
- new alarm record is created (
- At trigger time, receiver launches ringing flow (service + high-priority alarm notification; lockscreen activity when needed).
- User dismisses alarm; record moves to
DISMISSED.
Notes:
- "Latest screen-off wins" before confirmation.
- Duration
0means ring immediately at confirmation time. - Manual disarm stops monitoring and pending confirmation, but does not cancel already scheduled alarms.
- Dismissing a ringing alarm does not disarm Sleep8; armed/disarmed is manual-only.
- Last screen-off indicator is session-scoped: it can remain visible across midnight and is cleared on fire, dismiss, disarm, and new arm session start.
Code is split into ui, domain, service, data, and util.
- UI layer:
MainActivity,SettingsActivity,AlarmHistoryActivity,AlarmRingingActivity- Compose screens and Quick Settings tile (
Sleep8TileService)
- Domain layer:
ArmManager(manual arming lifecycle and night-window boundary scheduling)StateMachineManager(screen events/confirmation transitions)AlarmScheduler,ConfirmOffScheduler,NightWindowScheduler
- Service/receiver layer:
NightMonitorService,AlarmRingingService- receivers for alarm firing, boot restore, confirmation, and window boundaries
- Data layer:
- Room DB + repositories for settings, sessions, and alarm records
- SharedPreferences (
AppPreferences) for runtime state and IDs
State machine:
DISARMEDARMED_IDLEARMED_PENDING_CONFIRMARMED_ALARM_SET
Room database: Sleep8Database (version 12)
settings- night window, confirmation minutes
- alarm duration, armed default
arm_sessions- arm/disarm lifecycle and source (
APP_BUTTON,QUICK_TILE)
- arm/disarm lifecycle and source (
screen_eventsSCREEN_OFF/SCREEN_ONaudit trail per session
alarm_records- trigger and lifecycle fields, including:
duration_used_minutesalarm_instance_idrequest_codestatus(SCHEDULED/FIRED/DISMISSED/CANCELED)canceled_reasonoverlay_used,activity_presented
- trigger and lifecycle fields, including:
monitoring_start_events- expected/scheduled/observed night window boundary timestamps
- armed/window gate snapshot at trigger time
- whether monitoring became active
- human-readable reason bucket when start failed
Manifest permissions include:
SCHEDULE_EXACT_ALARMPOST_NOTIFICATIONSUSE_FULL_SCREEN_INTENTREQUEST_IGNORE_BATTERY_OPTIMIZATIONSRECEIVE_BOOT_COMPLETED- Foreground service permissions
Settings includes a reliability section to verify/request:
- exact alarms
- notifications
- full-screen alarm UI capability
- battery optimization exclusion
- Pixel guidance: set Sleep8 battery usage to Unrestricted and avoid Extreme Battery Saver restrictions for Sleep8.
- Guarantee under normal OS conditions: if
armed && inNightWindowat night window start, monitoring auto-starts. - Reliability strategy: boundary exact alarm + +2/+10 minute boundary backstops + periodic 15-minute in-window health checks + boot/time/app-launch reconcile.
- Known limitations: force-stop and severe OS background restrictions can block any app-level guarantee.
- Kotlin, Jetpack Compose, Material 3
- Hilt dependency injection
- Room persistence
- AlarmManager (
setExactAndAllowWhileIdle,setAlarmClock) - JUnit5 + MockK + Robolectric + Compose UI tests
SDK/toolchain:
minSdk = 31targetSdk = 35compileSdk = 35- Java 17
- Kotlin 2.0.21
Prerequisites:
- Android Studio (or Gradle CLI)
- Android SDK for API 31+
- Java 17
Commands:
./gradlew assembleDebug
./gradlew installDebugLocal commands:
make check
make test-unit
make test-integration
make test-ui
make coverageEquivalent Gradle examples:
./gradlew testDebugUnitTest
./gradlew connectedDebugAndroidTest
./gradlew jacocoTestReport jacocoTestCoverageVerificationCurrent test footprint:
- 30 JVM test classes under
app/src/test - 6 instrumentation/Compose test classes under
app/src/androidTest
Coverage artifacts:
app/build/reports/jacoco/jacocoTestReport/html/index.htmlapp/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml
Coverage verification enforces >=90% on production-critical automation packages
(domain.manager, domain.state, domain.validator, and core time/duration utils).
Workflow: .github/workflows/android-ci-cd.yml
Runs:
- quality/lint
- unit + integration + coverage
- UI tests on emulator
- release build (non-PR events)
- optional Play deployment (workflow dispatch)
Codecov config: codecov.yml
app/Android app moduledocs/architecture/spec/testing/design docsapp/src/main/java/com/sleep8/...production sourceapp/src/test/...unit/integration testsapp/src/androidTest/...instrumentation/Compose tests
docs/SPEC.mdauthoritative product specdocs/ARCHITECTURE.mdarchitecture and runtime flowdocs/TEST_PLAN.mdwhat to verify across unit/integration/UI/manualdocs/MANUAL_TESTS.mddevice-first validation checklistdocs/DEV_NOTES.mddeveloper workflow notesdocs/VERIFICATION_REPORT.mdspec compliance snapshot
See LICENSE.