# Android Implementation Directive – Phase 3 ## Boot-Time Recovery (Device Reboot / System Restart) **Plugin:** Daily Notification Plugin **Author:** Matthew Raymer **Applies to:** Android Plugin (Kotlin), Capacitor Bridge **Related Docs:** - `03-plugin-requirements.md` - `000-UNIFIED-ALARM-DIRECTIVE.md` - `android-implementation-directive-phase1.md` - `android-implementation-directive-phase2.md` - `ACTIVATION-GUIDE.md` --- ## 1. Purpose Phase 3 introduces **Boot-Time Recovery**, which restores daily notifications after: - Device reboot - OS restart - Update-related restart - App not opened after reboot (silent recovery) Android clears **all alarms** on reboot. Therefore, if our plugin is not actively rescheduling on boot, the user will miss all daily notifications until they manually launch the app. Phase 3 ensures: 1. Schedules stored in SQLite survive reboot 2. Alarms are fully reconstructed 3. No duplication / double-scheduling 4. Boot behavior avoids unnecessary heavy recovery 5. Recovery occurs even if the user does **not** manually open the app --- ## 2. Boot-Time Recovery Flow ### Trigger: `BOOT_COMPLETED` broadcast received → Plugin's Boot Receiver invoked → Recovery logic executed with `scenario=BOOT` ### Recovery Steps 1. **Load all schedules** from SQLite (`NotificationRepository.getAllSchedules()`) 2. **For each schedule:** - Calculate next runtime based on cron expression - Compare with current time 3. **If the next scheduled time is in the future:** - Recreate alarm with `setAlarmClock` - Log: `Rescheduled alarm: for ` 4. **If schedule was *in the past* at boot time:** - Mark as missed - Schedule next run according to cron rules 5. **If no schedules found:** - Quiet exit, log only one line: `BOOT: No schedules found` 6. **Safeties:** - Boot recovery must **not** modify Plugin Settings - Must not regenerate Fetcher configuration - Must not overwrite database records --- ## 3. Required Android Components ### 3.1 Boot Receiver ```xml ``` ### 3.2 Kotlin Class ```kotlin class BootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent?) { if (intent?.action != Intent.ACTION_BOOT_COMPLETED) return ReactivationManager.runBootRecovery(context) } } ``` --- ## 4. ReactivationManager – Boot Logic ### Method Signature ```kotlin fun runBootRecovery(context: Context) ``` ### Required Logging (canonical) ``` DNP-REACTIVATION: Starting boot recovery DNP-REACTIVATION: Loaded schedules from DB DNP-REACTIVATION: Rescheduled alarm: for DNP-REACTIVATION: Marked missed notification: DNP-REACTIVATION: Boot recovery complete: missed=X, rescheduled=Y, errors=Z ``` ### Required Fields * `scenario=BOOT` * `missed` * `rescheduled` * `verified` **MUST BE 0** (boot has no verification phase) --- ## 5. Constraints & Guardrails 1. **No plugin initialization** Boot must *not* require running the app UI. 2. **No heavy processing** * limit to 2 seconds * use the same timeout guard as Phase 2 3. **No scheduling duplicates** * Must detect existing AlarmManager entries * Boot always clears them, so all reschedules should be fresh 4. **App does not need to be opened** * Entire recovery must run in background context 5. **Idempotency** * Running twice should produce identical logs --- ## 6. Implementation Checklist ### Mandatory * [ ] BootReceiver included * [ ] Manifest entry added * [ ] `runBootRecovery()` implemented * [ ] Scenario logged as `BOOT` * [ ] All alarms recreated * [ ] Timeout protection * [ ] No modifications to preferences or plugin settings ### Optional * [ ] Additional telemetry for analytics * [ ] Optional debug toast for dev builds only --- ## 7. Expected Output Examples ### Example 1 – Normal Boot (future alarms exist) ``` DNP-REACTIVATION: Starting boot recovery DNP-REACTIVATION: Loaded 2 schedules from DB DNP-REACTIVATION: Rescheduled alarm: daily_1764233911265 for 1764236120000 DNP-REACTIVATION: Rescheduled alarm: daily_1764233465343 for 1764233700000 DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled=2, errors=0 ``` ### Example 2 – Schedules present but some in past ``` Marked missed notification: daily_1764233300000 Rescheduled alarm: daily_1764233300000 for next day ``` ### Example 3 – No schedules ``` DNP-REACTIVATION: BOOT: No schedules found ``` --- ## 8. Status | Item | Status | | -------------------- | -------------------------------- | | Directive | **Complete** | | Implementation | ☐ Pending / ✅ **Complete** (plugin v1.2+) | | Emulator Test Script | Ready (`test-phase3.sh`) | | Verification Doc | Ready (`PHASE3-VERIFICATION.md`) | --- ## 9. Related Documentation - [Unified Alarm Directive](./alarms/000-UNIFIED-ALARM-DIRECTIVE.md) - Master coordination document - [Plugin Requirements](./alarms/03-plugin-requirements.md) - Requirements this phase implements - [Platform Capability Reference](./alarms/01-platform-capability-reference.md) - OS-level facts - [Phase 1](./android-implementation-directive-phase1.md) - Prerequisite - [Phase 2](./android-implementation-directive-phase2.md) - Prerequisite - [Phase 3 Emulator Testing](./alarms/PHASE3-EMULATOR-TESTING.md) - Test procedures - [Phase 3 Verification](./alarms/PHASE3-VERIFICATION.md) - Verification report --- **Status**: Directive complete, ready for implementation **Last Updated**: November 2025