Imported from bas080/auto-sleep-droid (
AGENTS.md). Install upstream withnpx skills add bas080/auto-sleep-droid. Copyright stays with the author.
AGENTS.md
Instructions and guidelines for AI coding agents and human developers working in this repository.
Project Overview
Auto Sleep Droid is an Android sleep timer app controlled entirely from the notification shade with a live event log UI in MainActivity.
Project Documentation
- SPEC.md: product requirements and acceptance criteria.
- IMPLEMENTATION.md: architecture, runtime flows, persistence, permissions, build/release details, and guidance for future developers and AI agents.
- USER_PERSONA_AND_NEEDS.md: user personas, target audience needs, mental models, reasoning, and product workflows. Consult this document whenever UX design decisions have to be made.
- EVENTS_AND_STATES.md: comprehensive reference of system states, input/sensor events, state transitions, transition matrix, state diagram, and event log formats.
- PERFORMANCE.md: performance analysis, optimizations implemented, and recommendations for future increases.
- NOTIFICATION_INPUT_OPTIONS.md: analysis of notification duration input options, framework constraints, and string parsing.
- NOTIFICATION_GOAL_INPUT_OPTIONS.md: options, constraints, parsing specifications, and architectural design for setting target wake-up goal alarms from notifications.
- UPDATE_NOTIFICATIONS.md: technical architecture, UX design, GitHub REST API integration, WorkManager check scheduling, and version comparison for non-store update notifications.
- IMPORT_EXPORT.md: specification, data schema format (JSON Schema v1), UI layout placement, clipboard/dialog workflows, and architecture for the Import/Export feature.
- GOOGLE_PLAY_RELEASE.md: research on feasibility, prerequisites, tooling, workflow configurations, and Google Play policy requirements for releasing via GitHub Workflows.
Build & Test Instructions
Common Commands
- Run unit tests:
./gradlew test - Build debug APK:
./gradlew assembleDebug - Build release APK (unsigned):
./gradlew assembleRelease - Lint F-Droid metadata:
fdroid lint com.bas080.autosleepdroid - Test F-Droid build:
fdroid build --stop --test com.bas080.autosleepdroid - Clean build outputs:
./gradlew clean
Key Codebase Conventions
- UX Design Decisions: Consult
docs/USER_PERSONA_AND_NEEDS.mdwhenever making UX design decisions to ensure alignment with target user personas, mental models, zero-gaze nighttime interaction principles, and user needs. - Action Toast Feedback: Actions that change something (such as toggling timer state, setting duration, dismissing/snoozing alarms, marking awake) should always be accompanied with a toast.
- Reactive UI Updates with
watchEffect: All UI updates in activities and services should usepreferenceManager.watchEffectto ensure that UI changes are fully reactive. - Documentation Boundaries:
docs/SPEC.mdis central to designing the app and any changes to the spec or product behavior require updatingdocs/SPEC.md. Always updatedocs/SPEC.mdwhenever user requirements, specifications, or product behaviors are described or changed.docs/SPEC.mdmust focus purely on product requirements, acceptance criteria, and user-visible behavior without technical implementation details (such as Android API names, classes, or code constructs). Technical implementation details and things implicit in the code should be documented indocs/IMPLEMENTATION.mdso future agents can clearly understand how the code works; favor writing indocs/IMPLEMENTATION.mdover writing code docs or inline comments. - No Text Codeblock Diagrams: Do not render ASCII or text-art codeblock diagrams in documentation files. Text diagrams are not computer parseable and are less desired.
- UI & Notification Strings: Do not include trailing punctuation, colons, or ellipses in UI and notification string resource values (
strings.xml). - Localization: Maintain default English resources in
app/src/main/res/values/strings.xmland Spanish translations inapp/src/main/res/values-es/strings.xml. - Test-Driven Development (TDD): When attempting a fix, follow a TDD approach where possible: write a test that fails first, and then implement the fix to make that test pass.
- Code Testability over Reflection: Prefer refactoring production code for testability (e.g. extracting testable logic into utility classes or methods, or increasing visibility) over using reflection in unit tests. Reflection should only be used when refactoring does not solve the problem.
- Unit Tests: Do not add unit tests or test dependencies unless explicitly instructed by the user.
- Reproducible & F-Droid Builds: Keep
dependenciesInfo(includeInApk = false,includeInBundle = false) disabled inapp/build.gradlefor F-Droid compliance. Whenever making changes affecting build configurations, Gradle plugins, or metadata, verify that unsigned release builds (./gradlew assembleReleaseorfdroid build --stop --test com.bas080.autosleepdroid) assemble cleanly without keystore environment variables and runfdroid lint com.bas080.autosleepdroidto ensure F-Droid build compatibility. - Releases: Follow
scripts/release.sh <version>for bumping versions and tagging manually, or trigger a release via GitHub Actionsworkflow_dispatchwith aversionparameter. GitHub Actions (.github/workflows/android-release.yml) executesscripts/release.sh, bumps versions, pushesmasterand the version tag (v<version>), and triggers the release workflow on the newly pushed tag to build APKs and publish releases automatically. Point to GitHub Releases in Fastlane description metadata rather than per-version changelogs. - Commit Messages: Do not use prefixes such as
ci:,feat:,fix:, orchore:. Write plain, clear titles written for normal human readers (e.g.Add dark mode supportinstead offeat: add dark mode support). Always checkgit diffbefore writing human readable, spec-focused commit messages and submission titles/descriptions to ensure accuracy. - User Manual Asset: The user manual is bundled in
app/src/main/assets/manual.htmland must be kept in sync whenever changes affecting user-visible behavior or features occur or wheneverdocs/SPEC.mdis updated. Do not use nested lists (<ul>inside<li>) inmanual.htmlor user documentation; favor flat, single-level lists, paragraphs, or separate subheadings instead. - Permissions Declaration & Documentation: Whenever feature logic relies on system permissions or policy access (e.g. Do Not Disturb access), always ensure
<uses-permission>is declared inAndroidManifest.xmlAND documented in the "Permissions Used" section inREADME.md(specifying whether each permission is required or optional). - Minimal Null Guards & Exception Handling: Write code with the least amount of null guards and
try-catchblocks necessary. Allow exceptions to be thrown when the application enters an invalid state so that the global error handler can intercept the error, record diagnostic context/stack traces, and prompt the user appropriately rather than silently swallowing errors or continuing in a corrupted state. - Background System Crash Analysis & Fault Tolerance:
When analyzing crash reports caused by background framework constraints (such as
ForegroundServiceStartNotAllowedExceptionor background execution limits):- Root Cause & Context: Identify whether the crash stems from modern OS restrictions when the app or service is executing in the background without user-initiated foreground privileges (e.g., system
START_STICKYservice restarts or deferred broadcast triggers). - Workability & State Integrity: Evaluate whether catching the exception allows the component to remain in a workable, consistent state. Defensive handling should log the failure context to
EventLoggerwhile preserving internal state machine logic, timers, alarms, and background listeners without bringing down the process. - Self-Healing Recovery: Design recovery mechanisms so the app self-heals seamlessly upon the next user interaction (e.g., re-invoking
startForegroundService()whenMainActivityenters the foreground). - API & Manifest Alignment: Ensure modern SDK parameter requirements (such as
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACKon API 29+) match declared AndroidManifest configurations.
- Root Cause & Context: Identify whether the crash stems from modern OS restrictions when the app or service is executing in the background without user-initiated foreground privileges (e.g., system
- Android Backwards Compatibility &
@Suppress("DEPRECATION")Guidelines:- Version Fallback Branches for Devices Below a Certain API Level: When an application supports older Android versions (within its configured
minSdkrange) and a framework API is deprecated in newer SDKs (e.g. API 31), write version-conditional logic:
In these version fallback branches,if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Modern API for Android 12+ (API 31+) val vibratorManager = context.getSystemService(VibratorManager::class.java) vibratorManager?.defaultVibrator } else { // Fallback for Android 8.0 - 11 (API 26 to 30) // Here Context.VIBRATOR_SERVICE is deprecated in newer SDKs, // but required to support devices running Android 8-11. @Suppress("DEPRECATION") context.getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator }@Suppress("DEPRECATION")is legitimate and expected because you intentionally invoke legacy framework calls to support older devices within yourminSdkrange. - When Refactoring Is Preferred Over
@Suppress: There are two key cases where refactoring without@Suppressis preferable:- AndroidX Compatibility Libraries: AndroidX provides backward-compatible wrappers (
IntentCompat,OnBackPressedDispatcher,ActivityResultContracts,NotificationCompat) that handle API level checks internally down to low API levels. Using AndroidX abstractions removes deprecations while preserving full backward compatibility. - APIs Already Supported Across
minSdk: If an API check guards logic for API 21 or 24, but the app'sminSdkis 26, the fallback branch is dead code on all supported devices. Removing the dead branch eliminates both the unreachable code and the deprecation warning.
- AndroidX Compatibility Libraries: AndroidX provides backward-compatible wrappers (
- Summary:
- Using
@Suppress("DEPRECATION")is valid whenever you maintain explicit backward-compatibility fallbacks for older devices within yourminSdktarget. - Using AndroidX / Modern APIs is preferred when AndroidX helpers exist or when the modern API is natively supported across your entire
minSdkrange.
- Using
- Version Fallback Branches for Devices Below a Certain API Level: When an application supports older Android versions (within its configured