# Plugin Behavior Exploration Template

**Author**: Matthew Raymer  
**Date**: November 2025  
**Status**: Active Exploration Template

## Purpose

This document provides an **executable template** for exploring and documenting the current plugin's alarm/schedule/notification behavior on Android and iOS.

**Use this template to**:
1. Test plugin behavior across different scenarios
2. Document expected vs actual results
3. Identify gaps between current behavior and platform capabilities
4. Generate findings for the Plugin Requirements document

**Reference**: See [Platform Capability Reference](../alarms/01-platform-capability-reference.md) for OS-level facts.

---

## 0. Quick Reference: Platform Capabilities

**Android**: See [Platform Capability Reference - Android Section](../alarms/01-platform-capability-reference.md#2-android-alarm-capability-matrix)

**iOS**: See [Platform Capability Reference - iOS Section](../alarms/01-platform-capability-reference.md#3-ios-notification-capability-matrix)

**Key Differences**:
* Android: Alarms wiped on reboot; must reschedule
* iOS: Notifications persist across reboot automatically
* Android: App code runs when alarm fires
* iOS: App code does NOT run when notification fires (unless user interacts)

---

## 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 | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule alarm 2 minutes in future | - | Alarm scheduled | ☐ | |
| 2 | Leave app in foreground/background | - | - | ☐ | |
| 3 | Wait for trigger time | Alarm fires | Notification displayed | ☐ | |
| 4 | Check logs | - | No errors | ☐ | |

**Code Reference**: `NotifyReceiver.scheduleExactNotification()` line 92

---

#### Test 2: Swipe from Recents

| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule alarm 2-5 minutes in future | - | Alarm scheduled | ☐ | |
| 2 | Swipe app away from recents | - | - | ☐ | |
| 3 | Wait for trigger time | ✅ Alarm fires (OS resurrects process) | ✅ Notification displayed | ☐ | |
| 4 | Check app state on wake | Cold start | App process recreated | ☐ | |
| 5 | Check logs | - | No errors | ☐ | |

**Code Reference**: `NotifyReceiver.scheduleExactNotification()` uses `setAlarmClock()` line 219

**Platform Behavior**: OS-guaranteed (Android AlarmManager)

---

#### Test 3: OS Kill (Memory Pressure)

| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule alarm 2-5 minutes in future | - | Alarm scheduled | ☐ | |
| 2 | Force kill via `adb shell am kill <package>` | - | - | ☐ | |
| 3 | Wait for trigger time | ✅ Alarm fires | ✅ Notification displayed | ☐ | |
| 4 | Check logs | - | No errors | ☐ | |

**Platform Behavior**: OS-guaranteed (Android AlarmManager)

---

#### Test 4: Device Reboot

| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule alarm 10 minutes in future | - | Alarm scheduled | ☐ | |
| 2 | Reboot device | - | - | ☐ | |
| 3 | Do NOT open app | ❌ Alarm does NOT fire | ❌ No notification | ☐ | |
| 4 | Wait past scheduled time | ❌ No automatic firing | ❌ No notification | ☐ | |
| 5 | Open app manually | - | Plugin detects missed alarm | ☐ | |
| 6 | Check missed alarm handling | - | ✅ Missed alarm detected | ☐ | |
| 7 | Check rescheduling | - | ✅ Future alarms rescheduled | ☐ | |

**Code Reference**: 
- Boot receiver: `BootReceiver.kt` line 24
- Rescheduling: `BootReceiver.kt` line 38+

**Platform Behavior**: Plugin-guaranteed (must implement boot receiver)

**Expected Plugin Behavior**: Plugin must reschedule from database on boot

---

#### Test 5: Android Force Stop

| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule alarm | - | Alarm scheduled | ☐ | |
| 2 | Go to Settings → Apps → [App] → Force Stop | ❌ All alarms removed | ❌ All alarms removed | ☐ | |
| 3 | Wait for trigger time | ❌ Alarm does NOT fire | ❌ No notification | ☐ | |
| 4 | Open app again | - | Plugin detects missed alarm | ☐ | |
| 5 | Check recovery | - | ✅ Missed alarm detected | ☐ | |
| 6 | Check rescheduling | - | ✅ Future alarms rescheduled | ☐ | |

**Platform Behavior**: Not allowed (Android hard kill)

**Expected Plugin Behavior**: Plugin must detect and recover on app restart

---

#### Test 6: Exact Alarm Permission (Android 12+)

| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Revoke exact alarm permission | - | - | ☐ | |
| 2 | Attempt to schedule alarm | - | Plugin requests permission | ☐ | |
| 3 | Check settings opened | - | ✅ Settings opened | ☐ | |
| 4 | Grant permission | - | - | ☐ | |
| 5 | Schedule alarm | - | ✅ Alarm scheduled | ☐ | |
| 6 | Verify alarm fires | ✅ Alarm fires | ✅ Notification displayed | ☐ | |

**Code Reference**: `DailyNotificationPlugin.kt` line 1309, 1314-1324

---

### 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. iOS Exploration

### 2.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 |

### 2.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

---

#### Test 2: Swipe App Away

| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule notification 2-5 minutes in future | - | Notification scheduled | ☐ | |
| 2 | Swipe app away from app switcher | - | - | ☐ | |
| 3 | Wait for trigger time | ✅ Notification fires (OS handles) | ✅ Notification displayed | ☐ | |
| 4 | Check app state | App terminated | App not running | ☐ | |

**Platform Behavior**: OS-guaranteed (iOS UNUserNotificationCenter)

---

#### Test 3: Device Reboot

| Step | Action | Expected (OS) | Expected (Plugin) | Actual Result | Notes |
| ---- | ------ | ------------- | ------------------ | ------------- | ----- |
| 1 | Schedule notification for future time | - | Notification scheduled | ☐ | |
| 2 | Reboot device | - | - | ☐ | |
| 3 | Do NOT open app | ✅ Notification fires (OS persists) | ✅ Notification displayed | ☐ | |
| 4 | Check notification timing | ✅ On time (±180s tolerance) | ✅ On time | ☐ | |

**Platform Behavior**: OS-guaranteed (iOS persists calendar/time triggers)

**Note**: Only calendar and time-based triggers persist. Location triggers do not.

---

#### 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**: System-controlled (not guaranteed)

---

### 2.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)

---

### 2.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 | |

---

## 3. 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 |

---

## 4. Findings & Gaps

### 4.1 Android Gaps

| Gap | Severity | Description | Recommendation |
| --- | -------- | ----------- | -------------- |
| Boot recovery | ☐ High/Medium/Low | Does plugin reschedule on boot? | Implement if missing |
| Missed alarm detection | ☐ High/Medium/Low | Does plugin detect missed alarms? | Implement if missing |
| Force stop recovery | ☐ High/Medium/Low | Does plugin recover after force stop? | Implement if missing |
| Persistence completeness | ☐ High/Medium/Low | Are all required fields persisted? | Verify and add if missing |

### 4.2 iOS Gaps

| Gap | Severity | Description | Recommendation |
| --- | -------- | ----------- | -------------- |
| Missed notification detection | ☐ High/Medium/Low | Does plugin detect missed notifications? | Implement if missing |
| Plugin-side persistence | ☐ High/Medium/Low | Does plugin persist state separately? | Consider if needed |
| Background task reliability | ☐ High/Medium/Low | Can plugin rely on BGTaskScheduler? | Document limitations |

---

## 5. Deliverables from This Exploration

After completing this exploration, generate:

1. **ALARMS_BEHAVIOR_MATRIX.md** - Completed test results
2. **PLUGIN_ALARM_LIMITATIONS.md** - Documented limitations and gaps
3. **Annotated code pointers** - Code locations with findings
4. **Open Questions / TODOs** - Unresolved issues

---

## Related Documentation

- [Platform Capability Reference](../alarms/01-platform-capability-reference.md) - OS-level facts
- [Plugin Requirements & Implementation](./plugin-requirements-implementation.md) - Requirements based on findings
- [Improve Alarm Directives](./improve-alarm-directives.md) - Improvement directive

---

## 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

