Files
daily-notification-plugin/docs/android-alarm-persistence-directive.md
Matthew Raymer 6aa9140f67 docs: add comprehensive alarm/notification behavior documentation
- Add platform capability reference (Android & iOS OS-level facts)
- Add plugin behavior exploration template (executable test matrices)
- Add plugin requirements & implementation directive
- Add Android-specific implementation directive with detailed test procedures
- Add exploration findings from code inspection
- Add improvement directive for refining documentation structure
- Add Android alarm persistence directive (OS capabilities)

All documents include:
- File locations, function references, and line numbers
- Detailed test procedures with ADB commands
- Cross-platform comparisons
- Implementation checklists and code examples
2025-11-21 07:30:25 +00:00

245 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Android Alarm Persistence, Recovery, and Limitations
**Author**: Matthew Raymer
**Date**: November 2025
**Status**: Engineering Directive - Active Reference
## Purpose
This document provides a **clean, consolidated, engineering-grade directive** summarizing Android's abilities and limitations for remembering, firing, and restoring alarms across:
- App kills
- Swipes from recents
- Device reboot
- **Force stop**
- User-triggered reactivation
This is the actionable version you can plug directly into your architecture docs.
---
## 1. Core Principle
Android does **not** guarantee persistence of alarms across process death, swipes, or reboot.
It is the app's responsibility to **persist alarm definitions** and **re-schedule them** under allowed system conditions.
The following directives outline **exactly what is possible** and **what is impossible**.
---
## 2. Allowed Behaviors (What *Can* Work)
### 2.1 Alarms survive UI kills (swipe from recents)
`AlarmManager.setExactAndAllowWhileIdle(...)` alarms **will fire** even after:
- App is swiped away
- App process is killed by the OS
The OS recreates your app's process to deliver the `PendingIntent`.
**Directive:**
Use `setExactAndAllowWhileIdle` for alarm execution.
---
### 2.2 Alarms can be preserved across device reboot
Android wipes all alarms on reboot, but **you may recreate them**.
**Directive:**
1. Persist all alarms in storage (Room DB or SharedPreferences).
2. Add a `BOOT_COMPLETED` / `LOCKED_BOOT_COMPLETED` broadcast receiver.
3. On boot, load all enabled alarms and reschedule them using AlarmManager.
**Permissions required:**
- `RECEIVE_BOOT_COMPLETED`
**Conditions:**
- User must have launched your app at least once before reboot to grant boot receiver execution.
---
### 2.3 Alarms can fire full-screen notifications and wake the device
**Directive:**
Implement `setFullScreenIntent(...)`, use an IMPORTANCE_HIGH channel with `CATEGORY_ALARM`.
This allows Clock-appstyle alarms even when the app is not foregrounded.
---
### 2.4 Alarms can be restored after app restart
If the user re-opens the app (direct user action), you may:
- Scan the persistent DB
- Detect "missed" alarms
- Reschedule future alarms
- Fire "missed alarm" notifications
- Reconstruct WorkManager/JobScheduler tasks wiped by OS
**Directive:**
Create a `ReactivationManager` that runs on every app launch and recomputes the correct alarm state.
---
## 3. Forbidden Behaviors (What *Cannot* Work)
### 3.1 You cannot survive "Force Stop"
**Settings → Apps → YourApp → Force Stop** triggers:
- Removal of all alarms
- Removal of WorkManager tasks
- Blocking of all broadcast receivers (including BOOT_COMPLETED)
- Blocking of all JobScheduler jobs
- Blocking of AlarmManager callbacks
- Your app will NOT run until the user manually launches it again
**Directive:**
Accept that FORCE STOP is a hard kill.
No scheduling, alarms, jobs, or receivers may execute afterward.
---
### 3.2 You cannot auto-resume after "Force Stop"
You may only resume tasks when:
- The user opens your app
- The user taps a notification belonging to your app
- The user interacts with a widget/deep link
- Another app explicitly targets your component
**Directive:**
Provide user-facing reactivation pathways (icon, widget, notification).
---
### 3.3 Alarms cannot be preserved solely in RAM
Android can kill your app's RAM state at any time.
**Directive:**
All alarm data must be persisted in durable storage.
---
### 3.4 You cannot bypass Doze or battery optimization restrictions without permission
Doze may defer inexact alarms; exact alarms with `setExactAndAllowWhileIdle` are allowed.
**Directive:**
Request `SCHEDULE_EXACT_ALARM` on Android 12+.
---
## 4. Required Implementation Components
### 4.1 Persistent Storage
Create a table or serialized structure for alarms:
```
id: Int
timeMillis: Long
repeat: NONE | DAILY | WEEKLY | CUSTOM
label: String
enabled: Boolean
```
---
### 4.2 Alarm Scheduling
Use:
```kotlin
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
triggerAtMillis,
pendingIntent
)
```
---
### 4.3 Boot Receiver
Reschedules alarms from storage.
---
### 4.4 Reactivation Manager
Runs on **every app launch** and performs:
- Load pending alarms
- Detect overdue alarms
- Reschedule future alarms
- Trigger notifications for missed alarms
---
### 4.5 Full-Screen Alarm UI
Use a `BroadcastReceiver` → Notification with full-screen intent → Activity.
---
## 5. Summary of Android Alarm Capability Matrix
| Scenario | Will Alarm Fire? | Reason |
| --------------------------------------- | --------------------------------------- | --------------------------------------------------------------- |
| **Swipe from Recents** | ✅ Yes | AlarmManager resurrects the app process |
| **App silently killed by OS** | ✅ Yes | AlarmManager still holds scheduled alarms |
| **Device Reboot** | ❌ No (auto) / ✅ Yes (if you reschedule) | Alarms wiped on reboot |
| **Doze Mode** | ⚠️ Only "exact" alarms | Must use `setExactAndAllowWhileIdle` |
| **Force Stop** | ❌ Never | Android blocks all callbacks + receivers until next user launch |
| **User reopens app** | ✅ You may reschedule & recover | All logic must be implemented by app |
| **PendingIntent from user interaction** | ✅ If triggered by user | User action unlocks the app |
---
## 6. Final Directive
> **Design alarm behavior with the assumption that Android will destroy all scheduled work on reboot or force-stop.
>
> Persist all alarm definitions. On every boot or app reactivation, reconstruct and reschedule alarms.
>
> Never rely on the OS to preserve alarms except across UI process kills.
>
> Accept that "force stop" is a hard stop that cannot be bypassed.**
---
## Related Documentation
- [Boot Receiver Testing Guide](./boot-receiver-testing-guide.md)
- [App Startup Recovery Solution](./app-startup-recovery-solution.md)
- [Reboot Testing Procedure](./reboot-testing-procedure.md)
---
## Future Directives
Potential follow-up directives:
- **How to implement the minimal alarm system**
- **How to implement a Clock-style robust alarm system**
- **How to map this to your own app's architecture**