docs: Consolidate documentation structure (139 files, zero information loss)
Consolidate all markdown documentation into organized structure per CONSOLIDATION_DIRECTIVE. All files preserved (canonical, merged, or archived). - docs/integration/ - Integration documentation (7 files) - docs/platform/ios/ - iOS platform docs (12 files) - docs/platform/android/ - Android platform docs (9 files) - docs/testing/ - Testing documentation (15 files) - docs/design/ - Design & research (5 files) - docs/ai/ - AI/ChatGPT artifacts (7 files) - docs/archive/2025-legacy-doc/ - Historical docs (17 files) - Integration: Root INTEGRATION_GUIDE.md → docs/integration/ - Platform: Separated iOS and Android into platform/ subdirectories - Testing: Consolidated all testing docs to docs/testing/ - Legacy: Archived entire doc/ directory to archive/ - AI: Moved all ChatGPT artifacts to docs/ai/ - Added docs/00-INDEX.md - Central navigation hub - Added docs/CONSOLIDATION_SOURCE_MAP.md - Complete audit trail - Added docs/CONSOLIDATION_COMPLETE.md - Consolidation summary - Updated README.md with links to documentation index - All 139 files have destinations (see CONSOLIDATION_SOURCE_MAP.md) - Zero information loss (all files preserved) - Archive preserves original structure - Index provides clear navigation - 87 files moved/created/updated - Root-level docs consolidated - Legacy doc/ directory archived - Test app docs remain with test apps (indexed) Ref: CONSOLIDATION_DIRECTIVE Author: Matthew Raymer
This commit is contained in:
248
docs/platform/android/ALARM_PERSISTENCE_DIRECTIVE.md
Normal file
248
docs/platform/android/ALARM_PERSISTENCE_DIRECTIVE.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# Android Alarm Persistence, Recovery, and Limitations
|
||||
|
||||
**⚠️ DEPRECATED**: This document has been superseded by [01-platform-capability-reference.md](./alarms/01-platform-capability-reference.md) as part of the unified alarm documentation structure.
|
||||
|
||||
**See**: [Unified Alarm Directive](./alarms/000-UNIFIED-ALARM-DIRECTIVE.md) for the new documentation structure.
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: November 2025
|
||||
**Status**: **DEPRECATED** - Superseded by unified structure
|
||||
|
||||
## 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