rename 'docs' directory to 'doc'
This commit is contained in:
221
doc/platform/android/PHASE3_DIRECTIVE.md
Normal file
221
doc/platform/android/PHASE3_DIRECTIVE.md
Normal file
@@ -0,0 +1,221 @@
|
||||
# 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
|
||||
|
||||
```xml
|
||||
<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
|
||||
|
||||
```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 <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`) |
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
Reference in New Issue
Block a user