# 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](./platform-capability-reference.md) for OS-level facts. --- ## 0. Quick Reference: Platform Capabilities **Android**: See [Platform Capability Reference - Android Section](./platform-capability-reference.md#2-android-alarm-capability-matrix) **iOS**: See [Platform Capability Reference - iOS Section](./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 ` | - | - | ☐ | | | 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](./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