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
This commit is contained in:
244
docs/android-alarm-persistence-directive.md
Normal file
244
docs/android-alarm-persistence-directive.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# 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-app–style 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**
|
||||
|
||||
Reference in New Issue
Block a user