Files
daily-notification-plugin/docs/android-implementation-directive-phase3.md
Matthew Raymer 28fb233286 docs(test): add Phase 3 boot recovery testing infrastructure
Adds documentation and test harness for Phase 3 (Boot-Time Recovery).

Changes:
- Update android-implementation-directive-phase3.md with concise boot recovery flow
- Add PHASE3-EMULATOR-TESTING.md with detailed test procedures
- Add PHASE3-VERIFICATION.md with test matrix and verification template
- Add test-phase3.sh automated test harness

Test harness features:
- 4 test cases: future alarms, past alarms, no schedules, silent recovery
- Automatic emulator reboot handling
- Log parsing for boot recovery scenario and results
- UI prompts for plugin configuration and scheduling
- Verifies silent recovery without app launch

Related:
- Directive: android-implementation-directive-phase3.md
- Requirements: docs/alarms/03-plugin-requirements.md §3.1.1
- Testing: docs/alarms/PHASE3-EMULATOR-TESTING.md
- Verification: docs/alarms/PHASE3-VERIFICATION.md
2025-11-27 10:01:46 +00:00

5.7 KiB
Raw Blame History

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: <id> for <ts>
  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

<receiver
    android:name=".BootReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

3.2 Kotlin Class

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

fun runBootRecovery(context: Context)

Required Logging (canonical)

DNP-REACTIVATION: Starting boot recovery
DNP-REACTIVATION: Loaded <N> schedules from DB
DNP-REACTIVATION: Rescheduled alarm: <id> for <ts>
DNP-REACTIVATION: Marked missed notification: <id>
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)


Status: Directive complete, ready for implementation
Last Updated: November 2025