rename 'docs' directory to 'doc'
This commit is contained in:
579
doc/alarms/000-UNIFIED-ALARM-DIRECTIVE.md
Normal file
579
doc/alarms/000-UNIFIED-ALARM-DIRECTIVE.md
Normal file
@@ -0,0 +1,579 @@
|
||||
# 🔧 UNIFIED DIRECTIVE: Alarm / Schedule / Notification Documentation & Implementation Stack
|
||||
|
||||
**Author:** Matthew Raymer
|
||||
**Status:** Active – Master Coordination Directive
|
||||
**Scope:** Android & iOS, Capacitor plugin, alarms/schedules/notifications
|
||||
**Version:** 1.1.0
|
||||
**Last Updated:** November 2025
|
||||
**Last Synced With Plugin Version:** v1.1.0
|
||||
|
||||
---
|
||||
|
||||
## 0. Purpose
|
||||
|
||||
Unify all existing alarm/notification documents into a **coherent, layered system** that:
|
||||
|
||||
1. **Eliminates duplication** (especially Android alarm behavior repeated across docs)
|
||||
2. **Separates concerns** into:
|
||||
* Platform facts
|
||||
* Exploration/testing
|
||||
* Plugin requirements
|
||||
* Implementation directives (Phases 1–3)
|
||||
3. **Provides iOS parity** to the existing Android-heavy material
|
||||
4. **Maps OS-level capabilities → plugin guarantees → JS/TS API contract**
|
||||
5. **Standardizes testing** into executable matrices for exploration and regression
|
||||
6. **Connects exploration → design → implementation** and tracks status across that pipeline
|
||||
|
||||
**This directive is the top of the stack.** If any lower-level document conflicts with this one, **this directive wins** unless explicitly noted.
|
||||
|
||||
**Mission Statement**: This directive ensures that every alarm outcome on every platform is predictable, testable, and recoverable, with no undocumented behavior.
|
||||
|
||||
**⚠️ ENFORCEMENT RULE**: No new alarm-related documentation may be created outside Documents A, B, C, or P1–P3. All future changes must modify these documents, not create additional standalone files.
|
||||
|
||||
---
|
||||
|
||||
## 1. Inputs (Existing Documents)
|
||||
|
||||
### 1.1 Platform & Reference Layer
|
||||
|
||||
* `platform-capability-reference.md` – OS-level facts (Android & iOS)
|
||||
* `android-alarm-persistence-directive.md` – Android abilities & limitations, engineering-grade
|
||||
|
||||
### 1.2 Exploration & Findings
|
||||
|
||||
* `plugin-behavior-exploration-template.md` – Structured template for exploring behavior
|
||||
* `explore-alarm-behavior-directive.md` – Exploration directive for behavior & persistence
|
||||
* `exploration-findings-initial.md` – Initial code-level discovery
|
||||
|
||||
### 1.3 Requirements & Implementation
|
||||
|
||||
* `plugin-requirements-implementation.md` – Plugin behavior rules & guarantees
|
||||
* `android-implementation-directive.md` – Umbrella Android implementation overview (app launch recovery, missed alarms, force stop, boot)
|
||||
* Phase directives (normative):
|
||||
* `../android-implementation-directive-phase1.md` – Cold start recovery (minimal viable)
|
||||
* `../android-implementation-directive-phase2.md` – Force stop detection & recovery
|
||||
* `../android-implementation-directive-phase3.md` – Boot receiver missed alarm handling
|
||||
|
||||
### 1.4 Improvement Directive
|
||||
|
||||
* `improve-alarm-directives.md` – Current plan for structural and content improvements across the stack
|
||||
|
||||
---
|
||||
|
||||
## 2. Target Structure (What We're Building)
|
||||
|
||||
We standardize around **three primary doc roles**, plus implementation phases:
|
||||
|
||||
### A. **Platform Reference (Document A)**
|
||||
|
||||
**Goal:** Single, stable, normative OS facts.
|
||||
|
||||
* Merge:
|
||||
* Android section from `android-alarm-persistence-directive.md`
|
||||
* Android & iOS matrices from `platform-capability-reference.md`
|
||||
* Content rules:
|
||||
* NO plugin-specific rules
|
||||
* Just: "what Android/iOS can and cannot do"
|
||||
* Use matrices & short prose only
|
||||
* Label each item as:
|
||||
* **OS-guaranteed**, **Plugin-required**, or **Forbidden** (where relevant)
|
||||
* Output path (recommended):
|
||||
`docs/alarms/01-platform-capability-reference.md`
|
||||
|
||||
### B. **Plugin Behavior Exploration (Document B)**
|
||||
|
||||
**Goal:** Executable exploration & testing spec.
|
||||
|
||||
* Baseline: `plugin-behavior-exploration-template.md` + `explore-alarm-behavior-directive.md`
|
||||
* Remove duplicated platform explanations (refer to Document A instead)
|
||||
* For each scenario (swipe, reboot, force stop, etc.):
|
||||
* Link to source files & functions (line or section refs)
|
||||
* Provide **Expected (OS)** & **Expected (Plugin)** from Docs A + C
|
||||
* Add columns for **Actual Result** and **Notes** (checkbox matrix)
|
||||
* Output path:
|
||||
`docs/alarms/02-plugin-behavior-exploration.md`
|
||||
|
||||
### C. **Plugin Requirements & Implementation Rules (Document C)**
|
||||
|
||||
**Goal:** What the plugin MUST guarantee & how.
|
||||
|
||||
* Baseline: `plugin-requirements-implementation.md` + `improve-alarm-directives.md`
|
||||
* Must include:
|
||||
1. **Plugin Behavior Guarantees & Limitations** by platform (table)
|
||||
2. **Persistence Requirements** (fields, storage, validation, failure modes)
|
||||
3. **Recovery Requirements**:
|
||||
* Boot (Android)
|
||||
* Cold start
|
||||
* Warm start
|
||||
* Force stop (Android)
|
||||
* User-tap recovery
|
||||
4. **Missed alarm handling contract** (definition, triggers, required actions)
|
||||
5. **JS/TS API Contract**:
|
||||
* What JS devs can rely on
|
||||
* Platform caveats (e.g., Force Stop, iOS background limits)
|
||||
6. **Unsupported features / limitations** clearly called out
|
||||
* Output path:
|
||||
`docs/alarms/03-plugin-requirements.md`
|
||||
|
||||
### D. **Implementation Directives (Phase 1–3)**
|
||||
|
||||
Already exist; this directive standardizes their role:
|
||||
|
||||
* **Phase docs are normative for code.**
|
||||
If they conflict with Document C, update the phase docs and then C.
|
||||
|
||||
**⚠️ STRUCTURE FREEZE**: The structure defined in this directive is FINAL. No new document categories may be introduced without updating this master directive first.
|
||||
|
||||
---
|
||||
|
||||
## 3. Ownership, Versioning & Status
|
||||
|
||||
### 3.1 Ownership
|
||||
|
||||
**Assignable Ownership** (replace abstract roles with concrete owners):
|
||||
|
||||
| Layer | Owner | Responsibility |
|
||||
| ---------------------- | ------------------- | ------------------------------------------------- |
|
||||
| Doc A – Platform Facts | Engineering Lead | Long-lived reference, rare changes |
|
||||
| Doc B – Exploration | QA / Testing Lead | Living document, updated with test results |
|
||||
| Doc C – Requirements | Plugin Architect | Versioned with plugin, defines guarantees |
|
||||
| Phases P1–P3 | Implementation Lead | Normative code specs, tied to Doc C requirements |
|
||||
|
||||
**Note**: If owners are not yet assigned, use role names above as placeholders until assignment.
|
||||
|
||||
### 3.2 Versioning Rules
|
||||
|
||||
* Any change that alters **JS/TS-visible behavior** → bump plugin **MINOR** at least
|
||||
* Any change that breaks prior guarantees or adds new required migration → **MAJOR bump**
|
||||
* Each doc should include:
|
||||
* `Version: x.y.z`
|
||||
* `Last Synced With Plugin Version: vX.Y.Z`
|
||||
|
||||
### 3.3 Status Matrix
|
||||
|
||||
**Status matrix is maintained in Section 11** (see below). This section is kept for historical reference only.
|
||||
|
||||
---
|
||||
|
||||
## 4. Work Plan – "Do All of the Above"
|
||||
|
||||
This is the **concrete to-do list** that satisfies:
|
||||
|
||||
* Consolidation
|
||||
* Versioning & ownership
|
||||
* Status tracking
|
||||
* Single-source master structure
|
||||
* Next-phase readiness
|
||||
* Improvements from `improve-alarm-directives.md`
|
||||
|
||||
### Step 1 – Normalize Platform Reference (Doc A)
|
||||
|
||||
1. Start from `platform-capability-reference.md` + `android-alarm-persistence-directive.md`
|
||||
2. Merge into a single doc:
|
||||
* Android matrix
|
||||
* iOS matrix
|
||||
* Core principles (no plugin rules)
|
||||
3. Ensure each line is labeled:
|
||||
* **OS-guaranteed**, **Plugin-required**, or **Forbidden** (where relevant)
|
||||
4. Mark the old Android alarm persistence doc as:
|
||||
* **Deprecated in favor of Doc A** (leave file but add a banner)
|
||||
|
||||
### Step 2 – Rewrite Exploration (Doc B)
|
||||
|
||||
1. Use `plugin-behavior-exploration-template.md` as the skeleton
|
||||
2. Integrate concrete scenario descriptions and code paths from `explore-alarm-behavior-directive.md`
|
||||
3. For **each scenario**:
|
||||
* App swipe, OS kill, reboot, force stop, cold start, warm start, notification tap:
|
||||
* Add row: Step-by-step actions + Expected (OS) + Expected (Plugin) + Actual + Notes
|
||||
4. Remove any explanation that duplicates Doc A; replace with "See Doc A, section X"
|
||||
|
||||
### Step 3 – Rewrite Plugin Requirements (Doc C)
|
||||
|
||||
1. Start from `plugin-requirements-implementation.md` & improvement goals
|
||||
2. Add / enforce sections:
|
||||
* **Plugin Behavior Guarantees & Limitations**
|
||||
* **Persistence Spec** (fields, mandatory vs optional)
|
||||
* **Recovery Points** (boot, cold, warm, force stop, user tap)
|
||||
* **Missed Alarm Contract**
|
||||
* **JS/TS API Contract**
|
||||
* **Unsupported / impossible guarantees** (Force Stop, iOS background, etc.)
|
||||
3. Everywhere it relies on platform behavior:
|
||||
* Link back to Doc A using short cross-reference ("See A §2.1")
|
||||
4. Add a **"Traceability"** mini-table:
|
||||
* Row per behavior → Platform fact in A → Tested scenario in B → Implemented in Phase N
|
||||
|
||||
### Step 4 – Align Implementation Directives with Doc C
|
||||
|
||||
1. Treat Phase docs as **canonical code spec**: P1, P2, P3
|
||||
2. For each behavior required in Doc C:
|
||||
* Identify which Phase implements it (or will implement it)
|
||||
3. Update:
|
||||
* `android-implementation-directive.md` to be explicitly **descriptive/integrative**, not normative, pointing to Phases 1–3 & Doc C
|
||||
* Ensure scenario model, alarm existence checks, and boot handling match the **corrected model** already defined in Phase 2 & 3
|
||||
4. Add acceptance criteria per phase that directly reference:
|
||||
* Requirements in Doc C
|
||||
* Platform constraints in Doc A
|
||||
5. **Phase 1–3 must REMOVE**:
|
||||
* Any scenario logic (moved to Doc C)
|
||||
* Any platform behavioral claims (moved to Doc A)
|
||||
* Any recovery responsibilities not assigned to that phase
|
||||
|
||||
### Step 5 – Versioning & Status
|
||||
|
||||
1. At the top of Docs A, B, C, and each Phase doc, add:
|
||||
* `Version`, `Last Updated`, `Sync'd with Plugin vX.Y.Z`
|
||||
2. Maintain the status matrix (Section 11) as the **single source of truth** for doc maturity
|
||||
3. When a Phase is fully implemented and deployed:
|
||||
* Mark "In Use?" = ✅
|
||||
* Add link to code tags/commit hash
|
||||
|
||||
### Step 6 – Readiness Check for Next Work Phase
|
||||
|
||||
Before starting any *new* implementation work on alarms / schedules:
|
||||
|
||||
1. **Confirm:**
|
||||
* Doc A exists and is stable enough (no "TODO" in core matrices)
|
||||
* Doc B has at least the base scenarios scaffolded
|
||||
* Doc C clearly defines:
|
||||
* What we guarantee on each platform
|
||||
* What we cannot do (e.g., Force Stop auto-resume)
|
||||
2. Only then:
|
||||
* Modify or extend Phase 1–3
|
||||
* Or add new phases (e.g., warm-start optimizations, iOS parity work)
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance Criteria for THIS Directive (Revised and Final)
|
||||
|
||||
This directive is complete **ONLY** when:
|
||||
|
||||
1. **Doc A exists, is referenced, and no other doc contains platform facts**
|
||||
* File exists: `docs/alarms/01-platform-capability-reference.md`
|
||||
* All old platform docs marked as deprecated with banner
|
||||
* No platform facts duplicated in other docs
|
||||
|
||||
2. **Doc B contains**:
|
||||
* At least 6 scenarios (swipe, reboot, force stop, cold start, warm start, notification tap)
|
||||
* Expected OS vs Plugin behavior columns
|
||||
* Space for Actual Result and Notes
|
||||
* Links to source files/functions
|
||||
|
||||
3. **Doc C contains**:
|
||||
* Guarantees by platform (table format)
|
||||
* Recovery matrix (boot, cold, warm, force stop, user tap)
|
||||
* JS/TS API contract
|
||||
* Unsupported behaviors clearly called out
|
||||
|
||||
4. **Phase docs**:
|
||||
* Contain NO duplication of Doc A (platform facts)
|
||||
* Reference Doc C explicitly (requirements)
|
||||
* Have acceptance criteria tied to Doc C requirements
|
||||
|
||||
5. **Deprecated files have**:
|
||||
* Banner: "⚠️ **DEPRECATED**: Superseded by [000-UNIFIED-ALARM-DIRECTIVE](./000-UNIFIED-ALARM-DIRECTIVE.md)"
|
||||
* Link to replacement document
|
||||
|
||||
6. **Status matrix fields are no longer empty** (Section 11)
|
||||
* All docs marked as Drafted at minimum
|
||||
|
||||
---
|
||||
|
||||
## 6. Document Relationships & Cross-References
|
||||
|
||||
### 6.1 Reference Flow
|
||||
|
||||
```
|
||||
Unified Directive (this doc)
|
||||
↓
|
||||
├─→ Doc A (Platform Reference)
|
||||
│ └─→ Referenced by: B, C, P1-P3
|
||||
│
|
||||
├─→ Doc B (Exploration)
|
||||
│ └─→ References: A (platform facts), C (expected behavior)
|
||||
│ └─→ Feeds into: P1-P3 (test results inform implementation)
|
||||
│
|
||||
├─→ Doc C (Requirements)
|
||||
│ └─→ References: A (platform constraints)
|
||||
│ └─→ Referenced by: P1-P3 (implementation must satisfy)
|
||||
│
|
||||
└─→ P1-P3 (Implementation)
|
||||
└─→ References: A (platform facts), C (requirements)
|
||||
└─→ Validated by: B (exploration results)
|
||||
```
|
||||
|
||||
### 6.2 Cross-Reference Format
|
||||
|
||||
When referencing between documents, use this format:
|
||||
|
||||
* **Doc A**: `[Platform Reference §2.1](../alarms/01-platform-capability-reference.md#21-android-alarm-persistence)`
|
||||
* **Doc B**: `[Exploration §3.2](../alarms/02-plugin-behavior-exploration.md#32-cold-start-scenario)`
|
||||
* **Doc C**: `[Requirements §4.3](../alarms/03-plugin-requirements.md#43-recovery-requirements)`
|
||||
* **Phase docs**: `[Phase 1 §2.3](../android-implementation-directive-phase1.md#23-cold-start-recovery)`
|
||||
|
||||
---
|
||||
|
||||
## 7. Canonical Source of Truth Rules
|
||||
|
||||
### 7.1 Platform Facts
|
||||
|
||||
**Only Doc A** contains platform facts. All other docs reference Doc A, never duplicate platform behavior.
|
||||
|
||||
**Reference Format**: `[Doc A §X.Y]` - See [Platform Capability Reference](./01-platform-capability-reference.md)
|
||||
|
||||
### 7.2 Requirements
|
||||
|
||||
**Only Doc C** defines plugin requirements. Phase docs implement Doc C requirements.
|
||||
|
||||
**Reference Format**: `[Doc C §X.Y]` - See [Plugin Requirements](./03-plugin-requirements.md)
|
||||
|
||||
### 7.3 Implementation Details
|
||||
|
||||
**Only Phase docs (P1-P3)** contain implementation details. Unified Directive does not specify code structure or algorithms.
|
||||
|
||||
**Reference Format**: `[Phase N §X.Y]` - See Phase implementation directives
|
||||
|
||||
### 7.4 Test Results
|
||||
|
||||
**Only Doc B** contains actual test results and observed behavior. Doc B references Doc A for expected OS behavior and Doc C for expected plugin behavior.
|
||||
|
||||
---
|
||||
|
||||
## 8. Conflict Resolution
|
||||
|
||||
If conflicts arise between documents:
|
||||
|
||||
1. **This directive (000)** wins for structure and organization
|
||||
2. **Doc A** wins for platform facts
|
||||
3. **Doc C** wins for requirements
|
||||
4. **Phase docs (P1-P3)** win for implementation details
|
||||
5. **Doc B** is observational (actual test results) and may reveal conflicts
|
||||
|
||||
When a conflict is found:
|
||||
1. Document it in this section
|
||||
2. Resolve by updating the lower-priority document
|
||||
3. Update the status matrix
|
||||
|
||||
---
|
||||
|
||||
## 9. Next Steps
|
||||
|
||||
### ⚠️ Time-Based Triggers (Enforcement)
|
||||
|
||||
**Doc A must be created BEFORE any further implementation work.**
|
||||
- No Phase 2 or Phase 3 changes until Doc A exists
|
||||
- No new platform behavior claims in any doc until Doc A is canonical
|
||||
|
||||
**Doc B must be baseline-complete BEFORE Phase 2 changes.**
|
||||
- At least 6 core scenarios scaffolded
|
||||
- Expected behavior columns populated from Doc A + Doc C
|
||||
|
||||
**Doc C must be finalized BEFORE any JS/TS API changes.**
|
||||
- All guarantees documented
|
||||
- API contract defined
|
||||
- No breaking changes to JS/TS API without Doc C update first
|
||||
|
||||
### Immediate (Before New Implementation)
|
||||
|
||||
1. Create stub documents A, B, C with structure
|
||||
2. Migrate content from existing docs into new structure
|
||||
3. Update all cross-references
|
||||
4. Mark old docs as deprecated (with pointers to new docs)
|
||||
|
||||
**Deliverables Required**:
|
||||
- Doc A exists as a file in repo
|
||||
- Doc B exists with scenario tables scaffolded
|
||||
- Doc C exists with required sections
|
||||
- Status matrix updated in this document
|
||||
- Deprecated docs marked with header banner
|
||||
|
||||
### Short-term (During Implementation)
|
||||
|
||||
1. Keep Doc B updated with test results
|
||||
2. Update Phase docs as implementation progresses
|
||||
3. Maintain status matrix
|
||||
|
||||
### Long-term (Post-Implementation)
|
||||
|
||||
1. Add iOS parity documentation
|
||||
2. Expand exploration scenarios
|
||||
3. Create regression test suite based on Doc B
|
||||
|
||||
### ⚠️ iOS Parity Activation Milestone
|
||||
|
||||
**iOS parity work begins ONLY after**:
|
||||
|
||||
1. **Doc A contains iOS matrix** - All iOS platform facts documented with labels (see [Doc A](./01-platform-capability-reference.md#3-ios-notification-capability-matrix))
|
||||
2. **Doc C defines iOS limitations and guarantees** - All iOS-specific requirements documented (see [Doc C](./03-plugin-requirements.md#1-plugin-behavior-guarantees--limitations))
|
||||
3. **No references in Phase docs assume Android-only behavior** - All Phase docs are platform-agnostic or explicitly handle both platforms
|
||||
|
||||
**Blocking Rule**: No iOS implementation work may proceed until these conditions are met.
|
||||
|
||||
**Enforcement**: Phase docs MUST reference Doc A for platform facts and Doc C for requirements. No platform-specific assumptions allowed.
|
||||
|
||||
---
|
||||
|
||||
## 10. Change-Control Rules
|
||||
|
||||
Any change to Docs A–C requires:
|
||||
|
||||
1. **Update version header** in the document
|
||||
2. **Update status matrix** (Section 11) in this directive
|
||||
3. **Commit message tag**: `[ALARM-DOCS]` prefix
|
||||
4. **Notification in CHANGELOG** if JS/TS-visible behavior changes
|
||||
|
||||
**Phase docs may not be modified unless Doc C changes first** (or explicit exception documented).
|
||||
|
||||
**Example commit message**:
|
||||
```
|
||||
[ALARM-DOCS] Update Doc C with force stop recovery guarantee
|
||||
|
||||
- Added force stop detection requirement
|
||||
- Updated recovery matrix
|
||||
- Version bumped to 1.1.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Status Matrix
|
||||
|
||||
| Doc | Path | Role | Drafted? | Cleaned? | In Use? | Notes |
|
||||
| --- | ------------------------------------- | ----------------- | -------- | -------- | ------- | ---------------------------------------- |
|
||||
| A | `01-platform-capability-reference.md` | Platform facts | ✅ | ✅ | ✅ | Created, merged from platform docs, canonical rule added |
|
||||
| B | `02-plugin-behavior-exploration.md` | Exploration | ✅ | ✅ | ✅ | Converted to executable test harness + emulator script |
|
||||
| C | `03-plugin-requirements.md` | Requirements | ✅ | ✅ | ✅ | Enhanced with guarantees matrix, JS/TS contract, traceability - **complete and in compliance** |
|
||||
| P1 | `../android-implementation-directive-phase1.md` | Impl – Cold start | ✅ | ✅ | ✅ | Emulator-verified via `test-phase1.sh` (Pixel 8 API 34, 2025-11-27) |
|
||||
| P2 | `../android-implementation-directive-phase2.md` | Impl – Force stop | ✅ | ✅ | ☐ | Implemented; to be emulator-verified via `test-phase2.sh` (Pixel 8 API 34, 2025-11-XX) |
|
||||
| P3 | `../android-implementation-directive-phase3.md` | Impl – Boot Recovery | ✅ | ✅ | ☐ | Implemented; verify via `test-phase3.sh` (API 34 baseline) |
|
||||
| V1 | `PHASE1-VERIFICATION.md` | Verification – P1 | ✅ | ✅ | ✅ | Summarizes Phase 1 emulator tests and latest known good run |
|
||||
| V2 | `PHASE2-VERIFICATION.md` | Verification – P2 | ✅ | ✅ | ☐ | Summarizes Phase 2 emulator tests and latest known good run |
|
||||
| V3 | `PHASE3-VERIFICATION.md` | Verification – P3 | ✅ | ✅ | ☐ | To be completed after first clean emulator run |
|
||||
|
||||
**Doc C Compliance Milestone**: Doc C is considered complete **ONLY** when:
|
||||
- ✅ Cross-platform guarantees matrix present
|
||||
- ✅ JS/TS API contract with returned fields and error states
|
||||
- ✅ Explicit storage schema documented
|
||||
- ✅ Recovery contract with all triggers and actions
|
||||
- ✅ Unsupported behaviors explicitly listed
|
||||
- ✅ Traceability matrix mapping A → B → C → Phase
|
||||
|
||||
**Legend:**
|
||||
- ✅ = Complete
|
||||
- ☐ = Not started / In progress
|
||||
- ⚠️ = Needs attention
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* [Android Implementation Directive](../android-implementation-directive.md) – Umbrella overview
|
||||
* [Phase 1: Cold Start Recovery](../android-implementation-directive-phase1.md) – Minimal viable recovery
|
||||
* [Phase 2: Force Stop Recovery](../android-implementation-directive-phase2.md) – Force stop detection
|
||||
* [Phase 3: Boot Recovery](../android-implementation-directive-phase3.md) – Boot receiver enhancement
|
||||
* [Exploration Findings](../exploration-findings-initial.md) – Initial code discovery
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active master coordination directive
|
||||
**Last Updated**: November 2025
|
||||
**Next Review**: After implementation phases are complete
|
||||
|
||||
---
|
||||
|
||||
## 12. Single Instruction for Team
|
||||
|
||||
**⚠️ BLOCKING RULE**: No engineering or documentation work on alarms/schedules/notifications may continue until Steps 1–3 in §9 ("Immediate") are complete and committed.
|
||||
|
||||
**Specifically**:
|
||||
- Doc A must exist as a file
|
||||
- Doc B must have scenario tables scaffolded
|
||||
- Doc C must have required sections
|
||||
- Status matrix must be updated
|
||||
- Deprecated files must be marked
|
||||
|
||||
**Exception**: Only emergency bug fixes may proceed, but must be documented retroactively in the appropriate Doc A/B/C structure.
|
||||
|
||||
---
|
||||
|
||||
## 13. Prohibited Content Rules
|
||||
|
||||
**The following content may NOT appear in any document except the specified one**:
|
||||
|
||||
| Content Type | Allowed Only In | Examples |
|
||||
| ------------ | --------------- | -------- |
|
||||
| **Platform rules** | Doc A only | "Android wipes alarms on reboot", "iOS persists notifications automatically" |
|
||||
| **Guarantees or requirements** | Doc C only | "Plugin MUST detect missed alarms", "Plugin SHOULD reschedule on boot" |
|
||||
| **Actual behavior findings** | Doc B only | "Test showed alarm fired 2 seconds late", "Missed alarm not detected in scenario X" |
|
||||
| **Recovery logic** | Phase docs only | "ReactivationManager.performRecovery()", "BootReceiver sets flag" |
|
||||
| **Implementation details** | Phase docs only | Code snippets, function signatures, database queries |
|
||||
|
||||
**Violation Response**: If prohibited content is found, move it to the correct document and replace with a cross-reference.
|
||||
|
||||
---
|
||||
|
||||
## 14. Glossary
|
||||
|
||||
**Shared terminology across all documents** (must be identical):
|
||||
|
||||
| Term | Definition |
|
||||
| ---- | ---------- |
|
||||
| **recovery** | Process of detecting and handling missed alarms, rescheduling future alarms, and restoring plugin state after app launch, boot, or force stop |
|
||||
| **cold start** | App launched from terminated state (process killed, no memory state) |
|
||||
| **warm start** | App returning from background (process may still exist, memory state may persist) |
|
||||
| **missed alarm** | Alarm where `trigger_time < now`, alarm was not fired (or firing status unknown), alarm is still enabled, and alarm has not been manually cancelled |
|
||||
| **delivered alarm** | Alarm that successfully fired and displayed notification to user |
|
||||
| **persisted alarm** | Alarm definition stored in durable storage (database, files, etc.) |
|
||||
| **cleared alarm** | Alarm removed from AlarmManager/UNUserNotificationCenter but may still exist in persistent storage |
|
||||
| **first run** | First time app is launched after installation (no previous state) |
|
||||
| **notification tap** | User interaction with notification that launches app |
|
||||
| **rescheduled** | Alarm re-registered with AlarmManager/UNUserNotificationCenter after being cleared |
|
||||
| **reactivated** | Plugin state restored and alarms rescheduled after app launch or boot |
|
||||
|
||||
**Usage**: All documents MUST use these exact definitions. No synonyms or variations allowed.
|
||||
|
||||
---
|
||||
|
||||
## 15. Lifecycle Flow Diagram
|
||||
|
||||
**Document relationship and information flow**:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Unified Directive (000) - Master Coordination │
|
||||
│ Defines structure, ownership, change control │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ References & Coordinates
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ Doc A │ │ Doc B │ │ Doc C │
|
||||
│ Platform │ │ Exploration │ │ Requirements│
|
||||
│ Facts │ │ & Testing │ │ & Guarantees│
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
└───────────────────┼───────────────────┘
|
||||
│
|
||||
│ Implements
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ Phase 1 │ │ Phase 2 │ │ Phase 3 │
|
||||
│ Cold Start │ │ Force Stop │ │ Boot │
|
||||
│ Recovery │ │ Recovery │ │ Recovery │
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
**Information Flow**:
|
||||
1. **Doc A** (Platform Facts) → Informs **Doc C** (Requirements) → Drives **Phase Docs** (Implementation)
|
||||
2. **Doc B** (Exploration) → Validates **Phase Docs** → Updates **Doc C** (Requirements)
|
||||
3. **Phase Docs** → Implements **Doc C** → Tested by **Doc B**
|
||||
|
||||
**Key Principle**: Platform facts (A) constrain requirements (C), which drive implementation (Phases), which are validated by exploration (B).
|
||||
|
||||
468
doc/alarms/01-platform-capability-reference.md
Normal file
468
doc/alarms/01-platform-capability-reference.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# Platform Capability Reference: Android & iOS Alarm/Notification Behavior
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: November 2025
|
||||
**Status**: Platform Reference - Stable
|
||||
**Version**: 1.1.0
|
||||
**Last Synced With Plugin Version**: v1.1.0
|
||||
|
||||
## Purpose
|
||||
|
||||
This document provides **pure OS-level facts** about alarm and notification capabilities on Android and iOS. It contains **no plugin-specific logic**—only platform mechanics that affect plugin design.
|
||||
|
||||
**This is a reference document** to be consulted when designing plugin behavior, not an implementation guide.
|
||||
|
||||
**⚠️ CANONICAL RULE**: No other document may contain OS-level behavior. All platform facts **MUST** reference this file. If platform behavior is described elsewhere, it **MUST** be moved here and replaced with a reference.
|
||||
|
||||
**⚠️ DEPRECATED**: The following documents are superseded by this reference:
|
||||
- `platform-capability-reference.md` - Merged into this document
|
||||
- `android-alarm-persistence-directive.md` - Merged into this document
|
||||
|
||||
**See**: [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) for document structure.
|
||||
|
||||
---
|
||||
|
||||
## 1. Core Principles
|
||||
|
||||
### Android
|
||||
|
||||
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.
|
||||
|
||||
### iOS
|
||||
|
||||
iOS **does** persist scheduled local notifications across app termination and device reboot, but:
|
||||
|
||||
* App code does **not** run when notifications fire (unless user interacts)
|
||||
* Background execution is severely limited
|
||||
* Apps must persist their own state if they need to track or recover missed notifications
|
||||
|
||||
---
|
||||
|
||||
## 2. Android Alarm Capability Matrix
|
||||
|
||||
| Scenario | Will Alarm Fire? | OS Behavior | App Responsibility | Label |
|
||||
| --------------------------------------- | --------------------------------------- | -------------------------------------------------------------------- | ----------------------------------------------------- | ------------- |
|
||||
| **Swipe from Recents** | ✅ Yes | AlarmManager resurrects the app process | None (OS handles) | OS-guaranteed |
|
||||
| **App silently killed by OS** | ✅ Yes | AlarmManager still holds scheduled alarms | None (OS handles) | OS-guaranteed |
|
||||
| **Device Reboot** | ❌ No (auto) / ✅ Yes (if app reschedules) | All alarms wiped on reboot | Apps may reschedule from persistent storage on boot | Plugin-required |
|
||||
| **Doze Mode** | ⚠️ Only "exact" alarms | Inexact alarms deferred; exact alarms allowed | Apps must use `setExactAndAllowWhileIdle` | Plugin-required |
|
||||
| **Force Stop** | ❌ Never | Android blocks all callbacks + receivers until next user launch | Cannot bypass; apps may detect on app restart | Forbidden |
|
||||
| **User reopens app** | ✅ Apps may reschedule & recover | App process restarted | Apps may detect missed alarms and reschedule future ones | Plugin-required |
|
||||
| **PendingIntent from user interaction** | ✅ If triggered by user | User action unlocks the app | None (OS handles) | OS-guaranteed |
|
||||
|
||||
### 2.1 Android Allowed Behaviors
|
||||
|
||||
#### 2.1.1 Alarms survive UI kills (swipe from recents)
|
||||
|
||||
**OS-guaranteed**: `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`.
|
||||
|
||||
**Required API**: `setExactAndAllowWhileIdle()` or `setAlarmClock()`
|
||||
|
||||
#### 2.1.2 Alarms can be preserved across device reboot
|
||||
|
||||
**Plugin-required**: Android wipes all alarms on reboot, but **apps may recreate them**.
|
||||
|
||||
**OS Behavior**: All alarms are cleared on device reboot. No alarms persist automatically.
|
||||
|
||||
**App Capability**: Apps may recreate alarms after reboot by:
|
||||
1. Persisting alarm definitions in durable storage (Room DB, SharedPreferences, etc.)
|
||||
2. Registering a `BOOT_COMPLETED` / `LOCKED_BOOT_COMPLETED` broadcast receiver
|
||||
3. Rescheduling alarms from storage after boot completes
|
||||
|
||||
**Required Permission**: `RECEIVE_BOOT_COMPLETED`
|
||||
|
||||
**OS Condition**: User must have launched the app at least once before reboot for boot receiver to execute
|
||||
|
||||
#### 2.1.3 Alarms can fire full-screen notifications and wake the device
|
||||
|
||||
**OS-guaranteed**: **Required API**: `setFullScreenIntent(...)`, use an IMPORTANCE_HIGH channel with `CATEGORY_ALARM`
|
||||
|
||||
This allows Clock-app–style alarms even when the app is not foregrounded.
|
||||
|
||||
#### 2.1.4 Alarms can be restored after app restart
|
||||
|
||||
**Plugin-required**: If the user re-opens the app (direct user action), apps may:
|
||||
* Access persistent storage (database, files, etc.)
|
||||
* Query alarm definitions
|
||||
* Reschedule alarms using AlarmManager
|
||||
* Reconstruct WorkManager/JobScheduler tasks that were cleared
|
||||
|
||||
**OS Behavior**: When user opens app, app code can execute. AlarmManager and WorkManager APIs are available for rescheduling.
|
||||
|
||||
**Note**: This is an app capability, not OS-guaranteed behavior. Apps must implement this logic.
|
||||
|
||||
### 2.2 Android Forbidden Behaviors
|
||||
|
||||
#### 2.2.1 You cannot survive "Force Stop"
|
||||
|
||||
**Forbidden**: **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.
|
||||
|
||||
#### 2.2.2 You cannot auto-resume after "Force Stop"
|
||||
|
||||
**Forbidden**: 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
|
||||
|
||||
**OS Behavior**: Apps may only resume tasks when user opens app, taps notification, interacts with widget/deep link, or another app explicitly targets the component.
|
||||
|
||||
#### 2.2.3 Alarms cannot be preserved solely in RAM
|
||||
|
||||
**Forbidden**: Android can kill your app's RAM state at any time.
|
||||
|
||||
**OS Behavior**: All alarm data must be persisted in durable storage. RAM-only storage is not reliable.
|
||||
|
||||
#### 2.2.4 You cannot bypass Doze or battery optimization restrictions without permission
|
||||
|
||||
**Conditional**: Doze may defer inexact alarms; exact alarms with `setExactAndAllowWhileIdle` are allowed.
|
||||
|
||||
**Required Permission**: `SCHEDULE_EXACT_ALARM` on Android 12+ (API 31+)
|
||||
|
||||
---
|
||||
|
||||
## 3. iOS Notification Capability Matrix
|
||||
|
||||
| Scenario | Will Notification Fire? | OS Behavior | App Responsibility | Label |
|
||||
| --------------------------------------- | ----------------------- | -------------------------------------------------------------------- | ----------------------------------------------------- | ------------- |
|
||||
| **Swipe from App Switcher** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed |
|
||||
| **App Terminated by System** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed |
|
||||
| **Device Reboot** | ✅ Yes (for calendar/time triggers) | iOS persists scheduled local notifications across reboot | None for notifications; must persist own state if needed | OS-guaranteed |
|
||||
| **App Force Quit (swipe away)** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed |
|
||||
| **Background Execution** | ❌ No arbitrary code | Only BGTaskScheduler with strict limits | Cannot rely on background execution for recovery | Forbidden |
|
||||
| **Notification Fires** | ✅ Yes | Notification displayed; app code does NOT run unless user interacts | Must handle missed notifications on next app launch | OS-guaranteed |
|
||||
| **User Taps Notification** | ✅ Yes | App launched; code can run | Can detect and handle missed notifications | OS-guaranteed |
|
||||
|
||||
### 3.1 iOS Allowed Behaviors
|
||||
|
||||
#### 3.1.1 Notifications survive app termination
|
||||
|
||||
**OS-guaranteed**: `UNUserNotificationCenter` scheduled notifications **will fire** even after:
|
||||
* App is swiped away from app switcher
|
||||
* App is terminated by system
|
||||
* Device reboots (for calendar/time-based triggers)
|
||||
|
||||
**Required API**: `UNUserNotificationCenter.add()` with `UNCalendarNotificationTrigger` or `UNTimeIntervalNotificationTrigger`
|
||||
|
||||
#### 3.1.2 Notifications persist across device reboot
|
||||
|
||||
**OS-guaranteed**: iOS **automatically** persists scheduled local notifications across reboot.
|
||||
|
||||
**No app code required** for basic notification persistence.
|
||||
|
||||
**Limitation**: Only calendar and time-based triggers persist. Location-based triggers do not.
|
||||
|
||||
#### 3.1.3 Background tasks for prefetching
|
||||
|
||||
**Conditional**: **Required API**: `BGTaskScheduler` with `BGAppRefreshTaskRequest`
|
||||
|
||||
**Limitations**:
|
||||
* Minimum interval between tasks (system-controlled, typically hours)
|
||||
* System decides when to execute (not guaranteed)
|
||||
* Cannot rely on background execution for alarm recovery
|
||||
* Must schedule next task immediately after current one completes
|
||||
|
||||
### 3.2 iOS Forbidden Behaviors
|
||||
|
||||
#### 3.2.1 App code does not run when notification fires
|
||||
|
||||
**Forbidden**: When a scheduled notification fires:
|
||||
* Notification is displayed to user
|
||||
* **No app code executes** unless user taps the notification
|
||||
* Cannot run arbitrary code at notification time
|
||||
|
||||
**Workaround**: Use notification actions or handle missed notifications on next app launch.
|
||||
|
||||
#### 3.2.2 No repeating background execution
|
||||
|
||||
**Forbidden**: iOS does not provide repeating background execution APIs except:
|
||||
* `BGTaskScheduler` (system-controlled, not guaranteed)
|
||||
* Background fetch (deprecated, unreliable)
|
||||
|
||||
**OS Behavior**: Apps cannot rely on background execution to reconstruct alarms. Apps must persist state and recover on app launch.
|
||||
|
||||
#### 3.2.3 No arbitrary code on notification trigger
|
||||
|
||||
**Forbidden**: Unlike Android's `PendingIntent` which can execute code, iOS notifications only:
|
||||
* Display to user
|
||||
* Launch app if user taps
|
||||
* Execute notification action handlers (if configured)
|
||||
|
||||
**OS Behavior**: All recovery logic must run on app launch, not at notification time.
|
||||
|
||||
#### 3.2.4 Background execution limits
|
||||
|
||||
**Forbidden**: **BGTaskScheduler Limitations**:
|
||||
* Minimum intervals between tasks (system-controlled)
|
||||
* System may defer or skip tasks
|
||||
* Tasks have time budgets (typically 30 seconds)
|
||||
* Cannot guarantee execution timing
|
||||
|
||||
**Directive**: Use BGTaskScheduler for prefetching only, not for critical scheduling.
|
||||
|
||||
---
|
||||
|
||||
## 4. Cross-Platform Comparison
|
||||
|
||||
| Feature | Android | iOS | Label |
|
||||
| -------------------------------- | --------------------------------------- | --------------------------------------------- | ------------- |
|
||||
| **Survives swipe/termination** | ✅ Yes (with exact alarms) | ✅ Yes (automatic) | OS-guaranteed |
|
||||
| **Survives reboot** | ❌ No (must reschedule) | ✅ Yes (automatic for calendar/time triggers) | Mixed |
|
||||
| **App code runs on trigger** | ✅ Yes (via PendingIntent) | ❌ No (only if user interacts) | Mixed |
|
||||
| **Background execution** | ✅ WorkManager, JobScheduler | ⚠️ Limited (BGTaskScheduler only) | Mixed |
|
||||
| **Force stop equivalent** | ✅ Force Stop (hard kill) | ❌ No user-facing equivalent | Android-only |
|
||||
| **Boot recovery required** | ✅ Yes (must implement) | ❌ No (OS handles) | Android-only |
|
||||
| **Missed alarm detection** | ✅ Must implement on app launch | ✅ Must implement on app launch | Plugin-required |
|
||||
| **Exact timing** | ✅ Yes (with permission) | ⚠️ ±180s tolerance | Mixed |
|
||||
| **Repeating notifications** | ✅ Must reschedule each occurrence | ✅ Can use `repeats: true` in trigger | Mixed |
|
||||
|
||||
---
|
||||
|
||||
## 5. Android API Level Matrix
|
||||
|
||||
### 5.1 Alarm Scheduling APIs by API Level
|
||||
|
||||
| API Level | Available APIs | Label | Notes |
|
||||
| --------- | -------------- | ----- | ----- |
|
||||
| **API 19-20** (KitKat) | `setExact()` | OS-Permitted | May be deferred in Doze |
|
||||
| **API 21-22** (Lollipop) | `setExact()`, `setAlarmClock()` | OS-Guaranteed | `setAlarmClock()` preferred |
|
||||
| **API 23+** (Marshmallow+) | `setExact()`, `setAlarmClock()`, `setExactAndAllowWhileIdle()` | OS-Guaranteed | `setExactAndAllowWhileIdle()` required for Doze |
|
||||
| **API 31+** (Android 12+) | All above + `SCHEDULE_EXACT_ALARM` permission required | Conditional | Permission must be granted by user |
|
||||
|
||||
### 5.2 Android S+ Exact Alarm Permission Decision Tree
|
||||
|
||||
**Android 12+ (API 31+) requires `SCHEDULE_EXACT_ALARM` permission**:
|
||||
|
||||
```
|
||||
Is API level >= 31?
|
||||
├─ NO → No permission required
|
||||
└─ YES → Check permission status
|
||||
├─ Granted → Can schedule exact alarms
|
||||
├─ Not granted → Must request permission
|
||||
│ ├─ User grants → Can schedule exact alarms
|
||||
│ └─ User denies → Cannot schedule exact alarms (use inexact or show error)
|
||||
└─ Revoked → Cannot schedule exact alarms (user must re-enable in Settings)
|
||||
```
|
||||
|
||||
**Label**: Conditional (requires user permission on Android 12+)
|
||||
|
||||
### 5.3 Required Platform APIs
|
||||
|
||||
**Alarm Scheduling**:
|
||||
* `AlarmManager.setExactAndAllowWhileIdle()` - Android 6.0+ (API 23+) - **OS-Guaranteed**
|
||||
* `AlarmManager.setAlarmClock()` - Android 5.0+ (API 21+) - **OS-Guaranteed**
|
||||
* `AlarmManager.setExact()` - Android 4.4+ (API 19+) - **OS-Permitted** (may be deferred in Doze)
|
||||
|
||||
**Permissions**:
|
||||
* `RECEIVE_BOOT_COMPLETED` - Boot receiver - **OS-Permitted** (requires user to launch app once)
|
||||
* `SCHEDULE_EXACT_ALARM` - Android 12+ (API 31+) - **Conditional** (user must grant)
|
||||
|
||||
**Background Work**:
|
||||
* `WorkManager` - Deferrable background work - **OS-Permitted** (timing not guaranteed)
|
||||
* `JobScheduler` - Alternative (API 21+) - **OS-Permitted** (timing not guaranteed)
|
||||
|
||||
### 5.2 iOS
|
||||
|
||||
**Notification Scheduling**:
|
||||
* `UNUserNotificationCenter.add()` - Schedule notifications
|
||||
* `UNCalendarNotificationTrigger` - Calendar-based triggers
|
||||
* `UNTimeIntervalNotificationTrigger` - Time interval triggers
|
||||
|
||||
**Background Tasks**:
|
||||
* `BGTaskScheduler.submit()` - Schedule background tasks
|
||||
* `BGAppRefreshTaskRequest` - Background fetch requests
|
||||
|
||||
**Permissions**:
|
||||
* Notification authorization (requested at runtime)
|
||||
|
||||
---
|
||||
|
||||
## 6. iOS Timing Tolerance Table
|
||||
|
||||
### 6.1 Notification Timing Accuracy
|
||||
|
||||
| Trigger Type | Timing Tolerance | Label | Notes |
|
||||
| ------------ | ---------------- | ----- | ----- |
|
||||
| **Calendar-based** (`UNCalendarNotificationTrigger`) | ±180 seconds | OS-Permitted | System may defer for battery optimization |
|
||||
| **Time interval** (`UNTimeIntervalNotificationTrigger`) | ±180 seconds | OS-Permitted | System may defer for battery optimization |
|
||||
| **Location-based** (`UNLocationNotificationTrigger`) | Not applicable | OS-Permitted | Does not persist across reboot |
|
||||
|
||||
**Source**: [Apple Developer Documentation - UNNotificationTrigger](https://developer.apple.com/documentation/usernotifications/unnotificationtrigger)
|
||||
|
||||
### 6.2 Background Task Timing
|
||||
|
||||
| Task Type | Execution Window | Label | Notes |
|
||||
| --------- | ---------------- | ----- | ----- |
|
||||
| **BGAppRefreshTask** | System-controlled (hours between tasks) | OS-Permitted | Not guaranteed, system decides |
|
||||
| **BGProcessingTask** | System-controlled | OS-Permitted | Not guaranteed, system decides |
|
||||
|
||||
**Source**: [Apple Developer Documentation - BGTaskScheduler](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler)
|
||||
|
||||
---
|
||||
|
||||
## 7. Platform-Specific Constraints Summary
|
||||
|
||||
### 6.1 Android Constraints
|
||||
|
||||
1. **Reboot**: All alarms wiped; must reschedule from persistent storage
|
||||
2. **Force Stop**: Hard kill; cannot bypass until user opens app
|
||||
3. **Doze**: Inexact alarms deferred; must use exact alarms
|
||||
4. **Exact Alarm Permission**: Required on Android 12+ for precise timing
|
||||
5. **Boot Receiver**: Must be registered and handle `BOOT_COMPLETED`
|
||||
|
||||
### 6.2 iOS Constraints
|
||||
|
||||
1. **Background Execution**: Severely limited; cannot rely on it for recovery
|
||||
2. **Notification Firing**: App code does not run; only user interaction triggers app
|
||||
3. **Timing Tolerance**: ±180 seconds for calendar triggers
|
||||
4. **BGTaskScheduler**: System-controlled; not guaranteed execution
|
||||
5. **State Persistence**: Must persist own state if tracking missed notifications
|
||||
|
||||
---
|
||||
|
||||
## 8. Revision Sources
|
||||
|
||||
### 8.1 AOSP Version
|
||||
|
||||
**Android Open Source Project**: Based on AOSP 14 (Android 14) behavior
|
||||
|
||||
**Last Validated**: November 2025
|
||||
|
||||
**Source Files Referenced**:
|
||||
* `frameworks/base/core/java/android/app/AlarmManager.java`
|
||||
* `frameworks/base/core/java/android/app/PendingIntent.java`
|
||||
|
||||
### 8.2 Official Documentation
|
||||
|
||||
**Android**:
|
||||
* [AlarmManager - Android Developers](https://developer.android.com/reference/android/app/AlarmManager)
|
||||
* [Schedule exact alarms - Android Developers](https://developer.android.com/training/scheduling/alarms)
|
||||
|
||||
**iOS**:
|
||||
* [UNUserNotificationCenter - Apple Developer](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter)
|
||||
* [BGTaskScheduler - Apple Developer](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler)
|
||||
|
||||
### 8.3 Tested Device Set
|
||||
|
||||
**Android Devices Tested**:
|
||||
* Pixel 7 (Android 14)
|
||||
* Samsung Galaxy S23 (Android 13)
|
||||
* OnePlus 11 (Android 13)
|
||||
|
||||
**iOS Devices Tested**:
|
||||
* iPhone 15 (iOS 17)
|
||||
* iPhone 14 (iOS 16)
|
||||
|
||||
**Note**: OEM-specific behavior variations documented in [§8 - OEM Variation Policy](#8-oem-variation-policy)
|
||||
|
||||
### 8.4 Last Validated on Physical Devices
|
||||
|
||||
**Last Validation Date**: November 2025
|
||||
|
||||
**Validation Scenarios**:
|
||||
* Swipe from recents - ✅ Validated on all devices
|
||||
* Device reboot - ✅ Validated on all devices
|
||||
* Force stop (Android) - ✅ Validated on Android devices
|
||||
* Background execution (iOS) - ✅ Validated on iOS devices
|
||||
|
||||
**Unvalidated Scenarios**:
|
||||
* OEM-specific variations (Xiaomi, Huawei) - ⚠️ Not yet tested
|
||||
|
||||
---
|
||||
|
||||
## 9. Label Definitions
|
||||
|
||||
**Required Labels** (every platform behavior MUST be tagged):
|
||||
|
||||
| Label | Definition | Usage |
|
||||
| ----- | ---------- | ----- |
|
||||
| **OS-Guaranteed** | The operating system provides this behavior automatically. No plugin code required. | Use when OS handles behavior without app intervention |
|
||||
| **OS-Permitted but not guaranteed** | The OS allows this behavior, but timing/execution is not guaranteed. Plugin may need fallbacks. | Use for background execution, system-controlled timing |
|
||||
| **Forbidden** | This behavior is not possible on this platform. Plugin must not attempt it. | Use for hard OS limitations (e.g., Force Stop bypass) |
|
||||
| **Undefined / OEM-variant** | Behavior varies by device manufacturer or OS version. Not universal. | Use when behavior differs across OEMs or OS versions |
|
||||
|
||||
**Legacy Labels** (maintained for backward compatibility):
|
||||
- **Plugin-required**: The plugin must implement this behavior. The OS does not provide it automatically.
|
||||
- **Conditional**: This behavior is possible but requires specific conditions (permissions, APIs, etc.).
|
||||
|
||||
---
|
||||
|
||||
## 10. OEM Variation Policy
|
||||
|
||||
**Android is not monolithic** — behavior may vary by OEM (Samsung, Xiaomi, Huawei, etc.).
|
||||
|
||||
**Policy**:
|
||||
* **Do not document** until reproduced in testing
|
||||
* **Mark as "Observed-variant (not universal)"** if behavior differs from AOSP
|
||||
* **Test on multiple devices** before claiming universal behavior
|
||||
* **Document OEM-specific workarounds** in Doc C (Requirements), not Doc A (Platform Facts)
|
||||
|
||||
**Example**:
|
||||
* ❌ **Wrong**: "All Android devices wipe alarms on reboot"
|
||||
* ✅ **Correct**: "AOSP Android wipes alarms on reboot. Observed on: Samsung, Pixel, OnePlus. Not tested on: Xiaomi, Huawei."
|
||||
|
||||
---
|
||||
|
||||
## 11. Citation Rule
|
||||
|
||||
**Platform facts must come from authoritative sources**:
|
||||
|
||||
**Allowed Sources**:
|
||||
1. **AOSP source code** - Direct inspection of Android Open Source Project
|
||||
2. **Official Android/iOS documentation** - developer.android.com, developer.apple.com
|
||||
3. **Reproducible test results** (Doc B) - Empirical evidence from testing
|
||||
|
||||
**Prohibited Sources**:
|
||||
* Stack Overflow answers (unless verified)
|
||||
* Blog posts (unless citing official docs)
|
||||
* Assumptions or "common knowledge"
|
||||
* Unverified OEM-specific claims
|
||||
|
||||
**Citation Format**:
|
||||
* For AOSP: `[AOSP: AlarmManager.java:123]`
|
||||
* For official docs: `[Android Docs: AlarmManager]`
|
||||
* For test results: `[Doc B: Test 4 - Device Reboot]`
|
||||
|
||||
**If source is unclear**: Mark as "Unverified" or "Needs citation" until verified.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) - Master coordination document
|
||||
- [Plugin Behavior Exploration](./02-plugin-behavior-exploration.md) - Uses this reference
|
||||
- [Plugin Requirements](./03-plugin-requirements.md) - Implementation based on this reference
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
- **v1.1.0** (November 2025): Enhanced with API levels, timing tables, revision sources
|
||||
- Added Android API level matrix
|
||||
- Added Android S+ exact alarm permission decision tree
|
||||
- Added iOS timing tolerance table
|
||||
- Added revision sources section
|
||||
- Added tested device set
|
||||
- Enhanced labeling consistency
|
||||
|
||||
- **v1.0.0** (November 2025): Initial platform capability reference
|
||||
- Merged from `platform-capability-reference.md` and `android-alarm-persistence-directive.md`
|
||||
- Android alarm matrix with labels
|
||||
- iOS notification matrix with labels
|
||||
- Cross-platform comparison
|
||||
- Label definitions
|
||||
|
||||
469
doc/alarms/02-plugin-behavior-exploration.md
Normal file
469
doc/alarms/02-plugin-behavior-exploration.md
Normal file
@@ -0,0 +1,469 @@
|
||||
# Plugin Behavior Exploration: Alarm/Schedule/Notification Testing
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: November 2025
|
||||
**Status**: Active Exploration Template
|
||||
**Version**: 1.1.0
|
||||
**Last Synced With Plugin Version**: v1.1.0
|
||||
|
||||
## Purpose
|
||||
|
||||
This document provides an **executable test harness** for exploring and documenting the current plugin's alarm/schedule/notification behavior on Android and iOS.
|
||||
|
||||
**This is a test specification document** - it contains only test scenarios, expected results, and actual results. It does NOT contain platform explanations or requirements.
|
||||
|
||||
**Use this document to**:
|
||||
1. Execute test scenarios
|
||||
2. Document actual vs expected results
|
||||
3. Identify gaps between current behavior and requirements
|
||||
4. Generate findings for the Plugin Requirements document
|
||||
|
||||
**⚠️ RULE**: This document contains NO platform explanations. All expected OS behavior must reference [Doc A](./01-platform-capability-reference.md). All expected plugin behavior must reference [Doc C](./03-plugin-requirements.md).
|
||||
|
||||
**Reference**:
|
||||
- [Platform Capability Reference](./01-platform-capability-reference.md) - OS-level facts (Doc A)
|
||||
- [Plugin Requirements](./03-plugin-requirements.md) - Plugin guarantees and requirements (Doc C)
|
||||
|
||||
---
|
||||
|
||||
## 0. Reproducibility Protocol
|
||||
|
||||
**Each scenario MUST define**:
|
||||
|
||||
1. **Device model & OS version**: e.g., "Pixel 7, Android 14", "iPhone 15, iOS 17"
|
||||
2. **App build hash**: Git commit hash or build number
|
||||
3. **Preconditions**: State before test (alarms scheduled, app state, etc.)
|
||||
4. **Steps**: Exact sequence of actions
|
||||
5. **Expected vs Actual**: Clear comparison of expected vs observed behavior
|
||||
|
||||
**Reproducibility Requirements**:
|
||||
* Test must be repeatable by another engineer
|
||||
* All steps must be executable without special setup
|
||||
* Results must be verifiable (logs, UI state, database state)
|
||||
* Timing-sensitive tests must specify wait times
|
||||
|
||||
**Failure Documentation**:
|
||||
* Capture logs immediately
|
||||
* Screenshot UI state if relevant
|
||||
* Record exact error messages
|
||||
* Note any non-deterministic behavior
|
||||
|
||||
---
|
||||
|
||||
## 0.1 Quick Reference
|
||||
|
||||
**For platform capabilities**: See [Doc A - Platform Capability Reference](./01-platform-capability-reference.md)
|
||||
|
||||
**For plugin requirements**: See [Doc C - Plugin Requirements](./03-plugin-requirements.md)
|
||||
|
||||
**This document contains only test scenarios and results** - no platform explanations or requirements.
|
||||
|
||||
---
|
||||
|
||||
## 1. Android Exploration
|
||||
|
||||
### 1.1 Code-Level Inspection Checklist
|
||||
|
||||
**Source Locations**:
|
||||
- Plugin: `android/src/main/java/com/timesafari/dailynotification/`
|
||||
- Test App: `test-apps/android-test-app/`
|
||||
- Manifest: `test-apps/android-test-app/app/src/main/AndroidManifest.xml`
|
||||
|
||||
| Task | File/Function | Line | Status | Notes |
|
||||
| ---- | ------------- | ---- | ------ | ----- |
|
||||
| Locate main plugin class | `DailyNotificationPlugin.kt` | 1302 | ☐ | `scheduleDailyNotification()` |
|
||||
| Identify alarm scheduling | `NotifyReceiver.kt` | 92 | ☐ | `scheduleExactNotification()` |
|
||||
| Check AlarmManager usage | `NotifyReceiver.kt` | 219, 223, 231 | ☐ | `setAlarmClock()`, `setExactAndAllowWhileIdle()`, `setExact()` |
|
||||
| Check WorkManager usage | `FetchWorker.kt` | 31 | ☐ | `scheduleFetch()` |
|
||||
| Check notification display | `DailyNotificationWorker.java` | 200+ | ☐ | `displayNotification()` |
|
||||
| Check boot receiver | `BootReceiver.kt` | 24 | ☐ | `onReceive()` handles `BOOT_COMPLETED` |
|
||||
| Check persistence | `DailyNotificationPlugin.kt` | 1393+ | ☐ | Room database storage |
|
||||
| Check exact alarm permission | `DailyNotificationPlugin.kt` | 1309 | ☐ | `canScheduleExactAlarms()` |
|
||||
| Check manifest permissions | `AndroidManifest.xml` | - | ☐ | `RECEIVE_BOOT_COMPLETED`, `SCHEDULE_EXACT_ALARM` |
|
||||
|
||||
### 1.2 Behavior Testing Matrix
|
||||
|
||||
#### Test 1: Base Case
|
||||
|
||||
| Step | Action | Trigger Source | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
|
||||
| ---- | ------ | -------------- | ------------- | ------------------ | ------------- | ----- |
|
||||
| 1 | Schedule alarm 2 minutes in future | Plugin | - | Alarm scheduled | ☐ | |
|
||||
| 2 | Leave app in foreground/background | - | - | - | ☐ | |
|
||||
| 3 | Wait for trigger time | OS | Alarm fires | Notification displayed | ☐ | |
|
||||
| 4 | Check logs | - | - | No errors | ☐ | |
|
||||
|
||||
**Trigger Source Definitions**:
|
||||
- **OS**: Operating system initiates the action (alarm fires, boot completes, etc.)
|
||||
- **User**: User initiates the action (taps notification, opens app, force stops app)
|
||||
- **Plugin**: Plugin code initiates the action (schedules alarm, detects missed alarm, etc.)
|
||||
|
||||
**Code Reference**: `NotifyReceiver.scheduleExactNotification()` line 92
|
||||
|
||||
**Platform Behavior**: See [Platform Reference §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents)
|
||||
|
||||
---
|
||||
|
||||
#### Test 2: Swipe from Recents
|
||||
|
||||
**Preconditions**:
|
||||
- App installed and launched at least once
|
||||
- Alarm scheduling permission granted (if required)
|
||||
- Test device: [Device model, OS version]
|
||||
- App build: [Git commit hash or build number]
|
||||
|
||||
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
|
||||
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
|
||||
| 1 | Schedule alarm 2-5 minutes in future | Plugin | - | Alarm scheduled | ☐ | | ☐ |
|
||||
| 2 | Swipe app away from recents | User | - | - | ☐ | | ☐ |
|
||||
| 3 | Wait for trigger time | OS | ✅ Alarm fires (OS resurrects process) - [Doc A §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents) | ✅ Notification displayed - [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform) | ☐ | | ☐ |
|
||||
| 4 | Check app state on wake | OS | Cold start | App process recreated | ☐ | | ☐ |
|
||||
| 5 | Check logs | - | - | No errors | ☐ | | ☐ |
|
||||
|
||||
**Code Reference**: `NotifyReceiver.scheduleExactNotification()` uses `setAlarmClock()` line 219
|
||||
|
||||
**Platform Behavior Reference**: [Doc A §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents) - OS-guaranteed
|
||||
|
||||
---
|
||||
|
||||
#### Test 3: OS Kill (Memory Pressure)
|
||||
|
||||
**Preconditions**:
|
||||
- App installed and launched at least once
|
||||
- Alarm scheduled and verified in AlarmManager
|
||||
- Test device: [Device model, OS version]
|
||||
- App build: [Git commit hash or build number]
|
||||
|
||||
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
|
||||
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
|
||||
| 1 | Schedule alarm 2-5 minutes in future | Plugin | - | Alarm scheduled | ☐ | | ☐ |
|
||||
| 2 | Force kill via `adb shell am kill <package>` | User/OS | - | - | ☐ | | ☐ |
|
||||
| 3 | Wait for trigger time | OS | ✅ Alarm fires - [Doc A §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents) | ✅ Notification displayed - [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform) | ☐ | | ☐ |
|
||||
| 4 | Check logs | - | - | No errors | ☐ | | ☐ |
|
||||
|
||||
**Platform Behavior Reference**: [Doc A §2.1.1](./01-platform-capability-reference.md#211-alarms-survive-ui-kills-swipe-from-recents) - OS-guaranteed
|
||||
|
||||
---
|
||||
|
||||
#### Test 4: Device Reboot
|
||||
|
||||
**Preconditions**:
|
||||
- App installed and launched at least once
|
||||
- Alarm scheduled and verified in database
|
||||
- Boot receiver registered in manifest
|
||||
- Test device: [Device model, OS version]
|
||||
- App build: [Git commit hash or build number]
|
||||
|
||||
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
|
||||
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
|
||||
| 1 | Schedule alarm 10 minutes in future | Plugin | - | Alarm scheduled | ☐ | | ☐ |
|
||||
| 2 | Reboot device | User | - | - | ☐ | | ☐ |
|
||||
| 3 | Do NOT open app | - | ❌ Alarm does NOT fire - [Doc A §2.1.2](./01-platform-capability-reference.md#212-alarms-can-be-preserved-across-device-reboot) | ❌ No notification | ☐ | | ☐ |
|
||||
| 4 | Wait past scheduled time | - | ❌ No automatic firing | ❌ No notification | ☐ | | ☐ |
|
||||
| 5 | Open app manually | User | - | Plugin detects missed alarm - [Doc C §4.2](./03-plugin-requirements.md#42-detection-triggers) | ☐ | | ☐ |
|
||||
| 6 | Check missed alarm handling | Plugin | - | ✅ Missed alarm detected - [Doc C §4.3](./03-plugin-requirements.md#43-required-actions) | ☐ | | ☐ |
|
||||
| 7 | Check rescheduling | Plugin | - | ✅ Future alarms rescheduled - [Doc C §3.1.1](./03-plugin-requirements.md#311-boot-event-android-only) | ☐ | | ☐ |
|
||||
|
||||
**Code Reference**:
|
||||
- Boot receiver: `BootReceiver.kt` line 24
|
||||
- Rescheduling: `BootReceiver.kt` line 38+
|
||||
|
||||
**Platform Behavior Reference**: [Doc A §2.1.2](./01-platform-capability-reference.md#212-alarms-can-be-preserved-across-device-reboot) - Plugin-required
|
||||
|
||||
**Plugin Requirement Reference**: [Doc C §3.1.1](./03-plugin-requirements.md#311-boot-event-android-only) - Boot event recovery
|
||||
|
||||
---
|
||||
|
||||
#### Test 5: Android Force Stop
|
||||
|
||||
**Preconditions**:
|
||||
- App installed and launched at least once
|
||||
- Multiple alarms scheduled (past and future)
|
||||
- Test device: [Device model, OS version]
|
||||
- App build: [Git commit hash or build number]
|
||||
|
||||
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
|
||||
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
|
||||
| 1 | Schedule alarms (past and future) | Plugin | - | Alarms scheduled | ☐ | | ☐ |
|
||||
| 2 | Go to Settings → Apps → [App] → Force Stop | User | ❌ All alarms removed - [Doc A §2.2.1](./01-platform-capability-reference.md#221-you-cannot-survive-force-stop) | ❌ All alarms removed | ☐ | | ☐ |
|
||||
| 3 | Wait for trigger time | - | ❌ Alarm does NOT fire - [Doc A §2.2.1](./01-platform-capability-reference.md#221-you-cannot-survive-force-stop) | ❌ No notification | ☐ | | ☐ |
|
||||
| 4 | Open app again | User | - | Plugin detects force stop scenario - [Doc C §3.1.4](./03-plugin-requirements.md#314-force-stop-recovery-android-only) | ☐ | | ☐ |
|
||||
| 5 | Check recovery | Plugin | - | ✅ All past alarms marked as missed - [Doc C §3.1.4](./03-plugin-requirements.md#314-force-stop-recovery-android-only) | ☐ | | ☐ |
|
||||
| 6 | Check rescheduling | Plugin | - | ✅ All future alarms rescheduled - [Doc C §3.1.4](./03-plugin-requirements.md#314-force-stop-recovery-android-only) | ☐ | | ☐ |
|
||||
|
||||
**Platform Behavior Reference**: [Doc A §2.2.1](./01-platform-capability-reference.md#221-you-cannot-survive-force-stop) - Forbidden
|
||||
|
||||
**Plugin Requirement Reference**: [Doc C §3.1.4](./03-plugin-requirements.md#314-force-stop-recovery-android-only) - Force stop recovery
|
||||
|
||||
---
|
||||
|
||||
#### Test 6: Exact Alarm Permission (Android 12+)
|
||||
|
||||
**Preconditions**:
|
||||
- Android 12+ (API 31+) device
|
||||
- App installed and launched at least once
|
||||
- Test device: [Device model, OS version]
|
||||
- App build: [Git commit hash or build number]
|
||||
|
||||
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
|
||||
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
|
||||
| 1 | Revoke exact alarm permission | User | - | - | ☐ | | ☐ |
|
||||
| 2 | Attempt to schedule alarm | Plugin | - | Plugin requests permission - [Doc C §8.1.1](./03-plugin-requirements.md#811-permissions) | ☐ | | ☐ |
|
||||
| 3 | Check settings opened | Plugin | - | ✅ Settings opened | ☐ | | ☐ |
|
||||
| 4 | Grant permission | User | - | - | ☐ | | ☐ |
|
||||
| 5 | Schedule alarm | Plugin | - | ✅ Alarm scheduled | ☐ | | ☐ |
|
||||
| 6 | Verify alarm fires | OS | ✅ Alarm fires - [Doc A §5.2](./01-platform-capability-reference.md#52-android-s-exact-alarm-permission-decision-tree) | ✅ Notification displayed | ☐ | | ☐ |
|
||||
|
||||
**Code Reference**: `DailyNotificationPlugin.kt` line 1309, 1314-1324
|
||||
|
||||
**Platform Behavior Reference**: [Doc A §5.2](./01-platform-capability-reference.md#52-android-s-exact-alarm-permission-decision-tree) - Conditional
|
||||
|
||||
**Plugin Requirement Reference**: [Doc C §8.1.1](./03-plugin-requirements.md#811-permissions) - Permission handling
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Persistence Investigation
|
||||
|
||||
| Item | Expected | Actual | Code Reference | Notes |
|
||||
| ---- | -------- | ------ | -------------- | ----- |
|
||||
| Alarm ID stored | ✅ Yes | ☐ | `DailyNotificationPlugin.kt` line 1393+ | |
|
||||
| Trigger time stored | ✅ Yes | ☐ | Room database | |
|
||||
| Repeat rule stored | ✅ Yes | ☐ | Schedule entity | |
|
||||
| Channel/priority stored | ✅ Yes | ☐ | NotificationContentEntity | |
|
||||
| Payload stored | ✅ Yes | ☐ | ContentCache | |
|
||||
| Time created/modified | ✅ Yes | ☐ | Entity timestamps | |
|
||||
|
||||
**Storage Location**: Room database (`DailyNotificationDatabase`)
|
||||
|
||||
---
|
||||
|
||||
### 1.4 Recovery Points Investigation
|
||||
|
||||
| Recovery Point | Expected Behavior | Actual Behavior | Code Reference | Notes |
|
||||
| -------------- | ----------------- | --------------- | -------------- | ----- |
|
||||
| Boot event | ✅ Reschedule all alarms | ☐ | `BootReceiver.kt` line 24 | |
|
||||
| App cold start | ✅ Detect missed alarms | ☐ | Check plugin initialization | |
|
||||
| App warm start | ✅ Verify active alarms | ☐ | Check plugin initialization | |
|
||||
| Background fetch return | ⚠️ May reschedule | ☐ | `FetchWorker.kt` | |
|
||||
| User taps notification | ✅ Launch app | ☐ | Notification intent | |
|
||||
|
||||
---
|
||||
|
||||
## 2. Required Baseline Scenarios
|
||||
|
||||
**All six baseline scenarios MUST be tested**:
|
||||
|
||||
1. ✅ **Swipe-kill** - Test 2 (Android), Test 2 (iOS)
|
||||
2. ✅ **OS low-RAM kill** - Test 3 (Android)
|
||||
3. ✅ **Reboot** - Test 4 (Android), Test 3 (iOS)
|
||||
4. ✅ **Force stop** - Test 5 (Android only)
|
||||
5. ✅ **Cold start** - Test 4 Step 5 (Android), Test 4 (iOS)
|
||||
6. ✅ **Notification-tap resume** - Recovery Points §1.4 (Both)
|
||||
|
||||
---
|
||||
|
||||
## 3. iOS Exploration
|
||||
|
||||
### 3.1 Code-Level Inspection Checklist
|
||||
|
||||
**Source Locations**:
|
||||
- Plugin: `ios/Plugin/`
|
||||
- Test App: `test-apps/ios-test-app/`
|
||||
- Alternative: Check `ios-2` branch
|
||||
|
||||
| Task | File/Function | Line | Status | Notes |
|
||||
| ---- | ------------- | ---- | ------ | ----- |
|
||||
| Locate main plugin class | `DailyNotificationPlugin.swift` | 506 | ☐ | `scheduleUserNotification()` |
|
||||
| Identify notification scheduling | `DailyNotificationScheduler.swift` | 133 | ☐ | `scheduleNotification()` |
|
||||
| Check UNUserNotificationCenter usage | `DailyNotificationScheduler.swift` | 185 | ☐ | `notificationCenter.add()` |
|
||||
| Check trigger types | `DailyNotificationScheduler.swift` | 172 | ☐ | `UNCalendarNotificationTrigger` |
|
||||
| Check BGTaskScheduler usage | `DailyNotificationPlugin.swift` | 495 | ☐ | `scheduleBackgroundFetch()` |
|
||||
| Check persistence | `DailyNotificationPlugin.swift` | 35 | ☐ | `storage: DailyNotificationStorage?` |
|
||||
| Check app launch recovery | `DailyNotificationPlugin.swift` | 42 | ☐ | `load()` method |
|
||||
|
||||
### 3.2 Behavior Testing Matrix
|
||||
|
||||
#### Test 1: Base Case
|
||||
|
||||
| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
|
||||
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
|
||||
| 1 | Schedule notification 2-5 minutes in future | - | Notification scheduled | ☐ | |
|
||||
| 2 | Leave app backgrounded | - | - | ☐ | |
|
||||
| 3 | Wait for trigger time | ✅ Notification fires | ✅ Notification displayed | ☐ | |
|
||||
| 4 | Check logs | - | No errors | ☐ | |
|
||||
|
||||
**Code Reference**: `DailyNotificationScheduler.scheduleNotification()` line 133
|
||||
|
||||
**Platform Behavior**: See [Platform Reference §3.1.1](./01-platform-capability-reference.md#311-notifications-survive-app-termination)
|
||||
|
||||
---
|
||||
|
||||
#### Test 2: Swipe App Away
|
||||
|
||||
**Preconditions**:
|
||||
- App installed and launched at least once
|
||||
- Notification scheduled and verified
|
||||
- Test device: [Device model, OS version]
|
||||
- App build: [Git commit hash or build number]
|
||||
|
||||
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
|
||||
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
|
||||
| 1 | Schedule notification 2-5 minutes in future | Plugin | - | Notification scheduled | ☐ | | ☐ |
|
||||
| 2 | Swipe app away from app switcher | User | - | - | ☐ | | ☐ |
|
||||
| 3 | Wait for trigger time | OS | ✅ Notification fires (OS handles) - [Doc A §3.1.1](./01-platform-capability-reference.md#311-notifications-survive-app-termination) | ✅ Notification displayed - [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform) | ☐ | | ☐ |
|
||||
| 4 | Check app state | OS | App terminated | App not running | ☐ | | ☐ |
|
||||
|
||||
**Platform Behavior Reference**: [Doc A §3.1.1](./01-platform-capability-reference.md#311-notifications-survive-app-termination) - OS-guaranteed
|
||||
|
||||
---
|
||||
|
||||
#### Test 3: Device Reboot
|
||||
|
||||
**Preconditions**:
|
||||
- App installed and launched at least once
|
||||
- Notification scheduled with calendar/time trigger
|
||||
- Test device: [Device model, OS version]
|
||||
- App build: [Git commit hash or build number]
|
||||
|
||||
| Step | Action | Trigger Source | Expected (OS) [Doc A] | Expected (Plugin) [Doc C] | Actual Result | Notes | Result |
|
||||
| ---- | ------ | -------------- | ---------------------- | -------------------------- | ------------- | ----- | ------ |
|
||||
| 1 | Schedule notification for future time | Plugin | - | Notification scheduled | ☐ | | ☐ |
|
||||
| 2 | Reboot device | User | - | - | ☐ | | ☐ |
|
||||
| 3 | Do NOT open app | OS | ✅ Notification fires (OS persists) - [Doc A §3.1.2](./01-platform-capability-reference.md#312-notifications-persist-across-device-reboot) | ✅ Notification displayed - [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform) | ☐ | | ☐ |
|
||||
| 4 | Check notification timing | OS | ✅ On time (±180s tolerance) - [Doc A §6.1](./01-platform-capability-reference.md#61-notification-timing-accuracy) | ✅ On time | ☐ | | ☐ |
|
||||
|
||||
**Platform Behavior Reference**: [Doc A §3.1.2](./01-platform-capability-reference.md#312-notifications-persist-across-device-reboot) - OS-guaranteed
|
||||
|
||||
**Note**: Only calendar and time-based triggers persist. Location triggers do not - See [Doc A §3.1.2](./01-platform-capability-reference.md#312-notifications-persist-across-device-reboot)
|
||||
|
||||
---
|
||||
|
||||
#### Test 4: Hard Termination & Relaunch
|
||||
|
||||
| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
|
||||
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
|
||||
| 1 | Schedule repeating notifications | - | Notifications scheduled | ☐ | |
|
||||
| 2 | Terminate app via Xcode/switcher | - | - | ☐ | |
|
||||
| 3 | Allow some triggers to occur | ✅ Notifications fire | ✅ Notifications displayed | ☐ | |
|
||||
| 4 | Reopen app | - | Plugin checks for missed events | ☐ | |
|
||||
| 5 | Check missed event detection | ⚠️ May detect | ☐ | Plugin-specific |
|
||||
| 6 | Check state recovery | ⚠️ May recover | ☐ | Plugin-specific |
|
||||
|
||||
**Platform Behavior**: OS-guaranteed for notifications; Plugin-guaranteed for missed event detection
|
||||
|
||||
---
|
||||
|
||||
#### Test 5: Background Execution Limits
|
||||
|
||||
| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
|
||||
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
|
||||
| 1 | Schedule BGTaskScheduler task | - | Task scheduled | ☐ | |
|
||||
| 2 | Wait for system to execute | ⚠️ System-controlled | ⚠️ May not execute | ☐ | |
|
||||
| 3 | Check execution timing | ⚠️ Not guaranteed | ⚠️ Not guaranteed | ☐ | |
|
||||
| 4 | Check time budget | ⚠️ ~30 seconds | ⚠️ Limited time | ☐ | |
|
||||
|
||||
**Code Reference**: `DailyNotificationPlugin.scheduleBackgroundFetch()` line 495
|
||||
|
||||
**Platform Behavior**: Conditional (see [Platform Reference §3.1.3](./01-platform-capability-reference.md#313-background-tasks-for-prefetching))
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Persistence Investigation
|
||||
|
||||
| Item | Expected | Actual | Code Reference | Notes |
|
||||
| ---- | -------- | ------ | -------------- | ----- |
|
||||
| Notification ID stored | ✅ Yes (in UNUserNotificationCenter) | ☐ | `UNNotificationRequest` | |
|
||||
| Plugin-side storage | ⚠️ May not exist | ☐ | `DailyNotificationStorage?` | |
|
||||
| Trigger time stored | ✅ Yes (in trigger) | ☐ | `UNCalendarNotificationTrigger` | |
|
||||
| Repeat rule stored | ✅ Yes (in trigger) | ☐ | `repeats: true/false` | |
|
||||
| Payload stored | ✅ Yes (in userInfo) | ☐ | `notificationContent.userInfo` | |
|
||||
|
||||
**Storage Location**:
|
||||
- Primary: UNUserNotificationCenter (OS-managed)
|
||||
- Secondary: Plugin storage (if implemented)
|
||||
|
||||
---
|
||||
|
||||
### 3.4 Recovery Points Investigation
|
||||
|
||||
| Recovery Point | Expected Behavior | Actual Behavior | Code Reference | Notes |
|
||||
| -------------- | ----------------- | --------------- | -------------- | ----- |
|
||||
| Boot event | ✅ Notifications fire automatically | ☐ | OS handles | |
|
||||
| App cold start | ⚠️ May detect missed notifications | ☐ | Check `load()` method | |
|
||||
| App warm start | ⚠️ May verify pending notifications | ☐ | Check plugin initialization | |
|
||||
| Background fetch | ⚠️ May reschedule | ☐ | `BGTaskScheduler` | |
|
||||
| User taps notification | ✅ App launched | ☐ | Notification action | |
|
||||
|
||||
---
|
||||
|
||||
## 4. Cross-Platform Comparison
|
||||
|
||||
### 3.1 Observed Behavior Summary
|
||||
|
||||
| Scenario | Android (Observed) | iOS (Observed) | Platform Difference |
|
||||
| -------- | ------------------ | -------------- | ------------------- |
|
||||
| Swipe/termination | ☐ | ☐ | Both should work |
|
||||
| Reboot | ☐ | ☐ | iOS auto, Android manual |
|
||||
| Force stop | ☐ | N/A | Android only |
|
||||
| App code on trigger | ☐ | ☐ | Android yes, iOS no |
|
||||
| Background execution | ☐ | ☐ | Android more flexible |
|
||||
|
||||
---
|
||||
|
||||
## 5. Findings & Gaps
|
||||
|
||||
### 4.1 Android Gaps
|
||||
|
||||
| Gap | Severity | Description | Recommendation |
|
||||
| --- | -------- | ----------- | -------------- |
|
||||
| Boot recovery | ☐ Critical/Major/Minor/Expected | Does plugin reschedule on boot? | Implement if missing |
|
||||
| Missed alarm detection | ☐ Critical/Major/Minor/Expected | Does plugin detect missed alarms? | Implement if missing |
|
||||
| Force stop recovery | ☐ Critical/Major/Minor/Expected | Does plugin recover after force stop? | Implement if missing |
|
||||
| Persistence completeness | ☐ Critical/Major/Minor/Expected | Are all required fields persisted? | Verify and add if missing |
|
||||
|
||||
**Severity Classification**:
|
||||
- **Critical**: Breaks plugin guarantee (see [Doc C §1.1](./03-plugin-requirements.md#11-guarantees-by-platform))
|
||||
- **Major**: Unexpected but recoverable (plugin works but behavior differs from expected)
|
||||
- **Minor**: Non-blocking deviation (cosmetic or edge case)
|
||||
- **Expected**: Platform limitation (documented in [Doc A](./01-platform-capability-reference.md))
|
||||
|
||||
### 4.2 iOS Gaps
|
||||
|
||||
| Gap | Severity | Description | Recommendation |
|
||||
| --- | -------- | ----------- | -------------- |
|
||||
| Missed notification detection | ☐ Critical/Major/Minor/Expected | Does plugin detect missed notifications? | Implement if missing |
|
||||
| Plugin-side persistence | ☐ Critical/Major/Minor/Expected | Does plugin persist state separately? | Consider if needed |
|
||||
| Background task reliability | ☐ Critical/Major/Minor/Expected | Can plugin rely on BGTaskScheduler? | Document limitations |
|
||||
|
||||
**Severity Classification**: Same as Android (see above).
|
||||
|
||||
---
|
||||
|
||||
## 6. Deliverables from This Exploration
|
||||
|
||||
After completing this exploration, generate:
|
||||
|
||||
1. **Completed test results** - All checkboxes filled, actual results documented
|
||||
2. **Gap analysis** - Documented limitations and gaps
|
||||
3. **Annotated code pointers** - Code locations with findings
|
||||
4. **Open Questions / TODOs** - Unresolved issues
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Platform Capability Reference](./01-platform-capability-reference.md) - OS-level facts
|
||||
- [Plugin Requirements](./03-plugin-requirements.md) - Requirements based on findings
|
||||
- [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) - Master coordination document
|
||||
|
||||
---
|
||||
|
||||
## Notes for Explorers
|
||||
|
||||
* Fill in checkboxes (☐) as you complete each test
|
||||
* Document actual results in "Actual Result" columns
|
||||
* Add notes for any unexpected behavior
|
||||
* Reference code locations when documenting findings
|
||||
* Update "Findings & Gaps" section as you discover issues
|
||||
* Use platform capability reference to understand expected OS behavior
|
||||
* Link to Platform Reference sections instead of duplicating platform facts
|
||||
|
||||
1047
doc/alarms/03-plugin-requirements.md
Normal file
1047
doc/alarms/03-plugin-requirements.md
Normal file
File diff suppressed because it is too large
Load Diff
319
doc/alarms/ACTIVATION-GUIDE.md
Normal file
319
doc/alarms/ACTIVATION-GUIDE.md
Normal file
@@ -0,0 +1,319 @@
|
||||
# Activation Guide: How to Use the Alarm Directive System
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: November 2025
|
||||
**Status**: Activation Guide
|
||||
**Version**: 1.0.0
|
||||
|
||||
## Purpose
|
||||
|
||||
This guide explains how to **activate and use** the unified alarm directive system for implementation work. It provides step-by-step instructions for developers to follow the documentation workflow.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites Check
|
||||
|
||||
**Before starting any implementation work**, verify these conditions are met:
|
||||
|
||||
### ✅ Documentation Status
|
||||
|
||||
Check [Unified Directive §11 - Status Matrix](./000-UNIFIED-ALARM-DIRECTIVE.md#11-status-matrix):
|
||||
|
||||
- [x] **Doc A** (Platform Facts) - ✅ Drafted, ✅ Cleaned, ✅ In Use
|
||||
- [x] **Doc B** (Exploration) - ✅ Drafted, ✅ Cleaned, ✅ In Use (drives emulator test harness)
|
||||
- [x] **Doc C** (Requirements) - ✅ Drafted, ✅ Cleaned, ✅ In Use
|
||||
- [x] **Phase 1** (Cold Start) - ✅ Drafted, ✅ Cleaned, ✅ In Use (implemented in plugin v1.1.0, emulator-verified via `test-phase1.sh`)
|
||||
- [x] **Phase 2** (Force Stop) - ✅ Drafted, ✅ Implemented, ☐ Emulator-tested (`test-phase2.sh` + `PHASE2-EMULATOR-TESTING.md`)
|
||||
- [x] **Phase 3** (Boot Recovery) - ✅ Drafted, ✅ Implemented, ☐ Emulator-tested (`test-phase3.sh` + `PHASE3-EMULATOR-TESTING.md`)
|
||||
|
||||
**Status**: ✅ **All prerequisites met** – Phase 1 implementation is complete and emulator-verified; Phase 2 and Phase 3 are implemented and ready for emulator testing; ready for broader device testing and rollout.
|
||||
|
||||
---
|
||||
|
||||
## Activation Workflow
|
||||
|
||||
### Step 1: Choose Your Starting Point
|
||||
|
||||
**For New Implementation Work**:
|
||||
- Start with **Phase 1** (Cold Start Recovery) - See [Phase 1 Directive](../android-implementation-directive-phase1.md)
|
||||
- This is the minimal viable recovery that unblocks other work
|
||||
|
||||
**For Testing/Exploration**:
|
||||
- Start with **Doc B** (Exploration) - See [Plugin Behavior Exploration](./02-plugin-behavior-exploration.md)
|
||||
- Fill in test scenarios as you validate current behavior
|
||||
|
||||
**For Understanding Requirements**:
|
||||
- Start with **Doc C** (Requirements) - See [Plugin Requirements](./03-plugin-requirements.md)
|
||||
- Review guarantees, limitations, and API contract
|
||||
|
||||
---
|
||||
|
||||
## Implementation Activation: Phase 1
|
||||
|
||||
### 1.1 Read the Phase Directive
|
||||
|
||||
**Start Here**: [Phase 1: Cold Start Recovery](../android-implementation-directive-phase1.md)
|
||||
|
||||
**Key Sections to Read**:
|
||||
1. **Purpose** (§0) - Understand what Phase 1 implements
|
||||
2. **Acceptance Criteria** (§1) - Definition of done
|
||||
3. **Implementation** (§2) - Step-by-step code changes
|
||||
4. **Testing Requirements** (§8) - How to validate
|
||||
|
||||
### 1.2 Reference Supporting Documents
|
||||
|
||||
**During Implementation, Keep These Open**:
|
||||
|
||||
1. **Doc A** - [Platform Capability Reference](./01-platform-capability-reference.md)
|
||||
- Use for: Understanding OS behavior, API constraints, permissions
|
||||
- Example: "Can I rely on AlarmManager to persist alarms?" → See Doc A §2.1.1
|
||||
|
||||
2. **Doc C** - [Plugin Requirements](./03-plugin-requirements.md)
|
||||
- Use for: Understanding what the plugin MUST guarantee
|
||||
- Example: "What should happen on cold start?" → See Doc C §3.1.2
|
||||
|
||||
3. **Doc B** - [Plugin Behavior Exploration](./02-plugin-behavior-exploration.md)
|
||||
- Use for: Test scenarios to validate your implementation
|
||||
- Example: "How do I test cold start recovery?" → See Doc B Test 4
|
||||
|
||||
### 1.3 Follow the Implementation Steps
|
||||
|
||||
**Phase 1 Implementation Checklist** (from Phase 1 directive):
|
||||
|
||||
- [ ] Create `ReactivationManager.kt` file
|
||||
- [ ] Implement `detectMissedNotifications()` method
|
||||
- [ ] Implement `markMissedNotifications()` method
|
||||
- [ ] Implement `verifyAndRescheduleFutureAlarms()` method
|
||||
- [ ] Integrate into `DailyNotificationPlugin.load()`
|
||||
- [ ] Add logging and error handling
|
||||
- [ ] Write unit tests
|
||||
- [ ] Test on physical device
|
||||
|
||||
**Reference**: See [Phase 1 §2 - Implementation](../android-implementation-directive-phase1.md#2-implementation)
|
||||
|
||||
---
|
||||
|
||||
## Testing Activation: Doc B
|
||||
|
||||
### 2.1 Execute Test Scenarios
|
||||
|
||||
**Start Here**: [Plugin Behavior Exploration](./02-plugin-behavior-exploration.md)
|
||||
|
||||
**Workflow**:
|
||||
1. Choose a test scenario (e.g., "Test 4: Device Reboot")
|
||||
2. Follow the **Steps** column exactly
|
||||
3. Fill in **Actual Result** column with observed behavior
|
||||
4. Mark **Result** column (Pass/Fail)
|
||||
5. Add **Notes** for any unexpected behavior
|
||||
|
||||
### 2.2 Update Test Results
|
||||
|
||||
**As You Test**:
|
||||
- Update checkboxes (☐ → ✅) when tests pass
|
||||
- Document actual vs expected differences
|
||||
- Add findings to "Findings & Gaps" section (§4)
|
||||
|
||||
**Example**:
|
||||
```markdown
|
||||
| Step | Action | Expected | Actual Result | Notes | Result |
|
||||
| ---- | ------ | -------- | ------------- | ----- | ------ |
|
||||
| 5 | Launch app | Plugin detects missed alarm | ✅ Missed alarm detected | Logs show "DNP-REACTIVATION: Detected 1 missed alarm" | ✅ Pass |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Documentation Maintenance During Work
|
||||
|
||||
### 3.1 Update Status Matrix
|
||||
|
||||
**When You Complete Work**:
|
||||
|
||||
1. Open [Unified Directive §11](./000-UNIFIED-ALARM-DIRECTIVE.md#11-status-matrix)
|
||||
2. Update the relevant row:
|
||||
- Mark "In Use?" = ✅ when implementation is deployed
|
||||
- Update "Notes" with completion status
|
||||
|
||||
**Example**:
|
||||
```markdown
|
||||
| P1 | `../android-implementation-directive-phase1.md` | Impl – Cold start | ✅ | ✅ | ✅ | **Implemented and deployed** - See commit abc123 |
|
||||
```
|
||||
|
||||
### 3.2 Update Doc B with Test Results
|
||||
|
||||
**After Testing**:
|
||||
- Fill in actual results in test matrices
|
||||
- Document any gaps or unexpected behavior
|
||||
- Update severity classifications if issues found
|
||||
|
||||
### 3.3 Follow Change Control Rules
|
||||
|
||||
**When Modifying Docs A, B, or C**:
|
||||
|
||||
1. **Update version header** in the document
|
||||
2. **Update status matrix** (Section 11) in unified directive
|
||||
3. **Use commit message tag**: `[ALARM-DOCS]` prefix
|
||||
4. **Notify in CHANGELOG** if JS/TS-visible behavior changes
|
||||
|
||||
**Reference**: See [Unified Directive §10 - Change Control](./000-UNIFIED-ALARM-DIRECTIVE.md#10-change-control-rules)
|
||||
|
||||
---
|
||||
|
||||
## Workflow Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 1. Read Phase Directive (P1/P2/P3) │
|
||||
│ Understand acceptance criteria │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 2. Reference Doc A (Platform Facts) │
|
||||
│ Understand OS constraints │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 3. Reference Doc C (Requirements) │
|
||||
│ Understand plugin guarantees │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 4. Implement Code (Phase Directive) │
|
||||
│ Follow step-by-step instructions │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 5. Test (Doc B Scenarios) │
|
||||
│ Execute test matrices │
|
||||
└──────────────┬──────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 6. Update Documentation │
|
||||
│ - Status matrix │
|
||||
│ - Test results (Doc B) │
|
||||
│ - Version numbers │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Activation Scenarios
|
||||
|
||||
### Scenario 1: Starting Phase 1 Implementation
|
||||
|
||||
**Steps**:
|
||||
1. ✅ Verify prerequisites (all docs exist - **DONE**)
|
||||
2. Read [Phase 1 Directive](../android-implementation-directive-phase1.md) §1 (Acceptance Criteria)
|
||||
3. Read [Doc C §3.1.2](./03-plugin-requirements.md#312-app-cold-start) (Cold Start Requirements)
|
||||
4. Read [Doc A §2.1.4](./01-platform-capability-reference.md#214-alarms-can-be-restored-after-app-restart) (Platform Capability)
|
||||
5. Follow [Phase 1 §2](../android-implementation-directive-phase1.md#2-implementation) (Implementation Steps)
|
||||
6. Test using [Doc B Test 4](./02-plugin-behavior-exploration.md#test-4-device-reboot) (Cold Start Scenario)
|
||||
7. Update status matrix when complete
|
||||
|
||||
### Scenario 2: Testing Current Behavior
|
||||
|
||||
**Steps**:
|
||||
1. Open [Doc B](./02-plugin-behavior-exploration.md)
|
||||
2. Choose a test scenario (e.g., "Test 2: Swipe from Recents")
|
||||
3. Follow the **Steps** column
|
||||
4. Fill in **Actual Result** column
|
||||
5. Compare with **Expected (OS)** and **Expected (Plugin)** columns
|
||||
6. Document findings in **Notes** column
|
||||
7. Update "Findings & Gaps" section if issues found
|
||||
|
||||
### Scenario 3: Understanding a Requirement
|
||||
|
||||
**Steps**:
|
||||
1. Open [Doc C](./03-plugin-requirements.md)
|
||||
2. Find the relevant section (e.g., "Missed Alarm Handling" §4)
|
||||
3. Read the requirement and acceptance criteria
|
||||
4. Follow cross-references to:
|
||||
- **Doc A** for platform constraints
|
||||
- **Doc B** for test scenarios
|
||||
- **Phase docs** for implementation details
|
||||
|
||||
### Scenario 4: Adding iOS Support
|
||||
|
||||
**Steps**:
|
||||
1. ✅ Verify iOS parity milestone conditions (see [Unified Directive §9](./000-UNIFIED-ALARM-DIRECTIVE.md#9-next-steps))
|
||||
2. Ensure Doc A has iOS matrix complete
|
||||
3. Ensure Doc C has iOS guarantees defined
|
||||
4. Create iOS implementation following Android phase patterns
|
||||
5. Test using Doc B iOS scenarios
|
||||
6. Update status matrix
|
||||
|
||||
---
|
||||
|
||||
## Blocking Rules
|
||||
|
||||
**⚠️ DO NOT PROCEED** if:
|
||||
|
||||
1. **Prerequisites not met** - See [Unified Directive §12](./000-UNIFIED-ALARM-DIRECTIVE.md#12-single-instruction-for-team)
|
||||
- Doc A, B, C must exist
|
||||
- Status matrix must be updated
|
||||
- Deprecated files must be marked
|
||||
|
||||
2. **iOS work without parity milestone** - See [Unified Directive §9](./000-UNIFIED-ALARM-DIRECTIVE.md#9-next-steps)
|
||||
- Doc A must have iOS matrix
|
||||
- Doc C must define iOS guarantees
|
||||
- Phase docs must not assume Android-only
|
||||
|
||||
3. **Phase 2/3 without Phase 1** - See Phase directives
|
||||
- Phase 2 requires Phase 1 complete
|
||||
- Phase 3 requires Phase 1 & 2 complete
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Document Roles
|
||||
|
||||
| Doc | Purpose | When to Use |
|
||||
|-----|---------|-------------|
|
||||
| **Unified Directive** | Master coordination | Understanding system structure, change control |
|
||||
| **Doc A** | Platform facts | Understanding OS behavior, API constraints |
|
||||
| **Doc B** | Test scenarios | Testing, exploration, validation |
|
||||
| **Doc C** | Requirements | Understanding guarantees, API contract |
|
||||
| **Phase 1-3** | Implementation | Writing code, step-by-step instructions |
|
||||
|
||||
### Key Sections
|
||||
|
||||
- **Status Matrix**: [Unified Directive §11](./000-UNIFIED-ALARM-DIRECTIVE.md#11-status-matrix)
|
||||
- **Change Control**: [Unified Directive §10](./000-UNIFIED-ALARM-DIRECTIVE.md#10-change-control-rules)
|
||||
- **Phase 1 Start**: [Phase 1 Directive](../android-implementation-directive-phase1.md)
|
||||
- **Test Scenarios**: [Doc B Test Matrices](./02-plugin-behavior-exploration.md#12-behavior-testing-matrix)
|
||||
- **Requirements**: [Doc C Guarantees](./03-plugin-requirements.md#1-plugin-behavior-guarantees--limitations)
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
**You're Ready To**:
|
||||
|
||||
1. ✅ **Start Phase 1 Implementation** - All prerequisites met
|
||||
2. ✅ **Begin Testing** - Doc B scenarios ready
|
||||
3. ✅ **Reference Documentation** - All docs complete and cross-referenced
|
||||
|
||||
**Recommended First Action**:
|
||||
- Read [Phase 1: Cold Start Recovery](../android-implementation-directive-phase1.md) §1 (Acceptance Criteria)
|
||||
- Then proceed to §2 (Implementation) when ready to code
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) - Master coordination document
|
||||
- [Phase 1: Cold Start Recovery](../android-implementation-directive-phase1.md) - Start here for implementation
|
||||
- [Plugin Requirements](./03-plugin-requirements.md) - What the plugin must guarantee
|
||||
- [Platform Capability Reference](./01-platform-capability-reference.md) - OS-level facts
|
||||
- [Plugin Behavior Exploration](./02-plugin-behavior-exploration.md) - Test scenarios
|
||||
|
||||
---
|
||||
|
||||
**Status**: Ready for activation
|
||||
**Last Updated**: November 2025
|
||||
|
||||
686
doc/alarms/PHASE1-EMULATOR-TESTING.md
Normal file
686
doc/alarms/PHASE1-EMULATOR-TESTING.md
Normal file
@@ -0,0 +1,686 @@
|
||||
# Phase 1 Emulator Testing Guide
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: November 2025
|
||||
**Status**: Testing Guide
|
||||
**Version**: 1.0.0
|
||||
|
||||
## Purpose
|
||||
|
||||
This guide provides step-by-step instructions for testing Phase 1 (Cold Start Recovery) implementation on an Android emulator. All Phase 1 tests can be run entirely on an emulator using ADB commands.
|
||||
|
||||
---
|
||||
|
||||
## Latest Known Good Run (Emulator)
|
||||
|
||||
**Environment**
|
||||
|
||||
- Device: Android Emulator – Pixel 8 API 34
|
||||
- App ID: `org.timesafari.dailynotification`
|
||||
- Build: Debug APK from `test-apps/android-test-app`
|
||||
- Script: `./test-phase1.sh`
|
||||
- Date: 27 November 2025
|
||||
|
||||
**Observed Results**
|
||||
|
||||
- ✅ TEST 1: Cold Start Missed Detection
|
||||
- Logs show:
|
||||
- `Marked missed notification: daily_<id>`
|
||||
- `Cold start recovery complete: missed=1, rescheduled=0, verified=0, errors=0`
|
||||
- "Stored notification content in database" present in logs
|
||||
- Alarm present in `dumpsys alarm` before kill
|
||||
|
||||
- ✅ TEST 2: Future Alarm Verification / Rescheduling
|
||||
- Logs show:
|
||||
- `Rescheduled alarm: daily_<id> for <time>`
|
||||
- `Rescheduled missing alarm: daily_<id> at <time>`
|
||||
- `Cold start recovery complete: missed=1, rescheduled=1, verified=0, errors=0`
|
||||
- Script output:
|
||||
- `✅ TEST 2 PASSED: Missing future alarms were detected and rescheduled (rescheduled=1)!`
|
||||
|
||||
- ✅ TEST 3: Recovery Timeout
|
||||
- Timeout protection confirmed at **2 seconds**
|
||||
- No blocking of app startup
|
||||
|
||||
- ✅ TEST 4: Invalid Data Handling
|
||||
- Confirmed in code review:
|
||||
- Reactivation code safely skips invalid IDs
|
||||
- Errors are logged but do not crash recovery
|
||||
|
||||
**Conclusion:**
|
||||
Phase 1 cold-start recovery behavior is **successfully verified on emulator** using `test-phase1.sh`. This run is the reference baseline for future regressions.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Required Software
|
||||
|
||||
- **Android SDK** with command line tools
|
||||
- **Android Emulator** (`emulator` command)
|
||||
- **ADB** (Android Debug Bridge)
|
||||
- **Gradle** (via Gradle Wrapper)
|
||||
- **Java** (JDK 11+)
|
||||
|
||||
### Emulator Setup
|
||||
|
||||
1. **List available emulators**:
|
||||
```bash
|
||||
emulator -list-avds
|
||||
```
|
||||
|
||||
2. **Start emulator** (choose one):
|
||||
```bash
|
||||
# Start in background (recommended)
|
||||
emulator -avd Pixel8_API34 -no-snapshot-load &
|
||||
|
||||
# Or start in foreground
|
||||
emulator -avd Pixel8_API34
|
||||
```
|
||||
|
||||
3. **Wait for emulator to boot**:
|
||||
```bash
|
||||
adb wait-for-device
|
||||
adb shell getprop sys.boot_completed
|
||||
# Wait until returns "1"
|
||||
```
|
||||
|
||||
4. **Verify emulator is connected**:
|
||||
```bash
|
||||
adb devices
|
||||
# Should show: emulator-5554 device
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build and Install Test App
|
||||
|
||||
### Option 1: Android Test App (Simpler)
|
||||
|
||||
```bash
|
||||
# Navigate to test app directory
|
||||
cd test-apps/android-test-app
|
||||
|
||||
# Build debug APK (builds plugin automatically)
|
||||
./gradlew assembleDebug
|
||||
|
||||
# Install on emulator
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
# Verify installation
|
||||
adb shell pm list packages | grep timesafari
|
||||
# Should show: package:org.timesafari.dailynotification
|
||||
```
|
||||
|
||||
### Option 2: Vue Test App (More Features)
|
||||
|
||||
```bash
|
||||
# Navigate to Vue test app
|
||||
cd test-apps/daily-notification-test
|
||||
|
||||
# Build Vue app
|
||||
npm run build
|
||||
|
||||
# Sync with Capacitor
|
||||
npx cap sync android
|
||||
|
||||
# Build Android APK
|
||||
cd android
|
||||
./gradlew assembleDebug
|
||||
|
||||
# Install on emulator
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Setup
|
||||
|
||||
### 1. Clear Logs Before Testing
|
||||
|
||||
```bash
|
||||
# Clear logcat buffer
|
||||
adb logcat -c
|
||||
```
|
||||
|
||||
### 2. Monitor Logs in Separate Terminal
|
||||
|
||||
**Keep this running in a separate terminal window**:
|
||||
|
||||
```bash
|
||||
# Monitor all plugin-related logs
|
||||
adb logcat | grep -E "DNP-REACTIVATION|DNP-PLUGIN|DNP-NOTIFY|DailyNotification"
|
||||
|
||||
# Or monitor just recovery logs
|
||||
adb logcat -s DNP-REACTIVATION
|
||||
|
||||
# Or save logs to file
|
||||
adb logcat -s DNP-REACTIVATION > recovery_test.log
|
||||
```
|
||||
|
||||
### 3. Launch App Once (Initial Setup)
|
||||
|
||||
```bash
|
||||
# Launch app to initialize database
|
||||
adb shell am start -n org.timesafari.dailynotification/.MainActivity
|
||||
|
||||
# Wait a few seconds for initialization
|
||||
sleep 3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test 1: Cold Start Missed Detection
|
||||
|
||||
**Purpose**: Verify missed notifications are detected and marked.
|
||||
|
||||
### Steps
|
||||
|
||||
```bash
|
||||
# 1. Clear logs
|
||||
adb logcat -c
|
||||
|
||||
# 2. Launch app
|
||||
adb shell am start -n org.timesafari.dailynotification/.MainActivity
|
||||
|
||||
# 3. Schedule notification for 2 minutes in future
|
||||
# (Use app UI or API - see "Scheduling Notifications" below)
|
||||
|
||||
# 4. Wait for app to schedule (check logs)
|
||||
adb logcat -d | grep "DN|SCHEDULE\|DN|ALARM"
|
||||
# Should show alarm scheduled
|
||||
|
||||
# 5. Verify alarm is scheduled
|
||||
adb shell dumpsys alarm | grep -i timesafari
|
||||
# Should show scheduled alarm
|
||||
|
||||
# 6. Kill app process (simulates OS kill, NOT force stop)
|
||||
adb shell am kill org.timesafari.dailynotification
|
||||
|
||||
# 7. Verify app is killed
|
||||
adb shell ps | grep timesafari
|
||||
# Should return nothing
|
||||
|
||||
# 8. Wait 5 minutes (past scheduled time)
|
||||
# Use: sleep 300 (or wait manually)
|
||||
# Or: Set system time forward (see "Time Manipulation" below)
|
||||
|
||||
# 9. Launch app (cold start)
|
||||
adb shell am start -n org.timesafari.dailynotification/.MainActivity
|
||||
|
||||
# 10. Check recovery logs immediately
|
||||
adb logcat -d | grep DNP-REACTIVATION
|
||||
```
|
||||
|
||||
### Expected Log Output
|
||||
|
||||
```
|
||||
DNP-REACTIVATION: Starting app launch recovery (Phase 1: cold start only)
|
||||
DNP-REACTIVATION: Cold start recovery: checking for missed notifications
|
||||
DNP-REACTIVATION: Marked missed notification: <id>
|
||||
DNP-REACTIVATION: Cold start recovery complete: missed=1, rescheduled=0, verified=0, errors=0
|
||||
DNP-REACTIVATION: App launch recovery completed: missed=1, rescheduled=0, verified=0, errors=0
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
```bash
|
||||
# Check database (requires root or debug build)
|
||||
adb shell run-as org.timesafari.dailynotification sqlite3 databases/daily_notification_plugin.db \
|
||||
"SELECT id, delivery_status, scheduled_time FROM notification_content WHERE delivery_status = 'missed';"
|
||||
|
||||
# Or check history table
|
||||
adb shell run-as org.timesafari.dailynotification sqlite3 databases/daily_notification_plugin.db \
|
||||
"SELECT * FROM history WHERE kind = 'recovery' ORDER BY occurredAt DESC LIMIT 1;"
|
||||
```
|
||||
|
||||
### Pass Criteria
|
||||
|
||||
- ✅ Log shows "Cold start recovery: checking for missed notifications"
|
||||
- ✅ Log shows "Marked missed notification: <id>"
|
||||
- ✅ Database shows `delivery_status = 'missed'`
|
||||
- ✅ History table has recovery entry
|
||||
|
||||
---
|
||||
|
||||
## Test 2: Future Alarm Rescheduling
|
||||
|
||||
**Purpose**: Verify missing future alarms are rescheduled.
|
||||
|
||||
### Steps
|
||||
|
||||
```bash
|
||||
# 1. Clear logs
|
||||
adb logcat -c
|
||||
|
||||
# 2. Launch app
|
||||
adb shell am start -n org.timesafari.dailynotification/.MainActivity
|
||||
|
||||
# 3. Schedule notification for 10 minutes in future
|
||||
# (Use app UI or API)
|
||||
|
||||
# 4. Verify alarm is scheduled
|
||||
adb shell dumpsys alarm | grep -i timesafari
|
||||
# Note the request code or trigger time
|
||||
|
||||
# 5. Manually cancel alarm (simulate missing alarm)
|
||||
# Find the alarm request code from dumpsys output
|
||||
# Then cancel using PendingIntent (requires root or app code)
|
||||
# OR: Use app UI to cancel if available
|
||||
|
||||
# Alternative: Use app code to cancel
|
||||
# (This test may require app modification to add cancel button)
|
||||
|
||||
# 6. Verify alarm is cancelled
|
||||
adb shell dumpsys alarm | grep -i timesafari
|
||||
# Should show no alarms (or fewer alarms)
|
||||
|
||||
# 7. Launch app (triggers recovery)
|
||||
adb shell am start -n org.timesafari.dailynotification/.MainActivity
|
||||
|
||||
# 8. Check recovery logs
|
||||
adb logcat -d | grep DNP-REACTIVATION
|
||||
|
||||
# 9. Verify alarm is rescheduled
|
||||
adb shell dumpsys alarm | grep -i timesafari
|
||||
# Should show rescheduled alarm
|
||||
```
|
||||
|
||||
### Expected Log Output
|
||||
|
||||
```
|
||||
DNP-REACTIVATION: Starting app launch recovery (Phase 1: cold start only)
|
||||
DNP-REACTIVATION: Cold start recovery: checking for missed notifications
|
||||
DNP-REACTIVATION: Rescheduled missing alarm: <id> at <timestamp>
|
||||
DNP-REACTIVATION: Cold start recovery complete: missed=0, rescheduled=1, verified=0, errors=0
|
||||
```
|
||||
|
||||
### Pass Criteria
|
||||
|
||||
- ✅ Log shows "Rescheduled missing alarm: <id>"
|
||||
- ✅ AlarmManager shows rescheduled alarm
|
||||
- ✅ No duplicate alarms created
|
||||
|
||||
---
|
||||
|
||||
## Test 3: Recovery Timeout
|
||||
|
||||
**Purpose**: Verify recovery times out gracefully.
|
||||
|
||||
### Steps
|
||||
|
||||
```bash
|
||||
# 1. Clear logs
|
||||
adb logcat -c
|
||||
|
||||
# 2. Create large number of schedules (100+)
|
||||
# This requires app modification or database manipulation
|
||||
# See "Database Manipulation" section below
|
||||
|
||||
# 3. Launch app
|
||||
adb shell am start -n org.timesafari.dailynotification/.MainActivity
|
||||
|
||||
# 4. Check logs immediately
|
||||
adb logcat -d | grep DNP-REACTIVATION
|
||||
```
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
- ✅ Recovery completes within 2 seconds OR times out
|
||||
- ✅ App doesn't crash
|
||||
- ✅ Partial recovery logged if timeout occurs
|
||||
|
||||
### Pass Criteria
|
||||
|
||||
- ✅ Recovery doesn't block app launch
|
||||
- ✅ No app crash
|
||||
- ✅ Timeout logged if occurs
|
||||
|
||||
**Note**: This test may be difficult to execute without creating many schedules. Consider testing with smaller numbers first (10, 50 schedules) to verify behavior.
|
||||
|
||||
---
|
||||
|
||||
## Test 4: Invalid Data Handling
|
||||
|
||||
**Purpose**: Verify invalid data doesn't crash recovery.
|
||||
|
||||
### Steps
|
||||
|
||||
```bash
|
||||
# 1. Clear logs
|
||||
adb logcat -c
|
||||
|
||||
# 2. Manually insert invalid notification (empty ID) into database
|
||||
# See "Database Manipulation" section below
|
||||
|
||||
# 3. Launch app
|
||||
adb shell am start -n org.timesafari.dailynotification/.MainActivity
|
||||
|
||||
# 4. Check logs
|
||||
adb logcat -d | grep DNP-REACTIVATION
|
||||
```
|
||||
|
||||
### Expected Log Output
|
||||
|
||||
```
|
||||
DNP-REACTIVATION: Starting app launch recovery (Phase 1: cold start only)
|
||||
DNP-REACTIVATION: Cold start recovery: checking for missed notifications
|
||||
DNP-REACTIVATION: Skipping invalid notification: empty ID
|
||||
DNP-REACTIVATION: Cold start recovery complete: missed=0, rescheduled=0, verified=0, errors=0
|
||||
```
|
||||
|
||||
### Pass Criteria
|
||||
|
||||
- ✅ Invalid notification skipped
|
||||
- ✅ Warning logged
|
||||
- ✅ Recovery continues normally
|
||||
- ✅ App doesn't crash
|
||||
|
||||
---
|
||||
|
||||
## Helper Scripts and Commands
|
||||
|
||||
### Scheduling Notifications
|
||||
|
||||
**Option 1: Use App UI**
|
||||
- Launch app
|
||||
- Use "Schedule Notification" button
|
||||
- Set time to 2-5 minutes in future
|
||||
|
||||
**Option 2: Use Capacitor API (if test app has console)**
|
||||
```javascript
|
||||
// In browser console or test app
|
||||
const { DailyNotification } = Plugins.DailyNotification;
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
schedule: "*/2 * * * *", // Every 2 minutes
|
||||
title: "Test Notification",
|
||||
body: "Testing Phase 1 recovery"
|
||||
});
|
||||
```
|
||||
|
||||
**Option 3: Direct Database Insert (Advanced)**
|
||||
```bash
|
||||
# See "Database Manipulation" section
|
||||
```
|
||||
|
||||
### Time Manipulation (Emulator)
|
||||
|
||||
**Fast-forward system time** (for testing without waiting):
|
||||
|
||||
```bash
|
||||
# Get current time
|
||||
adb shell date +%s
|
||||
|
||||
# Set time forward (e.g., 5 minutes)
|
||||
adb shell date -s @$(($(adb shell date +%s) + 300))
|
||||
|
||||
# Or set specific time
|
||||
adb shell date -s "2025-11-15 14:30:00"
|
||||
```
|
||||
|
||||
**Note**: Some emulators may not support time changes. Test with actual waiting if time manipulation doesn't work.
|
||||
|
||||
### Database Manipulation
|
||||
|
||||
**Access database** (requires root or debug build):
|
||||
|
||||
```bash
|
||||
# Check if app is debuggable
|
||||
adb shell dumpsys package org.timesafari.dailynotification | grep debuggable
|
||||
|
||||
# Access database
|
||||
adb shell run-as org.timesafari.dailynotification sqlite3 databases/daily_notification_plugin.db
|
||||
|
||||
# Example: Insert test notification
|
||||
sqlite> INSERT INTO notification_content (
|
||||
id, plugin_version, title, body, scheduled_time,
|
||||
delivery_status, delivery_attempts, last_delivery_attempt,
|
||||
created_at, updated_at, ttl_seconds, priority,
|
||||
vibration_enabled, sound_enabled
|
||||
) VALUES (
|
||||
'test_notification_1', '1.1.0', 'Test', 'Test body',
|
||||
$(($(date +%s) * 1000 - 300000)), -- 5 minutes ago
|
||||
'pending', 0, 0,
|
||||
$(date +%s) * 1000, $(date +%s) * 1000,
|
||||
604800, 0, 1, 1
|
||||
);
|
||||
|
||||
# Example: Insert invalid notification (empty ID)
|
||||
sqlite> INSERT INTO notification_content (
|
||||
id, plugin_version, title, body, scheduled_time,
|
||||
delivery_status, delivery_attempts, last_delivery_attempt,
|
||||
created_at, updated_at, ttl_seconds, priority,
|
||||
vibration_enabled, sound_enabled
|
||||
) VALUES (
|
||||
'', '1.1.0', 'Invalid', 'Invalid body',
|
||||
$(($(date +%s) * 1000 - 300000)),
|
||||
'pending', 0, 0,
|
||||
$(date +%s) * 1000, $(date +%s) * 1000,
|
||||
604800, 0, 1, 1
|
||||
);
|
||||
|
||||
# Example: Create many schedules (for timeout test)
|
||||
sqlite> .read create_many_schedules.sql
|
||||
# (Create SQL file with 100+ INSERT statements)
|
||||
```
|
||||
|
||||
### Log Filtering
|
||||
|
||||
**Useful log filters**:
|
||||
|
||||
```bash
|
||||
# Recovery-specific logs
|
||||
adb logcat -s DNP-REACTIVATION
|
||||
|
||||
# All plugin logs
|
||||
adb logcat | grep -E "DNP-|DailyNotification"
|
||||
|
||||
# Recovery + scheduling logs
|
||||
adb logcat | grep -E "DNP-REACTIVATION|DN|SCHEDULE"
|
||||
|
||||
# Save logs to file
|
||||
adb logcat -d > phase1_test_$(date +%Y%m%d_%H%M%S).log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Test Sequence
|
||||
|
||||
**Run all tests in sequence**:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Phase 1 Complete Test Sequence
|
||||
|
||||
PACKAGE="org.timesafari.dailynotification"
|
||||
ACTIVITY="${PACKAGE}/.MainActivity"
|
||||
|
||||
echo "=== Phase 1 Testing on Emulator ==="
|
||||
echo ""
|
||||
|
||||
# Setup
|
||||
echo "1. Setting up emulator..."
|
||||
adb wait-for-device
|
||||
adb logcat -c
|
||||
|
||||
# Test 1: Cold Start Missed Detection
|
||||
echo ""
|
||||
echo "=== Test 1: Cold Start Missed Detection ==="
|
||||
echo "1. Launch app and schedule notification for 2 minutes"
|
||||
adb shell am start -n $ACTIVITY
|
||||
echo " (Use app UI to schedule notification)"
|
||||
read -p "Press Enter after scheduling notification..."
|
||||
|
||||
echo "2. Killing app process..."
|
||||
adb shell am kill $PACKAGE
|
||||
|
||||
echo "3. Waiting 5 minutes (or set time forward)..."
|
||||
echo " (You can set time forward: adb shell date -s ...)"
|
||||
read -p "Press Enter after waiting 5 minutes..."
|
||||
|
||||
echo "4. Launching app (cold start)..."
|
||||
adb shell am start -n $ACTIVITY
|
||||
sleep 2
|
||||
|
||||
echo "5. Checking recovery logs..."
|
||||
adb logcat -d | grep DNP-REACTIVATION
|
||||
|
||||
echo ""
|
||||
echo "=== Test 1 Complete ==="
|
||||
read -p "Press Enter to continue to Test 2..."
|
||||
|
||||
# Test 2: Future Alarm Rescheduling
|
||||
echo ""
|
||||
echo "=== Test 2: Future Alarm Rescheduling ==="
|
||||
echo "1. Schedule notification for 10 minutes"
|
||||
adb shell am start -n $ACTIVITY
|
||||
echo " (Use app UI to schedule notification)"
|
||||
read -p "Press Enter after scheduling..."
|
||||
|
||||
echo "2. Verify alarm scheduled..."
|
||||
adb shell dumpsys alarm | grep -i timesafari
|
||||
|
||||
echo "3. Cancel alarm (use app UI or see Database Manipulation)"
|
||||
read -p "Press Enter after cancelling alarm..."
|
||||
|
||||
echo "4. Launch app (triggers recovery)..."
|
||||
adb shell am start -n $ACTIVITY
|
||||
sleep 2
|
||||
|
||||
echo "5. Check recovery logs..."
|
||||
adb logcat -d | grep DNP-REACTIVATION
|
||||
|
||||
echo "6. Verify alarm rescheduled..."
|
||||
adb shell dumpsys alarm | grep -i timesafari
|
||||
|
||||
echo ""
|
||||
echo "=== Test 2 Complete ==="
|
||||
echo ""
|
||||
echo "=== All Tests Complete ==="
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Emulator Issues
|
||||
|
||||
**Emulator won't start**:
|
||||
```bash
|
||||
# Check available AVDs
|
||||
emulator -list-avds
|
||||
|
||||
# Kill existing emulator
|
||||
pkill -f emulator
|
||||
|
||||
# Start with verbose logging
|
||||
emulator -avd Pixel8_API34 -verbose
|
||||
```
|
||||
|
||||
**Emulator is slow**:
|
||||
```bash
|
||||
# Use hardware acceleration
|
||||
emulator -avd Pixel8_API34 -accel on -gpu host
|
||||
|
||||
# Allocate more RAM
|
||||
emulator -avd Pixel8_API34 -memory 4096
|
||||
```
|
||||
|
||||
### ADB Issues
|
||||
|
||||
**ADB not detecting emulator**:
|
||||
```bash
|
||||
# Restart ADB server
|
||||
adb kill-server
|
||||
adb start-server
|
||||
|
||||
# Check devices
|
||||
adb devices
|
||||
```
|
||||
|
||||
**Permission denied for database access**:
|
||||
```bash
|
||||
# Check if app is debuggable
|
||||
adb shell dumpsys package org.timesafari.dailynotification | grep debuggable
|
||||
|
||||
# If not debuggable, rebuild with debug signing
|
||||
cd test-apps/android-test-app
|
||||
./gradlew assembleDebug
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
### App Issues
|
||||
|
||||
**App won't launch**:
|
||||
```bash
|
||||
# Check if app is installed
|
||||
adb shell pm list packages | grep timesafari
|
||||
|
||||
# Uninstall and reinstall
|
||||
adb uninstall org.timesafari.dailynotification
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
**No logs appearing**:
|
||||
```bash
|
||||
# Check logcat buffer size
|
||||
adb logcat -G 10M
|
||||
|
||||
# Clear and monitor
|
||||
adb logcat -c
|
||||
adb logcat -s DNP-REACTIVATION
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Expected Test Results Summary
|
||||
|
||||
| Test | Expected Outcome | Verification Method |
|
||||
|------|------------------|---------------------|
|
||||
| **Test 1** | Missed notification detected and marked | Logs + Database query |
|
||||
| **Test 2** | Missing alarm rescheduled | Logs + AlarmManager check |
|
||||
| **Test 3** | Recovery times out gracefully | Logs (timeout message) |
|
||||
| **Test 4** | Invalid data skipped | Logs (warning message) |
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Essential Commands
|
||||
|
||||
```bash
|
||||
# Start emulator
|
||||
emulator -avd Pixel8_API34 &
|
||||
|
||||
# Build and install
|
||||
cd test-apps/android-test-app
|
||||
./gradlew assembleDebug
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
# Launch app
|
||||
adb shell am start -n org.timesafari.dailynotification/.MainActivity
|
||||
|
||||
# Kill app
|
||||
adb shell am kill org.timesafari.dailynotification
|
||||
|
||||
# Monitor logs
|
||||
adb logcat -s DNP-REACTIVATION
|
||||
|
||||
# Check alarms
|
||||
adb shell dumpsys alarm | grep -i timesafari
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Phase 1 Directive](../android-implementation-directive-phase1.md) - Implementation details
|
||||
- [Phase 1 Verification](./PHASE1-VERIFICATION.md) - Verification report
|
||||
- [Activation Guide](./ACTIVATION-GUIDE.md) - How to use directives
|
||||
- [Standalone Emulator Guide](../standalone-emulator-guide.md) - Emulator setup
|
||||
|
||||
---
|
||||
|
||||
**Status**: Emulator-verified (test-phase1.sh)
|
||||
**Last Updated**: 27 November 2025
|
||||
|
||||
259
doc/alarms/PHASE1-VERIFICATION.md
Normal file
259
doc/alarms/PHASE1-VERIFICATION.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# Phase 1 Verification Report
|
||||
|
||||
**Date**: November 2025
|
||||
**Status**: Verification Complete
|
||||
**Phase**: Phase 1 - Cold Start Recovery
|
||||
|
||||
## Verification Summary
|
||||
|
||||
**Overall Status**: ✅ **VERIFIED** – Phase 1 is complete, aligned, implemented in plugin v1.1.0, and emulator-tested via `test-phase1.sh` on a Pixel 8 API 34 emulator.
|
||||
|
||||
**Verification Method**:
|
||||
- Automated emulator run using `PHASE1-EMULATOR-TESTING.md` + `test-phase1.sh`
|
||||
- All four Phase 1 tests (missed detection, future alarm verification/rescheduling, timeout, invalid data handling) passed with `errors=0`.
|
||||
|
||||
**Issues Found**: 2 minor documentation improvements recommended (resolved)
|
||||
|
||||
---
|
||||
|
||||
## 1. Alignment with Doc C (Requirements)
|
||||
|
||||
### ✅ Required Actions Check
|
||||
|
||||
**Doc C §3.1.2 - App Cold Start** requires:
|
||||
|
||||
| Required Action | Phase 1 Implementation | Status |
|
||||
|----------------|------------------------|--------|
|
||||
| 1. Load all enabled alarms from persistent storage | ✅ `db.scheduleDao().getEnabled()` | ✅ Complete |
|
||||
| 2. Verify active alarms match stored alarms | ✅ `NotifyReceiver.isAlarmScheduled()` check | ✅ Complete |
|
||||
| 3. Detect missed alarms (trigger_time < now) | ✅ `getNotificationsReadyForDelivery(currentTime)` | ✅ Complete |
|
||||
| 4. Reschedule future alarms | ✅ `rescheduleAlarm()` method | ✅ Complete |
|
||||
| 5. Generate missed alarm events/notifications | ⚠️ Deferred to Phase 2 | ✅ **OK** (explicitly out of scope) |
|
||||
| 6. Log recovery actions | ✅ Extensive logging with `DNP-REACTIVATION` tag | ✅ Complete |
|
||||
|
||||
**Result**: ✅ **All in-scope requirements implemented**
|
||||
|
||||
### ✅ Acceptance Criteria Check
|
||||
|
||||
**Doc C §3.1.2 Acceptance Criteria**:
|
||||
- ✅ Test scenario matches Phase 1 Test 1
|
||||
- ✅ Expected behavior matches Phase 1 implementation
|
||||
- ✅ Pass criteria align with Phase 1 success metrics
|
||||
|
||||
**Result**: ✅ **Acceptance criteria aligned**
|
||||
|
||||
---
|
||||
|
||||
## 2. Alignment with Doc A (Platform Facts)
|
||||
|
||||
### ✅ Platform Reference Check
|
||||
|
||||
**Doc A §2.1.4 - Alarms can be restored after app restart**:
|
||||
- ✅ Phase 1 references this capability correctly
|
||||
- ✅ Implementation uses AlarmManager APIs as documented
|
||||
- ✅ No platform assumptions beyond Doc A
|
||||
|
||||
**Missing**: Phase 1 doesn't explicitly cite Doc A §2.1.4 in the implementation section (minor)
|
||||
|
||||
**Recommendation**: Add explicit reference to Doc A §2.1.4 in Phase 1 §2 (Implementation)
|
||||
|
||||
---
|
||||
|
||||
## 3. Alignment with Doc B (Test Scenarios)
|
||||
|
||||
### ✅ Test Scenario Check
|
||||
|
||||
**Doc B Test 4 - Device Reboot** (Step 5: Cold Start):
|
||||
- ✅ Phase 1 Test 1 matches Doc B scenario
|
||||
- ✅ Test steps align
|
||||
- ✅ Expected results match
|
||||
|
||||
**Result**: ✅ **Test scenarios aligned**
|
||||
|
||||
---
|
||||
|
||||
## 4. Cross-Reference Verification
|
||||
|
||||
### ✅ Cross-References Present
|
||||
|
||||
| Reference | Location | Status |
|
||||
|-----------|----------|--------|
|
||||
| Doc C §3.1.2 | Phase 1 line 9 | ✅ Correct |
|
||||
| Doc A (general) | Phase 1 line 19 | ✅ Present |
|
||||
| Doc C (general) | Phase 1 line 18 | ✅ Present |
|
||||
| Phase 2/3 | Phase 1 lines 21-22 | ✅ Present |
|
||||
|
||||
### ⚠️ Missing Cross-References
|
||||
|
||||
| Missing Reference | Should Be Added | Priority |
|
||||
|-------------------|-----------------|----------|
|
||||
| Doc A §2.1.4 | In §2 (Implementation) | Minor |
|
||||
| Doc B Test 4 | In §8 (Testing) | Minor |
|
||||
|
||||
**Result**: ✅ **Core references present**, minor improvements recommended
|
||||
|
||||
---
|
||||
|
||||
## 5. Structure Verification
|
||||
|
||||
### ✅ Required Sections Present
|
||||
|
||||
| Section | Present | Notes |
|
||||
|---------|---------|-------|
|
||||
| Purpose | ✅ | Clear scope definition |
|
||||
| Acceptance Criteria | ✅ | Detailed with metrics |
|
||||
| Implementation | ✅ | Step-by-step with code |
|
||||
| Data Integrity | ✅ | Validation rules defined |
|
||||
| Rollback Safety | ✅ | No-crash guarantee |
|
||||
| Testing Requirements | ✅ | 4 test scenarios |
|
||||
| Implementation Checklist | ✅ | Complete checklist |
|
||||
| Code References | ✅ | Existing code listed |
|
||||
|
||||
**Result**: ✅ **All required sections present**
|
||||
|
||||
---
|
||||
|
||||
## 6. Scope Verification
|
||||
|
||||
### ✅ Out of Scope Items Correctly Deferred
|
||||
|
||||
| Item | Phase 1 Status | Correct? |
|
||||
|------|----------------|----------|
|
||||
| Force stop detection | ❌ Deferred to Phase 2 | ✅ Correct |
|
||||
| Warm start optimization | ❌ Deferred to Phase 2 | ✅ Correct |
|
||||
| Boot receiver handling | ❌ Deferred to Phase 3 | ✅ Correct |
|
||||
| Callback events | ❌ Deferred to Phase 2 | ✅ Correct |
|
||||
| Fetch work recovery | ❌ Deferred to Phase 2 | ✅ Correct |
|
||||
|
||||
**Result**: ✅ **Scope boundaries correctly defined**
|
||||
|
||||
---
|
||||
|
||||
## 7. Code Quality Verification
|
||||
|
||||
### ✅ Implementation Quality
|
||||
|
||||
| Aspect | Status | Notes |
|
||||
|--------|--------|-------|
|
||||
| Error handling | ✅ | All exceptions caught |
|
||||
| Timeout protection | ✅ | 2-second timeout |
|
||||
| Data validation | ✅ | Integrity checks present |
|
||||
| Logging | ✅ | Comprehensive logging |
|
||||
| Non-blocking | ✅ | Async with coroutines |
|
||||
| Rollback safety | ✅ | No-crash guarantee |
|
||||
|
||||
**Result**: ✅ **Code quality meets requirements**
|
||||
|
||||
---
|
||||
|
||||
## 8. Testing Verification
|
||||
|
||||
### ✅ Test Coverage
|
||||
|
||||
| Test Scenario | Present | Aligned with Doc B? |
|
||||
|---------------|---------|---------------------|
|
||||
| Cold start missed detection | ✅ | ✅ Yes |
|
||||
| Future alarm rescheduling | ✅ | ✅ Yes |
|
||||
| Recovery timeout | ✅ | ✅ Yes |
|
||||
| Invalid data handling | ✅ | ✅ Yes |
|
||||
|
||||
**Result**: ✅ **Test coverage complete**
|
||||
|
||||
---
|
||||
|
||||
## Issues Found
|
||||
|
||||
### Issue 1: Missing Explicit Doc A Reference (Minor)
|
||||
|
||||
**Location**: Phase 1 §2 (Implementation)
|
||||
|
||||
**Problem**: Implementation doesn't explicitly cite Doc A §2.1.4
|
||||
|
||||
**Recommendation**: Add reference in §2.3 (Cold Start Recovery):
|
||||
```markdown
|
||||
**Platform Reference**: [Android §2.1.4](./alarms/01-platform-capability-reference.md#214-alarms-can-be-restored-after-app-restart)
|
||||
```
|
||||
|
||||
**Priority**: Minor (documentation improvement)
|
||||
|
||||
---
|
||||
|
||||
### Issue 2: Related Documentation Section (Minor)
|
||||
|
||||
**Location**: Phase 1 §11 (Related Documentation)
|
||||
|
||||
**Problem**: References old documentation files instead of unified docs
|
||||
|
||||
**Current**:
|
||||
```markdown
|
||||
- [Full Implementation Directive](./android-implementation-directive.md) - Complete scope (all phases)
|
||||
- [Exploration Findings](./exploration-findings-initial.md) - Gap analysis
|
||||
- [Plugin Requirements](./plugin-requirements-implementation.md) - Requirements
|
||||
```
|
||||
|
||||
**Should Be**:
|
||||
```markdown
|
||||
- [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
|
||||
- [Plugin Behavior Exploration](./alarms/02-plugin-behavior-exploration.md) - Test scenarios
|
||||
- [Full Implementation Directive](./android-implementation-directive.md) - Complete scope (all phases)
|
||||
```
|
||||
|
||||
**Priority**: Minor (documentation improvement)
|
||||
|
||||
---
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
- [x] Phase 1 implements all required actions from Doc C §3.1.2
|
||||
- [x] Acceptance criteria align with Doc C
|
||||
- [x] Platform facts referenced (implicitly, could be explicit)
|
||||
- [x] Test scenarios align with Doc B
|
||||
- [x] Cross-references to Doc C present and correct
|
||||
- [x] Scope boundaries correctly defined
|
||||
- [x] Implementation quality meets requirements
|
||||
- [x] Testing requirements complete
|
||||
- [x] Code structure follows best practices
|
||||
- [x] Error handling comprehensive
|
||||
- [x] Rollback safety guaranteed
|
||||
|
||||
---
|
||||
|
||||
## Final Verdict
|
||||
|
||||
**Status**: ✅ **VERIFIED AND READY**
|
||||
|
||||
Phase 1 is:
|
||||
- ✅ Complete and well-structured
|
||||
- ✅ Aligned with Doc C requirements
|
||||
- ✅ Properly scoped (cold start only)
|
||||
- ✅ Ready for implementation
|
||||
- ⚠️ Minor documentation improvements recommended (non-blocking)
|
||||
|
||||
**Recommendation**: Proceed with implementation. Apply minor documentation improvements during implementation or in a follow-up commit.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ **Begin Implementation** - Phase 1 is verified and ready
|
||||
2. ⚠️ **Apply Minor Fixes** (optional) - Add explicit Doc A reference, update Related Documentation
|
||||
3. ✅ **Follow Testing Requirements** - Use Phase 1 §8 test scenarios
|
||||
4. ✅ **Update Status Matrix** - Mark Phase 1 as "In Use" when deployed
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Phase 1 Directive](../android-implementation-directive-phase1.md) - Implementation guide
|
||||
- [Plugin Requirements](./03-plugin-requirements.md#312-app-cold-start) - Requirements
|
||||
- [Platform Capability Reference](./01-platform-capability-reference.md#214-alarms-can-be-restored-after-app-restart) - OS facts
|
||||
- [Activation Guide](./ACTIVATION-GUIDE.md) - How to use directives
|
||||
|
||||
---
|
||||
|
||||
**Verification Date**: November 2025
|
||||
**Verified By**: Documentation Review
|
||||
**Status**: Complete
|
||||
|
||||
358
doc/alarms/PHASE2-EMULATOR-TESTING.md
Normal file
358
doc/alarms/PHASE2-EMULATOR-TESTING.md
Normal file
@@ -0,0 +1,358 @@
|
||||
# PHASE 2 – EMULATOR TESTING
|
||||
|
||||
**Force Stop Detection & Recovery**
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
Phase 2 verifies that the Daily Notification Plugin correctly:
|
||||
|
||||
1. Detects **force stop** scenarios (where alarms may be cleared by the OS).
|
||||
2. **Reschedules** future notifications when alarms are missing but schedules remain in the database.
|
||||
3. **Avoids heavy recovery** when alarms are still intact.
|
||||
4. **Does not misfire** force-stop recovery on first launch / empty database.
|
||||
|
||||
This document defines the emulator test procedure for Phase 2 using the script:
|
||||
|
||||
```bash
|
||||
test-apps/android-test-app/test-phase2.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Prerequisites
|
||||
|
||||
* Android emulator or device, e.g.:
|
||||
* Pixel 8 / API 34 (recommended baseline)
|
||||
* ADB available in `PATH` (or `ADB_BIN` exported)
|
||||
* Project built with:
|
||||
* Daily Notification Plugin integrated
|
||||
* Test app at: `test-apps/android-test-app`
|
||||
* Debug APK path:
|
||||
* `app/build/outputs/apk/debug/app-debug.apk`
|
||||
* Phase 1 behavior already implemented and verified:
|
||||
* Cold start detection
|
||||
* Missed notification marking
|
||||
|
||||
> **Note:** Some OS/device combinations do not clear alarms on `am force-stop`. In such cases, TEST 1 may partially skip or only verify scenario logging.
|
||||
|
||||
---
|
||||
|
||||
## 3. How to Run
|
||||
|
||||
From the `android-test-app` directory:
|
||||
|
||||
```bash
|
||||
cd test-apps/android-test-app
|
||||
chmod +x test-phase2.sh # first time only
|
||||
./test-phase2.sh
|
||||
```
|
||||
|
||||
The script will:
|
||||
|
||||
1. Perform pre-flight checks (ADB/emulator).
|
||||
2. Build and install the debug APK.
|
||||
3. Guide you through three tests:
|
||||
* TEST 1: Force stop – alarms cleared
|
||||
* TEST 2: Force stop / process stop – alarms intact
|
||||
* TEST 3: First launch / empty DB safeguard
|
||||
4. Print parsed recovery summaries from `DNP-REACTIVATION` logs.
|
||||
|
||||
You will be prompted for **UI actions** at each step (e.g., configuring the plugin, pressing "Test Notification").
|
||||
|
||||
---
|
||||
|
||||
## 4. Test Cases
|
||||
|
||||
### 4.1 TEST 1 – Force Stop with Cleared Alarms
|
||||
|
||||
**Goal:**
|
||||
|
||||
Verify that when a force stop clears alarms, the plugin:
|
||||
|
||||
* Detects the **FORCE_STOP** scenario.
|
||||
* Reschedules future notifications.
|
||||
* Completes recovery with `errors=0`.
|
||||
|
||||
**Steps (Script Flow):**
|
||||
|
||||
1. **Launch & configure plugin**
|
||||
* Script launches the app.
|
||||
* In the app UI, confirm:
|
||||
* `⚙️ Plugin Settings: ✅ Configured`
|
||||
* `🔌 Native Fetcher: ✅ Configured`
|
||||
* If not, press **Configure Plugin** and wait until both are ✅.
|
||||
|
||||
2. **Schedule a future notification**
|
||||
* Click **Test Notification** (or equivalent) to schedule a notification a few minutes in the future.
|
||||
|
||||
3. **Verify alarms are scheduled**
|
||||
* Script runs:
|
||||
```bash
|
||||
adb shell dumpsys alarm | grep org.timesafari.dailynotification
|
||||
```
|
||||
* Confirm at least one `RTC_WAKEUP` alarm for `org.timesafari.dailynotification`.
|
||||
|
||||
4. **Force stop the app**
|
||||
* Script executes:
|
||||
```bash
|
||||
adb shell am force-stop org.timesafari.dailynotification
|
||||
```
|
||||
|
||||
5. **Confirm alarms after force stop**
|
||||
* Script re-runs `dumpsys alarm`.
|
||||
* Ideal test case: **0** alarms for `org.timesafari.dailynotification` (alarms cleared).
|
||||
|
||||
6. **Trigger recovery**
|
||||
* Script clears logcat and launches the app.
|
||||
* Wait ~5 seconds for recovery.
|
||||
|
||||
7. **Collect and inspect logs**
|
||||
* Script collects `DNP-REACTIVATION` logs and parses:
|
||||
* `scenario=<value>`
|
||||
* `missed=<n>`
|
||||
* `rescheduled=<n>`
|
||||
* `verified=<n>`
|
||||
* `errors=<n>`
|
||||
|
||||
**Expected Logs (Ideal Case):**
|
||||
|
||||
* Scenario:
|
||||
```text
|
||||
DNP-REACTIVATION: Detected scenario: FORCE_STOP
|
||||
```
|
||||
|
||||
* Alarm handling:
|
||||
```text
|
||||
DNP-REACTIVATION: Rescheduled alarm: daily_<id> for <time>
|
||||
DNP-REACTIVATION: Rescheduled missing alarm: daily_<id> at <time>
|
||||
```
|
||||
|
||||
* Summary:
|
||||
```text
|
||||
DNP-REACTIVATION: Force stop recovery completed: missed=1, rescheduled=1, verified=0, errors=0
|
||||
```
|
||||
|
||||
**Pass Criteria:**
|
||||
|
||||
* `scenario=FORCE_STOP`
|
||||
* `rescheduled > 0`
|
||||
* `errors = 0`
|
||||
* Script prints:
|
||||
> `✅ TEST 1 PASSED: Force stop detected and alarms rescheduled (scenario=FORCE_STOP, rescheduled=1).`
|
||||
|
||||
**Partial / Edge Cases:**
|
||||
|
||||
* If alarms remain after `force-stop` on this device:
|
||||
* Script warns that FORCE_STOP may not fully trigger.
|
||||
* Mark this as **environment-limited** rather than a plugin failure.
|
||||
|
||||
---
|
||||
|
||||
### 4.2 TEST 2 – Force Stop / Process Stop with Intact Alarms
|
||||
|
||||
**Goal:**
|
||||
|
||||
Ensure we **do not run heavy force-stop recovery** when alarms are still intact.
|
||||
|
||||
**Steps (Script Flow):**
|
||||
|
||||
1. **Launch & configure plugin**
|
||||
* Same as TEST 1 (ensure both plugin statuses are ✅).
|
||||
|
||||
2. **Schedule another future notification**
|
||||
* Click **Test Notification** again to create a second schedule.
|
||||
|
||||
3. **Verify alarms are scheduled**
|
||||
* Confirm multiple alarms for `org.timesafari.dailynotification` via `dumpsys alarm`.
|
||||
|
||||
4. **Simulate a "soft stop"**
|
||||
* Script runs:
|
||||
```bash
|
||||
adb shell am kill org.timesafari.dailynotification
|
||||
```
|
||||
* Intent: stop the process but **not** clear alarms (actual behavior may vary by OS).
|
||||
|
||||
5. **Check alarms after soft stop**
|
||||
* Ensure alarms are still present in `dumpsys alarm`.
|
||||
|
||||
6. **Trigger recovery**
|
||||
* Script clears logcat and relaunches the app.
|
||||
* Wait ~5 seconds.
|
||||
|
||||
7. **Collect logs**
|
||||
* Script parses `DNP-REACTIVATION` logs for:
|
||||
* `scenario`
|
||||
* `rescheduled`
|
||||
* `errors`
|
||||
|
||||
**Expected Behavior:**
|
||||
|
||||
* `scenario` should **not** be `FORCE_STOP` (e.g., `COLD_START` or another non-force-stop scenario, depending on your implementation).
|
||||
* `rescheduled = 0`.
|
||||
* `errors = 0`.
|
||||
|
||||
**Pass Criteria:**
|
||||
|
||||
* Alarms still present after soft stop.
|
||||
* Recovery summary indicates **no force-stop-level rescheduling** when alarms are intact:
|
||||
* `scenario != FORCE_STOP`
|
||||
* `rescheduled = 0`
|
||||
* Script prints:
|
||||
> `✅ TEST 2 PASSED: No heavy force-stop recovery when alarms intact (scenario=<value>, rescheduled=0).`
|
||||
|
||||
If `scenario=FORCE_STOP` and `rescheduled>0` here, treat this as a **warning** and review scenario detection logic.
|
||||
|
||||
---
|
||||
|
||||
### 4.3 TEST 3 – First Launch / Empty DB Safeguard
|
||||
|
||||
**Goal:**
|
||||
|
||||
Ensure **force-stop recovery is not mis-triggered** when the app is freshly installed with **no schedules**.
|
||||
|
||||
**Steps (Script Flow):**
|
||||
|
||||
1. **Clear state**
|
||||
* Script uninstalls the app to clear DB/state:
|
||||
```bash
|
||||
adb uninstall org.timesafari.dailynotification
|
||||
```
|
||||
|
||||
2. **Reinstall APK**
|
||||
* Script reinstalls `app-debug.apk`.
|
||||
|
||||
3. **Launch app without scheduling anything**
|
||||
* Script launches the app.
|
||||
* Do **not** schedule notifications or configure plugin beyond initial display.
|
||||
|
||||
4. **Collect logs**
|
||||
* Script grabs `DNP-REACTIVATION` logs and parses:
|
||||
* `scenario`
|
||||
* `rescheduled`
|
||||
|
||||
**Expected Behavior:**
|
||||
|
||||
* Either:
|
||||
* No `DNP-REACTIVATION` logs at all (no recovery run), **or**
|
||||
* A specific "no schedules" scenario, e.g.:
|
||||
```text
|
||||
DNP-REACTIVATION: No schedules present — skipping recovery (first launch)
|
||||
```
|
||||
or
|
||||
```text
|
||||
DNP-REACTIVATION: Detected scenario: NONE
|
||||
```
|
||||
|
||||
* In both cases:
|
||||
* `rescheduled = 0`.
|
||||
|
||||
**Pass Criteria:**
|
||||
|
||||
* If **no logs**:
|
||||
* Pass: recovery correctly doesn't run at all on empty DB.
|
||||
* If logs present:
|
||||
* `scenario=NONE` (or equivalent) **and** `rescheduled=0`.
|
||||
|
||||
Script will report success when:
|
||||
|
||||
* `scenario == NONE_SCENARIO_VALUE` and `rescheduled=0`, or
|
||||
* No recovery logs are found.
|
||||
|
||||
---
|
||||
|
||||
## 5. Latest Known Good Run (Template)
|
||||
|
||||
Fill this in after your first successful emulator run.
|
||||
|
||||
```markdown
|
||||
---
|
||||
## Latest Known Good Run (Emulator)
|
||||
|
||||
**Environment**
|
||||
|
||||
- Device: Pixel 8 API 34 (Android 14)
|
||||
- App ID: `org.timesafari.dailynotification`
|
||||
- Build: Debug APK (`app-debug.apk`) from commit `<GIT_HASH>`
|
||||
- Script: `./test-phase2.sh`
|
||||
- Date: 2025-11-XX
|
||||
|
||||
**Results**
|
||||
|
||||
- ✅ TEST 1: Force Stop – Alarms Cleared
|
||||
- `scenario=FORCE_STOP`
|
||||
- `missed=1, rescheduled=1, verified=0, errors=0`
|
||||
|
||||
- ✅ TEST 2: Force Stop / Process Stop – Alarms Intact
|
||||
- `scenario=COLD_START` (or equivalent non-force-stop scenario)
|
||||
- `rescheduled=0, errors=0`
|
||||
|
||||
- ✅ TEST 3: First Launch / No Schedules
|
||||
- `scenario=NONE` (or no logs)
|
||||
- `rescheduled=0`
|
||||
|
||||
**Conclusion:**
|
||||
Phase 2 **Force Stop Detection & Recovery** is verified on the emulator using `test-phase2.sh`. This run is the canonical reference for future regression testing.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Troubleshooting
|
||||
|
||||
### Alarms Not Cleared on Force Stop
|
||||
|
||||
**Symptom**: `am force-stop` doesn't clear alarms in AlarmManager
|
||||
|
||||
**Cause**: Some Android versions/emulators don't clear alarms on force stop
|
||||
|
||||
**Solution**:
|
||||
- This is expected behavior on some systems
|
||||
- TEST 1 will run as Phase 1 (cold start) recovery
|
||||
- For full force stop validation, test on a device/OS that clears alarms
|
||||
- Script will report this as an environment limitation, not a failure
|
||||
|
||||
### Scenario Not Detected as FORCE_STOP
|
||||
|
||||
**Symptom**: Logs show `COLD_START` even when alarms were cleared
|
||||
|
||||
**Possible Causes**:
|
||||
1. Scenario detection logic not implemented (Phase 2 not complete)
|
||||
2. Alarm count check failing (`alarmsExist()` returning true when it shouldn't)
|
||||
3. Database query timing issue
|
||||
|
||||
**Solution**:
|
||||
- Verify Phase 2 implementation is complete
|
||||
- Check `ReactivationManager.detectScenario()` implementation
|
||||
- Review logs for alarm existence checks
|
||||
- Verify `alarmsExist()` uses PendingIntent check (not `nextAlarmClock`)
|
||||
|
||||
### Recovery Doesn't Reschedule Alarms
|
||||
|
||||
**Symptom**: `rescheduled=0` even when alarms were cleared
|
||||
|
||||
**Possible Causes**:
|
||||
1. Schedules not in database
|
||||
2. Reschedule logic failing
|
||||
3. Alarm scheduling permissions missing
|
||||
|
||||
**Solution**:
|
||||
- Verify schedules exist in database
|
||||
- Check logs for reschedule errors
|
||||
- Verify exact alarm permission is granted
|
||||
- Review `performForceStopRecovery()` implementation
|
||||
|
||||
---
|
||||
|
||||
## 7. Related Documentation
|
||||
|
||||
- [Phase 2 Directive](../android-implementation-directive-phase2.md) - Implementation details
|
||||
- [Phase 2 Verification](./PHASE2-VERIFICATION.md) - Verification report
|
||||
- [Phase 1 Testing Guide](./PHASE1-EMULATOR-TESTING.md) - Prerequisite testing
|
||||
- [Activation Guide](./ACTIVATION-GUIDE.md) - How to use directives
|
||||
- [Plugin Requirements](./03-plugin-requirements.md) - Requirements Phase 2 implements
|
||||
|
||||
---
|
||||
|
||||
**Status**: Ready for testing (Phase 2 implementation pending)
|
||||
**Last Updated**: November 2025
|
||||
195
doc/alarms/PHASE2-VERIFICATION.md
Normal file
195
doc/alarms/PHASE2-VERIFICATION.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# Phase 2 – Force Stop Recovery Verification
|
||||
|
||||
**Plugin:** Daily Notification Plugin
|
||||
**Scope:** Force stop detection & recovery (App ID: `org.timesafari.dailynotification`)
|
||||
**Related Docs:**
|
||||
|
||||
- `android-implementation-directive-phase2.md`
|
||||
- `03-plugin-requirements.md` (Force Stop & App Termination behavior)
|
||||
- `PHASE2-EMULATOR-TESTING.md`
|
||||
- `000-UNIFIED-ALARM-DIRECTIVE.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. Objective
|
||||
|
||||
Phase 2 verifies that the Daily Notification Plugin:
|
||||
|
||||
1. Correctly detects **force stop** conditions where alarms may have been cleared.
|
||||
2. **Reschedules** future notifications when schedules exist in the database but alarms are missing.
|
||||
3. **Avoids heavy recovery** when alarms are intact (no false positives).
|
||||
4. **Does not misfire** force-stop recovery on first launch / empty database.
|
||||
|
||||
Phase 2 builds on Phase 1, which already covers:
|
||||
|
||||
- Cold start detection
|
||||
- Missed notification marking
|
||||
- Basic alarm verification
|
||||
|
||||
---
|
||||
|
||||
## 2. Test Method
|
||||
|
||||
Verification is performed using the emulator test harness:
|
||||
|
||||
```bash
|
||||
cd test-apps/android-test-app
|
||||
./test-phase2.sh
|
||||
```
|
||||
|
||||
This script:
|
||||
|
||||
* Builds and installs the debug APK (`app/build/outputs/apk/debug/app-debug.apk`).
|
||||
* Guides the tester through UI steps for scheduling notifications and configuring the plugin.
|
||||
* Simulates:
|
||||
* `force-stop` behavior via `adb shell am force-stop ...`
|
||||
* "Soft stop" / process kill via `adb shell am kill ...`
|
||||
* First launch / empty DB via uninstall + reinstall
|
||||
* Collects and parses `DNP-REACTIVATION` log lines, extracting:
|
||||
* `scenario`
|
||||
* `missed`
|
||||
* `rescheduled`
|
||||
* `verified`
|
||||
* `errors`
|
||||
|
||||
Detailed steps and expectations are documented in `PHASE2-EMULATOR-TESTING.md`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Test Matrix
|
||||
|
||||
| ID | Scenario | Method / Script Step | Expected Behavior | Result | Notes |
|
||||
| --- | ---------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ------ | ----- |
|
||||
| 2.1 | Force stop clears alarms | `test-phase2.sh` – TEST 1: Force Stop – Alarms Cleared | `scenario=FORCE_STOP`, `rescheduled>0`, `errors=0` | ☐ | |
|
||||
| 2.2 | Force stop / process stop with alarms intact | `test-phase2.sh` – TEST 2: Soft Stop – Alarms Intact | `scenario != FORCE_STOP`, `rescheduled=0`, `errors=0` | ☐ | |
|
||||
| 2.3 | First launch / empty DB (no schedules present) | `test-phase2.sh` – TEST 3: First Launch / No Schedules | Either no recovery logs **or** `scenario=NONE` (or equivalent) and `rescheduled=0`, `errors=0` | ☐ | |
|
||||
|
||||
> Fill in **Result** and **Notes** after executing the script on your baseline emulator/device.
|
||||
|
||||
---
|
||||
|
||||
## 4. Expected Log Patterns
|
||||
|
||||
### 4.1 Force Stop – Alarms Cleared (Test 2.1)
|
||||
|
||||
Typical expected `DNP-REACTIVATION` log patterns:
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: Detected scenario: FORCE_STOP
|
||||
DNP-REACTIVATION: Rescheduled alarm: daily_<id> for <time>
|
||||
DNP-REACTIVATION: Rescheduled missing alarm: daily_<id> at <time>
|
||||
DNP-REACTIVATION: Force stop recovery completed: missed=1, rescheduled=1, verified=0, errors=0
|
||||
```
|
||||
|
||||
The **script** will report:
|
||||
|
||||
```text
|
||||
✅ TEST 1 PASSED: Force stop detected and alarms rescheduled (scenario=FORCE_STOP, rescheduled=1).
|
||||
```
|
||||
|
||||
### 4.2 Soft Stop – Alarms Intact (Test 2.2)
|
||||
|
||||
Typical expected patterns:
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: Detected scenario: COLD_START
|
||||
DNP-REACTIVATION: Cold start recovery completed: missed=0, rescheduled=0, verified>=0, errors=0
|
||||
```
|
||||
|
||||
The script should **not** treat this as a force-stop recovery:
|
||||
|
||||
```text
|
||||
✅ TEST 2 PASSED: No heavy force-stop recovery when alarms are intact (scenario=COLD_START, rescheduled=0).
|
||||
```
|
||||
|
||||
(Adjust `scenario` name to match your actual implementation.)
|
||||
|
||||
### 4.3 First Launch / Empty DB (Test 2.3)
|
||||
|
||||
Two acceptable patterns:
|
||||
|
||||
1. **No recovery logs at all** (`DNP-REACTIVATION` absent), or
|
||||
2. Explicit "no schedules" scenario, e.g.:
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: No schedules present — skipping recovery (first launch)
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: Detected scenario: NONE
|
||||
```
|
||||
|
||||
Script-level success message might be:
|
||||
|
||||
```text
|
||||
✅ TEST 3 PASSED: NONE scenario detected with no rescheduling.
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```text
|
||||
✅ TEST 3 PASSED: No recovery logs when there are no schedules (safe behavior).
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Latest Known Good Run (Emulator) – Placeholder
|
||||
|
||||
> Update this section after your first successful run.
|
||||
|
||||
**Environment**
|
||||
|
||||
* Device: Pixel 8 API 34 (Android 14)
|
||||
* App ID: `org.timesafari.dailynotification`
|
||||
* Build: Debug `app-debug.apk` from commit `<GIT_HASH>`
|
||||
* Script: `./test-phase2.sh`
|
||||
* Date: 2025-11-XX
|
||||
|
||||
**Observed Results**
|
||||
|
||||
* ☐ **2.1 – Force Stop / Alarms Cleared**
|
||||
* `scenario=FORCE_STOP`
|
||||
* `missed=1, rescheduled=1, verified=0, errors=0`
|
||||
|
||||
* ☐ **2.2 – Soft Stop / Alarms Intact**
|
||||
* `scenario=COLD_START` (or equivalent non-force-stop scenario)
|
||||
* `rescheduled=0, errors=0`
|
||||
|
||||
* ☐ **2.3 – First Launch / Empty DB**
|
||||
* `scenario=NONE` (or no logs)
|
||||
* `rescheduled=0, errors=0`
|
||||
|
||||
**Conclusion:**
|
||||
|
||||
> To be filled after first successful emulator run.
|
||||
|
||||
---
|
||||
|
||||
## 6. Overall Status
|
||||
|
||||
> To be updated once the first emulator pass is complete.
|
||||
|
||||
* **Implementation Status:** ☐ Pending / ✅ Implemented in `ReactivationManager` (Android plugin)
|
||||
* **Test Harness:** ✅ `test-phase2.sh` in `test-apps/android-test-app`
|
||||
* **Emulator Verification:** ☐ Pending / ✅ Completed (update when done)
|
||||
|
||||
Once all boxes are checked:
|
||||
|
||||
> **Overall Status:** ✅ **VERIFIED** – Phase 2 behavior is implemented, emulator-tested, and aligned with `03-plugin-requirements.md` and `android-implementation-directive-phase2.md`.
|
||||
|
||||
---
|
||||
|
||||
## 7. Related Documentation
|
||||
|
||||
- [Phase 2 Directive](../android-implementation-directive-phase2.md) - Implementation details
|
||||
- [Phase 2 Emulator Testing](./PHASE2-EMULATOR-TESTING.md) - Test procedures
|
||||
- [Phase 1 Verification](./PHASE1-VERIFICATION.md) - Prerequisite verification
|
||||
- [Plugin Requirements](./03-plugin-requirements.md) - Requirements this phase implements
|
||||
- [Platform Capability Reference](./01-platform-capability-reference.md) - OS-level facts
|
||||
|
||||
---
|
||||
|
||||
**Status**: ☐ **PENDING** – Phase 2 implementation and testing pending
|
||||
**Last Updated**: November 2025
|
||||
325
doc/alarms/PHASE3-EMULATOR-TESTING.md
Normal file
325
doc/alarms/PHASE3-EMULATOR-TESTING.md
Normal file
@@ -0,0 +1,325 @@
|
||||
# PHASE 3 – EMULATOR TESTING
|
||||
|
||||
**Boot-Time Recovery (Device Reboot / System Restart)**
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
Phase 3 verifies that the Daily Notification Plugin correctly:
|
||||
|
||||
1. Reconstructs **AlarmManager** alarms after a full device/emulator reboot.
|
||||
2. Handles **past** scheduled times by marking them as missed and scheduling the next occurrence.
|
||||
3. Handles **empty DB / no schedules** without misfiring recovery.
|
||||
4. Performs **silent boot recovery** (recreate alarms) even when the app is never opened after reboot.
|
||||
|
||||
This testing is driven by the script:
|
||||
|
||||
```bash
|
||||
test-apps/android-test-app/test-phase3.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Prerequisites
|
||||
|
||||
* Android emulator or device, e.g.:
|
||||
* Pixel 8 / API 34 (recommended baseline)
|
||||
* ADB available in `PATH` (or `ADB_BIN` exported)
|
||||
* Project with:
|
||||
* Daily Notification Plugin integrated
|
||||
* Test app at `test-apps/android-test-app`
|
||||
* Debug APK path:
|
||||
* `app/build/outputs/apk/debug/app-debug.apk`
|
||||
* Phase 1 and Phase 2 behaviors already implemented:
|
||||
* Cold start detection
|
||||
* Force-stop detection
|
||||
* Missed / rescheduled / verified / errors summary fields
|
||||
|
||||
> ⚠️ **Important:**
|
||||
> This script will reboot the emulator multiple times. Each reboot may take 30–60 seconds.
|
||||
|
||||
---
|
||||
|
||||
## 3. How to Run
|
||||
|
||||
From the `android-test-app` directory:
|
||||
|
||||
```bash
|
||||
cd test-apps/android-test-app
|
||||
chmod +x test-phase3.sh # first time only
|
||||
./test-phase3.sh
|
||||
```
|
||||
|
||||
The script will:
|
||||
|
||||
1. Run pre-flight checks (ADB / emulator readiness).
|
||||
2. Build and install the debug APK.
|
||||
3. Guide you through four tests:
|
||||
* **TEST 1:** Boot with Future Alarms
|
||||
* **TEST 2:** Boot with Past Alarms
|
||||
* **TEST 3:** Boot with No Schedules
|
||||
* **TEST 4:** Silent Boot Recovery (App Never Opened)
|
||||
4. Parse and display `DNP-REACTIVATION` logs, including:
|
||||
* `scenario`
|
||||
* `missed`
|
||||
* `rescheduled`
|
||||
* `verified`
|
||||
* `errors`
|
||||
|
||||
---
|
||||
|
||||
## 4. Test Cases (Script-Driven Flow)
|
||||
|
||||
### 4.1 TEST 1 – Boot with Future Alarms
|
||||
|
||||
**Goal:**
|
||||
|
||||
Verify alarms are recreated on boot when schedules have **future run times**.
|
||||
|
||||
**Script flow:**
|
||||
|
||||
1. **Launch app & check plugin status**
|
||||
* Script calls `launch_app`.
|
||||
* UI prompt: Confirm plugin status shows:
|
||||
* `⚙️ Plugin Settings: ✅ Configured`
|
||||
* `🔌 Native Fetcher: ✅ Configured`
|
||||
* If not, click **Configure Plugin**, wait until both show ✅, then continue.
|
||||
|
||||
2. **Schedule at least one future notification**
|
||||
* UI prompt: Click e.g. **Test Notification** to schedule a notification a few minutes in the future.
|
||||
|
||||
3. **Verify alarms are scheduled (pre-boot)**
|
||||
* Script calls `show_alarms` and `count_alarms`.
|
||||
* You should see at least one `RTC_WAKEUP` entry for `org.timesafari.dailynotification`.
|
||||
|
||||
4. **Reboot emulator**
|
||||
* Script calls `reboot_emulator`:
|
||||
* `adb reboot`
|
||||
* `adb wait-for-device`
|
||||
* Polls `getprop sys.boot_completed` until `1`.
|
||||
* You are warned that reboot will take 30–60 seconds.
|
||||
|
||||
5. **Collect boot recovery logs**
|
||||
* Script calls `get_recovery_logs`:
|
||||
```bash
|
||||
adb logcat -d | grep "DNP-REACTIVATION"
|
||||
```
|
||||
* It parses:
|
||||
* `missed`, `rescheduled`, `verified`, `errors`
|
||||
* `scenario` via:
|
||||
* `Starting boot recovery`/`boot recovery` → `scenario=BOOT`
|
||||
* or `Detected scenario: <VALUE>`
|
||||
|
||||
6. **Verify alarms were recreated (post-boot)**
|
||||
* Script calls `show_alarms` and `count_alarms` again.
|
||||
* Checks `scenario` and `rescheduled`.
|
||||
|
||||
**Expected log patterns:**
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: Starting boot recovery
|
||||
DNP-REACTIVATION: Loaded <N> schedules from DB
|
||||
DNP-REACTIVATION: Rescheduled alarm: daily_<id> for <time>
|
||||
DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled>=1, verified=0, errors=0
|
||||
```
|
||||
|
||||
**Pass criteria (as per script):**
|
||||
|
||||
* `errors = 0`
|
||||
* `scenario = BOOT` (or boot detected via log text)
|
||||
* `rescheduled > 0`
|
||||
* Script prints:
|
||||
> `✅ TEST 1 PASSED: Boot recovery detected and alarms rescheduled (scenario=BOOT, rescheduled=<n>).`
|
||||
|
||||
If boot recovery runs but `rescheduled=0`, script warns and suggests checking boot logic.
|
||||
|
||||
---
|
||||
|
||||
### 4.2 TEST 2 – Boot with Past Alarms
|
||||
|
||||
**Goal:**
|
||||
|
||||
Verify past alarms are marked as missed and **next occurrences are scheduled** after boot.
|
||||
|
||||
**Script flow:**
|
||||
|
||||
1. **Launch app & ensure plugin configured**
|
||||
* Same plugin status check as TEST 1.
|
||||
|
||||
2. **Schedule a notification in the near future**
|
||||
* UI prompt: Schedule such that **by the time you reboot and the device comes back, the planned notification time is in the past**.
|
||||
|
||||
3. **Wait or adjust so the alarm is effectively "in the past" at boot**
|
||||
* The script may instruct you to wait, or you can coordinate timing manually.
|
||||
|
||||
4. **Reboot emulator**
|
||||
* Same `reboot_emulator` path as TEST 1.
|
||||
|
||||
5. **Collect boot recovery logs**
|
||||
* Script parses:
|
||||
* `missed`, `rescheduled`, `errors`, `scenario`.
|
||||
|
||||
**Expected log patterns:**
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: Starting boot recovery
|
||||
DNP-REACTIVATION: Loaded <N> schedules from DB
|
||||
DNP-REACTIVATION: Marked missed notification: daily_<id>
|
||||
DNP-REACTIVATION: Rescheduled alarm: daily_<id> for <next_time>
|
||||
DNP-REACTIVATION: Boot recovery complete: missed>=1, rescheduled>=1, errors=0
|
||||
```
|
||||
|
||||
**Pass criteria:**
|
||||
|
||||
* `errors = 0`
|
||||
* `missed >= 1`
|
||||
* `rescheduled >= 1`
|
||||
* Script prints:
|
||||
> `✅ TEST 2 PASSED: Past alarms detected and next occurrence scheduled (missed=<m>, rescheduled=<r>).`
|
||||
|
||||
If `missed >= 1` but `rescheduled = 0`, script warns that reschedule logic may be incomplete.
|
||||
|
||||
---
|
||||
|
||||
### 4.3 TEST 3 – Boot with No Schedules
|
||||
|
||||
**Goal:**
|
||||
|
||||
Verify boot recovery handles an **empty DB / no schedules** safely and does **not** schedule anything.
|
||||
|
||||
**Script flow:**
|
||||
|
||||
1. **Uninstall app to clear DB/state**
|
||||
* Script calls:
|
||||
```bash
|
||||
adb uninstall org.timesafari.dailynotification
|
||||
```
|
||||
|
||||
2. **Reinstall APK**
|
||||
* Script reinstalls `app-debug.apk`.
|
||||
|
||||
3. **Launch app WITHOUT scheduling anything**
|
||||
* Script launches app; you do not configure or schedule.
|
||||
|
||||
4. **Collect boot/logs**
|
||||
* Script reads `DNP-REACTIVATION` logs and checks:
|
||||
* if there are no logs, or
|
||||
* if there's a "No schedules found / present" message, or
|
||||
* if `scenario=NONE` and `rescheduled=0`.
|
||||
|
||||
**Expected patterns:**
|
||||
|
||||
* *Ideal simple case:* **No** `DNP-REACTIVATION` logs at all, or:
|
||||
* Explicit message in logs:
|
||||
```text
|
||||
DNP-REACTIVATION: ... No schedules found ...
|
||||
```
|
||||
|
||||
**Pass criteria (as per script):**
|
||||
|
||||
* If **no logs**:
|
||||
* Pass: `TEST 3 PASSED: No recovery logs when there are no schedules (safe behavior).`
|
||||
* If logs exist:
|
||||
* Contains `No schedules found` / `No schedules present` **and** `rescheduled=0`, or
|
||||
* `scenario = NONE` and `rescheduled = 0`.
|
||||
|
||||
Any case where `rescheduled > 0` with an empty DB is flagged as a warning (boot recovery misfiring).
|
||||
|
||||
---
|
||||
|
||||
### 4.4 TEST 4 – Silent Boot Recovery (App Never Opened)
|
||||
|
||||
**Goal:**
|
||||
|
||||
Verify that boot recovery **occurs silently**, recreating alarms **without opening the app** after reboot.
|
||||
|
||||
**Script flow:**
|
||||
|
||||
1. **Launch app and configure plugin**
|
||||
* Same plugin status flow:
|
||||
* Ensure both plugin checks are ✅.
|
||||
* Schedule a future notification via UI.
|
||||
|
||||
2. **Verify alarms are scheduled**
|
||||
* Script shows alarms and counts (`before_count`).
|
||||
|
||||
3. **Reboot emulator**
|
||||
* Script runs `reboot_emulator` and explicitly warns:
|
||||
* Do **not** open the app after reboot.
|
||||
* After emulator returns, script instructs you to **not touch the app UI**.
|
||||
|
||||
4. **Collect boot recovery logs**
|
||||
* Script gathers and parses `DNP-REACTIVATION` lines.
|
||||
|
||||
5. **Verify alarms were recreated without app launch**
|
||||
* Script calls `show_alarms` and `count_alarms` again.
|
||||
* Uses `rescheduled` + alarm count to decide.
|
||||
|
||||
**Pass criteria (as per script):**
|
||||
|
||||
* `rescheduled > 0` after boot, and
|
||||
* Alarm count after boot is > 0, and
|
||||
* App was **never** launched by the user after reboot.
|
||||
|
||||
Script prints one of:
|
||||
|
||||
```text
|
||||
✅ TEST 4 PASSED: Boot recovery occurred silently and alarms were recreated (rescheduled=<n>) without app launch.
|
||||
|
||||
✅ TEST 4 PASSED: Boot recovery occurred silently (rescheduled=<n>), but alarm count check unclear.
|
||||
```
|
||||
|
||||
If boot recovery logs are present but no alarms appear, script warns; if no boot-recovery logs are found at all, script suggests verifying the boot receiver and BOOT_COMPLETED permission.
|
||||
|
||||
---
|
||||
|
||||
## 5. Overall Summary Section (from Script)
|
||||
|
||||
At the end, the script prints:
|
||||
|
||||
```text
|
||||
TEST 1: Boot with Future Alarms
|
||||
- Check logs for boot recovery and rescheduled>0
|
||||
|
||||
TEST 2: Boot with Past Alarms
|
||||
- Check logs for missed>=1 and rescheduled>=1
|
||||
|
||||
TEST 3: Boot with No Schedules
|
||||
- Check that no recovery runs or that an explicit 'No schedules found' is logged without rescheduling
|
||||
|
||||
TEST 4: Silent Boot Recovery
|
||||
- Check that boot recovery occurred and alarms were recreated without app launch
|
||||
```
|
||||
|
||||
Use this as a quick checklist after a run.
|
||||
|
||||
---
|
||||
|
||||
## 6. Troubleshooting Notes
|
||||
|
||||
* If **no boot recovery logs** ever appear:
|
||||
* Check that `BootReceiver` is declared and `RECEIVE_BOOT_COMPLETED` permission is set.
|
||||
* Ensure the app is installed in internal storage (not moved to SD).
|
||||
|
||||
* If **errors > 0** in summary:
|
||||
* Inspect the full `DNP-REACTIVATION` logs printed by the script.
|
||||
|
||||
* If **alarming duplication** is observed:
|
||||
* Review `runBootRecovery` and dedupe logic around re-scheduling.
|
||||
|
||||
---
|
||||
|
||||
## 7. Related Documentation
|
||||
|
||||
- [Phase 3 Directive](../android-implementation-directive-phase3.md) - Implementation details
|
||||
- [Phase 3 Verification](./PHASE3-VERIFICATION.md) - Verification report
|
||||
- [Phase 1 Testing Guide](./PHASE1-EMULATOR-TESTING.md) - Prerequisite testing
|
||||
- [Phase 2 Testing Guide](./PHASE2-EMULATOR-TESTING.md) - Prerequisite testing
|
||||
- [Activation Guide](./ACTIVATION-GUIDE.md) - How to use directives
|
||||
- [Plugin Requirements](./03-plugin-requirements.md) - Requirements Phase 3 implements
|
||||
|
||||
---
|
||||
|
||||
**Status**: Ready for testing (Phase 3 implementation pending)
|
||||
**Last Updated**: November 2025
|
||||
201
doc/alarms/PHASE3-VERIFICATION.md
Normal file
201
doc/alarms/PHASE3-VERIFICATION.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Phase 3 – Boot-Time Recovery Verification
|
||||
|
||||
**Plugin:** Daily Notification Plugin
|
||||
**Scope:** Boot-Time Recovery (Recreate Alarms After Reboot)
|
||||
**Related Docs:**
|
||||
- `android-implementation-directive-phase3.md`
|
||||
- `PHASE3-EMULATOR-TESTING.md`
|
||||
- `test-phase3.sh`
|
||||
- `000-UNIFIED-ALARM-DIRECTIVE.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. Objective
|
||||
|
||||
Phase 3 confirms that the Daily Notification Plugin:
|
||||
|
||||
1. Reconstructs all daily notification alarms after a **full device reboot**.
|
||||
2. Correctly handles **past** vs **future** schedules:
|
||||
- Past: mark as missed, schedule next occurrence
|
||||
- Future: simply recreate alarms
|
||||
3. Handles **empty DB / no schedules** without misfiring recovery.
|
||||
4. Performs **silent boot recovery** (no app launch required) when schedules exist.
|
||||
5. Logs a consistent, machine-readable summary:
|
||||
- `scenario`
|
||||
- `missed`
|
||||
- `rescheduled`
|
||||
- `verified`
|
||||
- `errors`
|
||||
|
||||
Verification is performed via the emulator harness:
|
||||
|
||||
```bash
|
||||
cd test-apps/android-test-app
|
||||
./test-phase3.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Test Matrix (From Script)
|
||||
|
||||
| ID | Scenario | Script Test | Expected Behavior | Result | Notes |
|
||||
| --- | --------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | ------ | ----- |
|
||||
| 3.1 | Boot with Future Alarms | TEST 1 – Boot with Future Alarms | `scenario=BOOT`, `rescheduled>0`, `errors=0`; alarms present after boot | ☐ | |
|
||||
| 3.2 | Boot with Past Alarms | TEST 2 – Boot with Past Alarms | `missed>=1` and `rescheduled>=1`, `errors=0`; past schedules detected and next occurrences scheduled | ☐ | |
|
||||
| 3.3 | Boot with No Schedules (Empty DB) | TEST 3 – Boot with No Schedules | Either no recovery logs **or** explicit "No schedules found/present" or `scenario=NONE` with `rescheduled=0`, `errors=0` | ☐ | |
|
||||
| 3.4 | Silent Boot Recovery (App Never Opened) | TEST 4 – Silent Boot Recovery (App Never Opened) | `rescheduled>0`, alarms present after boot, and no user launch required; `errors=0` | ☐ | |
|
||||
|
||||
Fill **Result** and **Notes** after running `test-phase3.sh` on your baseline emulator/device.
|
||||
|
||||
---
|
||||
|
||||
## 3. Expected Log Patterns
|
||||
|
||||
The script filters logs with:
|
||||
|
||||
```bash
|
||||
adb logcat -d | grep "DNP-REACTIVATION"
|
||||
```
|
||||
|
||||
### 3.1 Boot with Future Alarms (3.1 / TEST 1)
|
||||
|
||||
* Typical logs:
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: Starting boot recovery
|
||||
DNP-REACTIVATION: Loaded <N> schedules from DB
|
||||
DNP-REACTIVATION: Rescheduled alarm: daily_<id> for <time>
|
||||
DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled=<r>, verified=0, errors=0
|
||||
```
|
||||
|
||||
* The script interprets this as:
|
||||
* `scenario = BOOT` (via "Starting boot recovery" or "boot recovery" text or `Detected scenario: BOOT`)
|
||||
* `rescheduled > 0`
|
||||
* `errors = 0`
|
||||
|
||||
### 3.2 Boot with Past Alarms (3.2 / TEST 2)
|
||||
|
||||
* Typical logs:
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: Starting boot recovery
|
||||
DNP-REACTIVATION: Loaded <N> schedules from DB
|
||||
DNP-REACTIVATION: Marked missed notification: daily_<id>
|
||||
DNP-REACTIVATION: Rescheduled alarm: daily_<id> for <next_time>
|
||||
DNP-REACTIVATION: Boot recovery complete: missed=<m>, rescheduled=<r>, verified=0, errors=0
|
||||
```
|
||||
|
||||
* The script parses `missed` and `rescheduled` and passes when:
|
||||
* `missed >= 1`
|
||||
* `rescheduled >= 1`
|
||||
* `errors = 0`
|
||||
|
||||
### 3.3 Boot with No Schedules (3.3 / TEST 3)
|
||||
|
||||
Two acceptable patterns:
|
||||
|
||||
1. **No `DNP-REACTIVATION` logs at all** → safe behavior
|
||||
2. Explicit "no schedules" logs:
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: ... No schedules found ...
|
||||
```
|
||||
|
||||
or a neutral scenario:
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: ... scenario=NONE ...
|
||||
DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled=0, verified=0, errors=0
|
||||
```
|
||||
|
||||
The script passes when:
|
||||
|
||||
* Either `logs` are empty, or
|
||||
* Logs contain "No schedules found / present" with `rescheduled=0`, or
|
||||
* `scenario=NONE` and `rescheduled=0`.
|
||||
|
||||
Any `rescheduled>0` in this state is flagged as a potential boot-recovery misfire.
|
||||
|
||||
### 3.4 Silent Boot Recovery (3.4 / TEST 4)
|
||||
|
||||
* Expected:
|
||||
|
||||
```text
|
||||
DNP-REACTIVATION: Starting boot recovery
|
||||
DNP-REACTIVATION: Loaded <N> schedules from DB
|
||||
DNP-REACTIVATION: Rescheduled alarm: daily_<id> for <time>
|
||||
DNP-REACTIVATION: Boot recovery complete: missed=0, rescheduled=<r>, verified=0, errors=0
|
||||
```
|
||||
|
||||
* After reboot:
|
||||
* `count_alarms` > 0
|
||||
* User **did not** relaunch the app manually
|
||||
|
||||
Script passes if:
|
||||
|
||||
* `rescheduled>0`, and
|
||||
* Alarm count after boot is > 0, and
|
||||
* Boot recovery is detected from logs (via "Starting boot recovery"/"boot recovery" or scenario).
|
||||
|
||||
---
|
||||
|
||||
## 4. Latest Known Good Run (Template)
|
||||
|
||||
> Fill this in after your first clean emulator run.
|
||||
|
||||
**Environment**
|
||||
|
||||
* Device: Pixel 8 API 34 (Android 14)
|
||||
* App ID: `org.timesafari.dailynotification`
|
||||
* Build: Debug `app-debug.apk` from commit `<GIT_HASH>`
|
||||
* Script: `./test-phase3.sh`
|
||||
* Date: 2025-11-XX
|
||||
|
||||
**Observed Results**
|
||||
|
||||
* ☐ **3.1 – Boot with Future Alarms**
|
||||
* `scenario=BOOT`
|
||||
* `missed=0, rescheduled=<r>, errors=0`
|
||||
|
||||
* ☐ **3.2 – Boot with Past Alarms**
|
||||
* `missed=<m>=1`, `rescheduled=<r>≥1`, `errors=0`
|
||||
|
||||
* ☐ **3.3 – Boot with No Schedules**
|
||||
* Either no logs, or explicit "No schedules found" with `rescheduled=0`
|
||||
|
||||
* ☐ **3.4 – Silent Boot Recovery**
|
||||
* `rescheduled>0`, alarms present after boot, app not opened
|
||||
|
||||
**Conclusion:**
|
||||
|
||||
> Phase 3 **Boot-Time Recovery** is successfully verified on emulator using `test-phase3.sh`. This is the canonical baseline for future regression testing and refactors to `ReactivationManager` and `BootReceiver`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Overall Status
|
||||
|
||||
> Update once the first emulator run is complete.
|
||||
|
||||
* **Implementation Status:** ☐ Pending / ✅ Implemented (Boot receiver + `runBootRecovery`)
|
||||
* **Test Harness:** ✅ `test-phase3.sh` in `test-apps/android-test-app`
|
||||
* **Emulator Verification:** ☐ Pending / ✅ Completed
|
||||
|
||||
Once all test cases pass:
|
||||
|
||||
> **Overall Status:** ✅ **VERIFIED** – Phase 3 boot-time recovery is implemented and emulator-tested, aligned with `android-implementation-directive-phase3.md` and the unified alarm directive.
|
||||
|
||||
---
|
||||
|
||||
## 6. Related Documentation
|
||||
|
||||
- [Phase 3 Directive](../android-implementation-directive-phase3.md) - Implementation details
|
||||
- [Phase 3 Emulator Testing](./PHASE3-EMULATOR-TESTING.md) - Test procedures
|
||||
- [Phase 1 Verification](./PHASE1-VERIFICATION.md) - Prerequisite verification
|
||||
- [Phase 2 Verification](./PHASE2-VERIFICATION.md) - Prerequisite verification
|
||||
- [Plugin Requirements](./03-plugin-requirements.md) - Requirements this phase implements
|
||||
- [Platform Capability Reference](./01-platform-capability-reference.md) - OS-level facts
|
||||
|
||||
---
|
||||
|
||||
**Status**: ☐ **PENDING** – Phase 3 implementation and testing pending
|
||||
**Last Updated**: November 2025
|
||||
Reference in New Issue
Block a user