Commit Graph

490 Commits

Author SHA1 Message Date
Matthew
367325452a fix(android): explicitly set component and package for AlarmManager broadcasts
AlarmManager was firing alarms but DailyNotificationReceiver was not
receiving broadcasts. The issue was that Intents created with
Intent(context, Class) constructor were not reliably matched by
AlarmManager when delivering broadcasts.

Solution: Explicitly set ComponentName and package on all Intents used
for AlarmManager broadcasts. This ensures AlarmManager can correctly
match PendingIntents to the registered receiver.

Changes:
- NotifyReceiver.kt: Fixed Intent creation in scheduleNotification(),
  cancelNotification(), isAlarmScheduled(), and idempotence checks
- ReactivationManager.kt: Fixed alarmsExist() to use
  DailyNotificationReceiver with explicit component/package
- DailyNotificationScheduler.java: Fixed Intent creation to explicitly
  set component and package

This fixes the critical bug where alarms fire but receivers are not
triggered, resolving the gap between AlarmManager delivery and receiver
execution.
2026-02-03 00:33:33 -08:00
Matthew
dd55c6b4e1 fix(ios): use wrapper script for pod install in cap:sync:ios
The cap:sync:ios npm script was failing with "pod: command not found"
because npm scripts don't inherit the same PATH environment as shell
scripts, preventing detection of pod installed via rbenv shims.

Added pod-install.sh wrapper script that:
- Detects pod via command -v or rbenv shims ($HOME/.rbenv/shims/pod)
- Executes pod install with the found command
- Matches the pod detection logic used in build-native.sh

Updated cap:sync:ios script to use the wrapper instead of calling
pod install directly, ensuring consistent pod detection across
all build contexts.
2026-01-15 23:05:45 -08:00
Jose Olarte III
2915fe7438 fix(build): add SQLite conflict detection and Command Line Tools verification
Prevents iOS build failures caused by pkgx SQLite linking conflicts and
ensures Xcode Command Line Tools are properly installed.

Problem:
- pkgx installs SQLite built for macOS, causing linker errors when building
  for iOS simulator: "linking in dylib built for 'macOS'"
- Missing Command Line Tools cause build failures without clear error messages

Changes:
- Add check_sqlite_conflicts() function
  - Detects pkgx SQLite installations in ~/.pkgx
  - Warns about macOS dylibs that will cause iOS simulator build failures
  - Checks for system SQLite from Command Line Tools
  - Validates library paths (DYLD_LIBRARY_PATH, LD_LIBRARY_PATH)

- Add check_command_line_tools() function
  - Verifies Xcode Command Line Tools are installed and configured
  - Checks for xcodebuild availability
  - Verifies sqlite3 is available (part of Command Line Tools)
  - Provides clear error messages with installation instructions

- Enhance pkgx detection in iOS build functions
  - Specifically searches for pkgx SQLite dylibs
  - Automatically removes pkgx paths from PATH environment variable
  - Provides detailed warnings about detected conflicts
  - Cleans all problematic environment variables before building

- Integrate checks into environment validation
  - Runs automatically when building for iOS
  - Provides early warnings before build starts
  - Fails fast with clear error messages if tools are missing

This fixes the linker error:
  "ld: building for 'iOS-simulator', but linking in dylib
   (/Users/trent/.pkgx/sqlite.org/v3.44.2/lib/libsqlite3.0.dylib)
   built for 'macOS'"

The build script now:
- Detects pkgx SQLite conflicts before building
- Automatically fixes environment variables
- Verifies Command Line Tools are installed
- Provides clear guidance for manual fixes if needed

Files modified:
- scripts/build-native.sh
2026-01-15 18:34:33 +08:00
Jose Olarte III
5247ebeecb fix(build): add Capacitor sync and auto-fix for Android test app builds
Fixed Android test app build failures by ensuring Capacitor is synced
before building and automatically fixing missing file references.

Changes:
- Add Capacitor Android sync step before building test app
  - Runs `npm run cap:sync:android` to create required project structure
  - Ensures `:capacitor-cordova-android-plugins` project exists before Gradle resolves dependencies
- Add automatic fix for missing cordova.variables.gradle reference
  - Detects when capacitor.build.gradle references non-existent file
  - Automatically comments out problematic `apply from` line
  - Uses platform-agnostic sed command (handles macOS and Linux)
  - Provides clear logging about what was fixed
- Reorganize build flow to match iOS pattern
  - Sync Capacitor first, then navigate to platform directory
  - Apply fixes, then build

This fixes the build error:
  "Could not resolve project :capacitor-cordova-android-plugins"
  "No matching variant of project :capacitor-cordova-android-plugins was found"

The build now completes successfully even when:
- Capacitor hasn't been synced yet
- capacitor.build.gradle references missing files

Files modified:
- scripts/build-native.sh
2026-01-15 15:51:08 +08:00
Jose Olarte III
20b33f6e31 fix(build): handle missing dependencies and Capacitor files during iOS build
Fixed build failures when test app dependencies aren't installed and when
Capacitor files don't exist during initial install.

Changes:
- Use `npx run-p` in test app build script to work without local install
- Add dependency check in build-native.sh before building Vue app
- Make fix-capacitor-plugins.js resilient to missing files during postinstall
  - Gracefully handles missing capacitor.plugins.json on first install
  - Provides clear messaging about when fixes will be applied
  - No longer exits with error when Capacitor hasn't been synced yet

This allows the build to complete successfully even when:
- npm dependencies aren't installed in test app
- Capacitor files don't exist yet (will be created during cap:sync:ios)

Files modified:
- scripts/build-native.sh
- test-apps/daily-notification-test/package.json
- test-apps/daily-notification-test/scripts/fix-capacitor-plugins.js
2026-01-15 15:37:32 +08:00
Jose Olarte III
630fd3de81 fix(ios): resolve SQLite linking conflicts with pkgx
Fixes iOS build failures caused by linker picking up macOS SQLite
libraries from pkgx instead of iOS system SQLite, resulting in
undefined symbol errors for all sqlite3 functions.

Changes:
- Explicitly link system SQLite library (-lsqlite3) in podspec
- Detect and unset pkgx environment variables during iOS builds
- Add warnings to guide users if manual intervention needed

The issue occurs when pkgx (or similar package managers) set
DYLD_LIBRARY_PATH or PKGX_DIR, causing the linker to find macOS
SQLite dylibs at /Users/*/.pkgx/sqlite.org/*/lib/libsqlite3.0.dylib
instead of the iOS system SQLite library.

This fix ensures the iOS build always uses the correct system SQLite
library regardless of environment variable interference.
2026-01-14 18:41:46 +08:00
Jose Olarte III
aaac23111c chore(build): add clean-build script for troubleshooting
Adds a comprehensive clean script that removes all build artifacts,
caches, and dependencies to help reproduce build issues across
different development environments.

The script cleans:
- TypeScript build output (dist/)
- iOS plugin artifacts (Pods, Podfile.lock, build dirs)
- Android plugin artifacts (build dirs, optional .gradle cache)
- Test app artifacts (node_modules, dist/, iOS/Android builds)
- Optional: Xcode DerivedData, Gradle cache, node_modules reinstall

Usage:
  ./scripts/clean-build.sh              # Basic clean
  ./scripts/clean-build.sh --all        # Full clean with reinstall

This is particularly useful when troubleshooting build failures
that may be environment-specific (different Xcode, CocoaPods,
macOS, or Node versions).
2026-01-12 20:50:02 +08:00
Jose Olarte III
d2a1041cc4 feat(ios): add missed rollover recovery for background/inactive app scenarios
Implement enhanced app launch recovery to detect and schedule missed rollover
notifications that occurred while the app was terminated, backgrounded, or
inactive.

Key improvements:
- Detect missed rollovers on app launch by checking for past notifications
  without next scheduled notification
- Add active rollover check when app becomes active (handles inactive app
  scenario where notifications fire silently)
- Calculate forward to future time when next scheduled time is in the past
  (handles delays > rollover interval)
- Enhance duplicate detection to exclude original notification from checks
- Retry rollover if previous attempt failed (rollover time set but no next
  notification exists)

Changes:
- DailyNotificationReactivationManager: Add detectAndProcessMissedRollovers()
  method and performActiveRolloverCheck() for app becoming active
- DailyNotificationReactivationManager: Enhance warm start scenario to check
  for missed rollovers
- DailyNotificationScheduler: Add forward calculation loop when next scheduled
  time is in the past
- DailyNotificationPlugin: Register observer for UIApplication.didBecomeActiveNotification
  to trigger rollover check when app becomes active

Fixes rollover scheduling for:
- App terminated: Rollover now detected and scheduled on next launch
- App inactive/backgrounded: Rollover detected when app becomes active
- Delayed recovery: Handles cases where app reopened after rollover interval
  has passed by calculating forward to next future time

All scenarios now properly schedule rollover notifications regardless of app
state when notification fires.
2026-01-09 20:02:40 +08:00
Jose Olarte III
243cbd08f1 docs(ios): add testing instructions for rollover interval
Add inline comments and documentation explaining how to temporarily
change rollover notification intervals from 24 hours to 2 minutes
for testing purposes. Comments specify exact line numbers and values
to change, making it easy to switch between production and testing
modes without losing context.

Changes:
- Add TESTING section to calculateNextScheduledTime() documentation
- Add inline TESTING comments at three change points:
  * Calendar date addition (24 hours → 2 minutes)
  * Fallback time calculation (24 hours → 2 minutes)
  * Duplicate prevention threshold (1 hour → 1 minute)

All code remains at production settings (24-hour intervals).
2026-01-08 21:25:37 +08:00
Jose Olarte III
7e93cbd771 fix(test-app): convert boolean pending to number in display
The pending field in NotificationStatus is a boolean, but the UI
was displaying it directly, causing "true" to appear instead of
a numeric count when notifications were scheduled.

Added a pendingCount computed property that converts boolean
values to numbers (true → 1, false → 0) while also handling
number types for future compatibility.
2026-01-08 19:00:55 +08:00
Jose Olarte III
6d64f71988 fix(ios): save rollover notification content to storage
Save notification content to storage immediately after scheduling
rollover notification so it can be retrieved when the notification
fires. Without this, processRollover fails to find the content
and cannot schedule the next notification.

The rollover flow creates a new notification with a new ID
(daily_rollover_*) but was only scheduling it with the system,
not saving it to storage. When the notification fired, the
lookup by ID failed because the content wasn't stored.

This matches the pattern used in DailyNotificationScheduleHelper
which saves content before scheduling.
2026-01-08 17:29:46 +08:00
Jose Olarte III
65379aedd6 refactor(test-app): extract reusable StatusList component
Created standardized StatusList component to eliminate duplicate status
display code across views. Standardized styling:
- Flexbox layout with space-between justification
- Border-bottom dividers (removed via :last-child)
- Optional status-based color coding via show-status-colors prop
- Consistent padding (12px 0) and spacing

Migrated HomeView and StatusView to use the new component:
- HomeView: Replaced inline status list, removed ~50 lines of duplicate CSS
- StatusView: Replaced diagnostics info items, removed ~25 lines of duplicate CSS
- Removed unused helper functions (getStatusType, getStatusDescription)
- Fixed TypeScript type assertions for status values
- Added diagnosticsItems computed property in StatusView

Reduces code duplication by ~75 lines and provides single source of truth
for status list styling across the application.
2026-01-07 21:20:49 +08:00
Jose Olarte III
66c7eca33d refactor(test-app): simplify System Status section layout
Replaced StatusCard components with simpler inline list layout:
- Removed card bounding boxes and side padding
- Added horizontal dividers between status items
- Title and value on same line using grid layout (left/right justified)
- Reduced padding and margins for more compact display
- Removed unused StatusCard import
2026-01-07 18:53:16 +08:00
Jose Olarte III
d88978259d fix(ios): correct userInfo scope error in notification delivery handler
Fixed compilation error where userInfo was referenced outside its scope
in handleNotificationDelivery error logging. Changed to use
notification.userInfo directly.
2026-01-07 18:52:45 +08:00
Jose Olarte III
66cbe763fc fix(ios): add diagnostic logging for rollover notification flow
Add comprehensive logging to trace rollover notification handling
from AppDelegate delivery through to next notification scheduling.
This enables diagnosis of why rollover notifications fail to
schedule the next 24-hour notification.

Changes:
- Log observer registration on plugin load
- Log handler entry and data extraction in handleNotificationDelivery
- Log processing steps in processRollover including:
  * Missing scheduler/storage detection
  * Content lookup failures with available IDs
  * ScheduleNextNotification success/failure

These logs will help identify whether the issue is:
- Observer not receiving notifications
- Content missing from storage
- Scheduling logic failing silently
2026-01-07 16:51:40 +08:00
Jose Olarte III
766d56c661 feat(test-app): default notification time to current + 3 minutes
Replace hardcoded '09:00' default with dynamic calculation that sets
the notification time to 3 minutes from now (rounded up to next minute).
This makes it more convenient for users to quickly test notifications
without manually adjusting the time field.
2026-01-06 19:27:05 +08:00
Jose Olarte III
f446362984 fix(ui): make notification countdown update reactively
The "Time Until" field in NotificationsView was not updating when
refresh was clicked or over time because the computed property used
Date.now() directly, which is evaluated once and doesn't trigger
reactive updates.

Changes:
- Add reactive currentTime property that updates every second
- Set up interval in mounted() to keep countdown live
- Clean up interval in beforeUnmount() to prevent memory leaks
- Update timeUntilNext computed to use reactive currentTime
- Update refreshNotifications() to immediately refresh currentTime

The countdown now updates automatically every second and immediately
when the refresh button is clicked, without requiring navigation away
and back to the view.
2026-01-06 17:38:59 +08:00
Jose Olarte III
20f15ebcea fix(ios): post notification delivery event to trigger rollover
The AppDelegate's willPresent method was not posting the
DailyNotificationDelivered notification event that the plugin
observes to trigger rollover scheduling. This caused rollover
notifications (scheduled 24 hours after the current notification)
to never be created, even though the rollover logic was fully
implemented in the plugin.

The fix extracts notification_id and scheduled_time from the
notification's userInfo and posts them via NotificationCenter using
the decoupled pattern. This allows the plugin to detect notification
delivery and automatically schedule the next day's notification.

Rollover now works correctly: when a notification is delivered,
the plugin schedules the next notification for 24 hours later,
and the NotificationsView properly displays the next notification
timestamp.
2026-01-06 17:19:18 +08:00
Jose Olarte III
b230a8e7b5 feat(test-app): add emoji icons to platform and status badges
Add platform-specific emojis (🤖 Android, 🍎 iOS, 🌐 Web) and status
indicators ( Ready, ⚠️ Not Ready,  Unknown) to improve visual
clarity in the home view welcome section.
2026-01-06 16:23:20 +08:00
Jose Olarte III
f97b3bec5b feat(test-apps/daily-notification-test): implement notification status display in NotificationsView
Replace placeholder content with functional notification status viewer that
displays scheduled notifications and rollover information. Enables verification
of both manually scheduled notifications and automatic rollover scheduling
(24-hour recurrence).

Features:
- Display next scheduled notification time with formatted date/time
- Show time until next notification (days, hours, minutes)
- Display pending notification count
- Show last notification delivery time
- Display rollover status (enabled/disabled, last rollover time) when available
- Additional status info (enabled, scheduled, errors)
- Manual refresh button for status updates
- Loading and error states with platform detection

Uses typed plugin wrapper for type safety with fallback to raw plugin access
for rollover fields not in TypeScript interface (iOS-specific fields).
2026-01-05 20:57:15 +08:00
Jose Olarte III
911aabf671 fix(test-app): use Capacitor for platform detection in views
Replace hardcoded platform values and appStore.platform with
Capacitor.getPlatform() for accurate runtime platform detection.

Changes:
- HomeView: Use Capacitor.getPlatform() instead of appStore.platform
- StatusView: Use Capacitor.getPlatform() for initial diagnostics
- diagnostics-export: Replace hardcoded 'Android' with Capacitor detection
- StatusView: Fix timezone to use actual timezone instead of 'Unknown'
- diagnostics-export: Show 'N/A' for API Level on iOS/web (Android-specific)

Fixes platform badge showing "web" on iOS native and diagnostics
showing incorrect platform information.
2026-01-05 20:38:55 +08:00
Jose Olarte III
5ae63e6f6d fix(test-app): constrain JSON diagnostics output width
The Raw Diagnostics pre element was overflowing its container and
causing the entire page to require horizontal scrolling, making field
values in the diagnostics info section inaccessible.

Added min-width: 0 and overflow: hidden to .diagnostics-json container
to allow proper grid constraint propagation. Added max-width: 100%,
width: 100%, and box-sizing: border-box to .json-output to ensure
it respects container bounds while maintaining horizontal scroll
within the pre element itself.
2026-01-05 20:21:48 +08:00
Jose Olarte III
edc4082f72 feat(ios): implement testAlarm method and fix plugin discovery
Add testAlarm() method to iOS plugin for quick notification testing.
Fix plugin method discovery by registering testAlarm in CAPBridgedPlugin
pluginMethods array. Add force-load code in AppDelegate to ensure plugin
is discovered by Capacitor's objc_getClassList scan.

Changes:
- Add testAlarm() implementation in DailyNotificationPlugin.swift
- Register testAlarm in pluginMethods array (required for Capacitor discovery)
- Add force-load code in test app AppDelegate (matches working ios-test-app)
- Add UNUserNotificationCenterDelegate to show notifications in foreground
- Add test notification button to ScheduleView with immediate feedback
- Add debug logging for method discovery and plugin loading

Fixes issue where testAlarm was implemented but returned "UNIMPLEMENTED"
because it wasn't registered in the pluginMethods array. Also ensures
plugin class is loaded before Capacitor's discovery phase.
2025-12-31 17:25:52 +08:00
Jose Olarte III
c8919480d9 fix(test-app): conditionally call getExactAlarmStatus on Android only
getExactAlarmStatus() is an Android-only API and was causing
UNIMPLEMENTED errors on iOS. Now only calls the method on Android
platforms, with safe defaults for iOS.

- Check platform before calling getExactAlarmStatus()
- Use default values { enabled: false, supported: false } on iOS
- Add error handling for Android call failures
- Make exact alarm status logging conditional on Android
2025-12-31 14:27:08 +08:00
Jose Olarte III
2d353c877c feat(test-app): add dedicated Request Permissions view
Create a new RequestPermissionsView that provides a dedicated interface
for checking and requesting notification permissions, matching the
functionality found in the iOS test app.

The view includes:
- Status display with color-coded states (requesting/granted/error)
- Permission status grid showing notifications, exact alarm, and
  background refresh status
- Request Permissions button with same functionality as iOS test app
- Platform-specific settings access buttons
- Automatic status refresh on mount

Updated HomeView to navigate to the new view instead of calling
permission request function directly, providing better UX with
dedicated screen for permission management.
2025-12-31 14:20:49 +08:00
Jose Olarte III
2f0d733b10 feat(test-app): add back navigation and improve mobile layout
- Add back buttons to all sub-views (Schedule, Status, Notifications, History, Logs, Settings, UserZero, About)
- Fix router navigation by importing router instance directly (resolves TypeScript errors with vue-facing-decorator)
- Update back button styling: flex layout with page title, arrow-only label
- Fix "Check Status" action to navigate to StatusView instead of checking status inline
- Remove horizontal padding on mobile views (max-width 768px) for edge-to-edge layout
- Simplify badge styling in HomeView (remove padding and border-radius)
2025-12-31 14:04:42 +08:00
Jose Olarte III
a7d33e2d37 feat(build): add iOS support to build-native.sh
Adds iOS platform support to the unified build script, enabling
building of test-apps/daily-notification-test for iOS alongside
existing Android support.

Changes:
- Add build_plugin_for_test_app_ios() to build iOS test app
- Add build_ios() function for iOS platform handling
- Make environment checks conditional based on target platform
- Add get_pod_command() helper to handle CocoaPods via rbenv
- Update main() to accept --platform ios and include iOS in "all"

This aligns the script with BUILDING.md documentation (lines 71, 75)
which implied iOS support was already available. The iOS build
process mirrors Android: creates plugin symlink, builds Vue app,
syncs Capacitor iOS (handles Podfile fixes), and builds with
xcodebuild for simulator.

Platform-specific environment checks allow iOS-only builds without
requiring Android toolchain, and vice versa.
2025-12-31 13:11:08 +08:00
Jose Olarte III
83ec604a4b fix(build): resolve Android build failures with Java 21 and Capacitor context
Fixed two build issues preventing Android plugin compilation:

1. Build script now builds from test app context instead of standalone
   - Capacitor Android is only available as a project dependency, not from Maven
   - Plugin must be built within a Capacitor app's Android project
   - Changed build_plugin_for_test_app() to build from test app's android/
     directory where Capacitor is available as :capacitor-android project

2. Added JVM arguments for Java 17+ KAPT compatibility
   - Java 21's module system blocks KAPT from accessing internal compiler classes
   - Added --add-opens flags to both org.gradle.jvmargs and kotlin.daemon.jvmargs
   - Kotlin compiler daemon runs separately and needs its own configuration
   - Applied to both plugin and test app gradle.properties files

These changes allow the plugin to build successfully with Java 21 and ensure
it's built in the correct context where Capacitor dependencies are available.
2025-12-31 12:53:02 +08:00
Jose Olarte III
8b116db095 refactor(test-app): reset default margins and padding in HTML
Add inline style resets to html, body, and #app elements to
eliminate browser default margins and padding. This ensures consistent layout
baseline across browsers and complements the centralized padding
management in App.vue.
2025-12-31 10:30:03 +08:00
Jose Olarte III
76c05e3690 refactor(test-app): centralize padding in root container
Remove individual padding declarations from view components and
set padding to 0 on App.vue root container. This consolidates
padding management in one place for easier maintenance and
consistent spacing control.
2025-12-31 10:17:22 +08:00
Jose Olarte III
f19ff4c127 Merge branch 'master' into ios-2 2025-12-31 09:56:16 +08:00
Jose Olarte III
9565191101 Fix iOS build errors and test app setup
- Fix async/await usage in background fetch handler
- Fix Core Data metadata access errors
- Replace SQLITE_TRANSIENT with nil for Swift compatibility
- Fix PermissionStatus interface and type casts in test app
- Add iOS setup documentation to BUILDING.md
- Update iOS sync workflow to handle Podfile regeneration

Resolves all iOS compilation errors and improves test app setup process.
2025-12-30 12:35:10 +08:00
Matthew Raymer
f83e799254 Merge branch 'ios-2' 2025-12-30 03:03:09 +00:00
Matthew Raymer
36e15633be feat: add comprehensive logging to test app UI refresh and polling
- Add detailed [UI Refresh] prefix logging to loadPluginStatus()
- Log plugin availability checks, status calls, and UI updates
- Add detailed [Poll] prefix logging to checkNotificationDelivery()
- Log status check results, notification delivery detection, and time comparisons
- Log rollover detection with old/new timestamp details
- Log periodic refresh triggers and initialization of tracking variables
- Include structured object logging for debugging UI refresh behavior

This enables debugging of UI auto-refresh mechanism and visibility
into JavaScript console logs in captured logcat output during test runs.
2025-12-30 02:56:56 +00:00
Matthew Raymer
dced4b49e1 feat: add comprehensive logging for UI refresh and capture JS console logs
- Add detailed logging to loadPluginStatus() with [UI Refresh] prefix
- Add detailed logging to checkNotificationDelivery() with [Poll] prefix
- Log status check results, change detection, and refresh triggers
- Log nextNotificationTime comparisons to debug rollover detection
- Include Capacitor/Console in logcat capture pattern to capture JS logs
- Log notification delivery detection and time calculations
- Log when rollover is detected and UI refresh is triggered

This enables debugging of UI auto-refresh mechanism and visibility
into JavaScript console logs in captured logcat output.
2025-12-29 10:22:36 +00:00
Matthew Raymer
a85f8b2f52 chore: ignore test run directories in gitignore 2025-12-29 09:37:16 +00:00
Matthew Raymer
f6df9e13fb feat: add operator console and wire test scripts with event emission
- Add TestEventsPlugin for receiving ADB broadcast intents
- Create operator console UI (console/index.html, console.css, console.js)
- Add test plan structure (plan.json) with phases, tests, and steps
- Wire all test scripts (phase1, phase2, phase3) with step context and events
- Add event emission helpers to alarm-test-lib.sh (step_start, step_pass, etc.)
- Update test-phase1.sh with comprehensive prerequisite verification
- Register TestEventsPlugin in capacitor.plugins.json
- Add console documentation (CONSOLE-USAGE.md, CONSOLE-REMAINING-WORK.md)
- Add test implementation alignment tracking (TEST-IMPLEMENTATION-ALIGNMENT.md)

This enables real-time test progress tracking via structured events
from shell scripts to the operator console UI.
2025-12-29 09:37:12 +00:00
Matthew Raymer
b53042d679 test: improve rollover detection and UI auto-refresh
- Normalize alarm time seconds to :00 for consistent comparison
- Compare dates (YYYY-MM-DD) instead of full timestamps to detect rollover
- Expand logcat search patterns to catch all rollover logs (DN|RESCHEDULE, etc.)
- Add 5-second wait after notification fire to allow rollover processing
- UI: Normalize seconds display to :00 in all time displays
- UI: Add auto-refresh mechanism that detects nextNotificationTime changes
- UI: Poll every 3 seconds and force refresh when rollover detected
- UI: Initialize tracking variable on page load for change detection

Fixes issue where test passed but alarm time didn't actually change,
and UI wasn't updating to show rescheduled notification time after rollover.
2025-12-29 09:36:19 +00:00
Matthew Raymer
78cd72529d fix(android): add UI-friendly permission status field names
The test app UI expects 'notificationsEnabled' and 'exactAlarmEnabled'
fields from checkPermissionStatus(), but the plugin only returned
technical field names ('postNotificationsGranted', 'exactAlarmGranted').

Added compatibility fields:
- notificationsEnabled = postNotificationsGranted && notificationsEnabledAtOsLevel
- exactAlarmEnabled = exactAlarmGranted

This ensures the UI can correctly display permission status after
granting permissions.
2025-12-25 09:58:29 +00:00
Matthew
95bf0f03c9 feat(ios): update test app for iOS-specific methods and update checklist
Update iOS test app to use iOS-specific methods and remove Android-specific
code for better platform parity:

iOS Test App Updates:
- Remove Android-specific UI elements:
  - Removed "Exact Alarms" status (Android-only feature)
  - Removed "Channel" status (Android notification channels)
- Add iOS-specific UI elements:
  - Added "Background Refresh" status (BGTaskScheduler registration)
  - Added "Pending" notifications count display
- Replace Android-specific methods:
  - Removed isChannelEnabled() calls
  - Added getBackgroundTaskStatus() for background task registration
  - Added getPendingNotifications() for pending notification count
  - Updated loadPermissionStatus() to use getNotificationPermissionStatus()
- Update error handling:
  - Removed EXACT_ALARM_PERMISSION_REQUIRED error code references
  - Added iOS-specific error handling for NOTIFICATION_PERMISSION_DENIED
- Update checkStatus() handling:
  - Removed Android-specific fields (channelEnabled, exactAlarmsGranted)
  - Added iOS-specific status information (pending notifications)
- Add iOS-specific action buttons:
  - "Open Settings" button (openNotificationSettings)
  - "Background Refresh" button (openBackgroundAppRefreshSettings)
- Add iOS-specific helper functions:
  - loadBackgroundRefreshStatus() - checks BGTaskScheduler registration
  - loadPendingNotificationsStatus() - displays pending notification count
  - openNotificationSettings() - opens iOS notification settings
  - openBackgroundRefreshSettings() - opens Background App Refresh settings

iOS Implementation Checklist Updates:
- Mark integration tests as complete (DailyNotificationRecoveryIntegrationTests)
- Mark data conversion helpers as complete (DailyNotificationDataConversions.swift)
- Mark termination detection tests as complete
- Mark boot detection tests as complete
- Mark partial failure scenario tests as complete
- Update document version to 1.1.0
- Update last updated date to 2025-12-24

Achieves iOS-Android parity by using platform-appropriate methods and APIs.
2025-12-25 00:53:22 -08:00
Matthew Raymer
ac39255672 test(android-test-app): unify presentation framework with evidence collection
Implement P0-P5 directives for operator clarity, consistent outcomes, and
easy evidence capture across all test phases.

Changes:
- alarm-test-lib.sh: Add evidence collection (capture_alarms, capture_logcat,
  capture_screenshot), verdict functions (verdict_pass/warn/fail), run directory
  management, and release gating support (RELEASE_GATE_PHASE3)

- test-phase1.sh: Refactor to unified framework with CLI modes (--setup,
  --run, --smoke, --all, --ci), micro-prompts, evidence capture, and verdict
  blocks for all 5 tests

- test-phase2.sh: Add evidence capture, verdict blocks, and STRICTNESS policy
  (soft/hard) for warn vs fail behavior

- test-phase3.sh: Add evidence capture, verdict blocks, release gating
  (--gate-phase3), and fatigue reduction (time estimates, automation hints)

- RUNBOOK-TESTING.md: New comprehensive operator guide (669 lines) covering
  prerequisites, all phases, evidence locations, verdict interpretation,
  common failures, and troubleshooting

All test scripts now use consistent UI helpers (section, substep, info, ok,
warn, error), standardized evidence collection, and clear verdict reporting.
Evidence is saved to timestamped run directories (runs/<RUN_ID>/) with alarms,
logs, and screenshots organized by test phase and scenario.

Tests pass with consistent presentation and reproducible evidence collection.
2025-12-24 12:01:16 +00:00
Matthew Raymer
973af9b688 fix(android): use optBoolean for persistToken to prevent JSONException
Fix configuration error 'No value for persistToken' by using optBoolean()
instead of getBoolean(). The getBoolean() method throws JSONException
when the key doesn't exist, while optBoolean() returns the default value
(false) safely.

This allows configureNativeFetcher() to work when persistToken is not
provided in the options, which is the expected default behavior (tokens
are not persisted by default for security).
2025-12-24 09:35:09 +00:00
Matthew Raymer
11b86f1f2e test(android): complete Section 3.4 Android smoke test
Execute Android smoke test from production readiness runbook.

Results:
-  App installed successfully on emulator
-  Plugin loaded (DNP-SCHEDULE logs present)
-  Notification scheduled (existing alarm detected from boot recovery)
-  No retry storm detected (no endless loops in logs)
-  Alarm exists in AlarmManager (verified via dumpsys)

Observations:
- App was already configured with a scheduled notification
- Boot recovery successfully restored alarm from database
- Duplicate schedule detection working (skipped duplicate on boot)
- Pending count verification requires UI interaction (not automated)

Status: 17 of 19 sections complete (89%)
2025-12-24 09:34:02 +00:00
Matthew Raymer
7060c20508 docs(progress): add test-app compatibility review after P2.1 refactoring
Verify all test-apps are compatible with P2.1 native plugin refactoring.

Findings:
- All test-apps are fully compatible 
- No breaking changes detected
- All methods used by test-apps remain available
- API signatures unchanged (internal refactoring only)

Test-apps verified:
- test-apps/android-test-app/ (7 methods used)
- test-apps/daily-notification-test/ (7 methods used)
- test-apps/ios-test-app/ (7 methods used)
- test-apps/ios-app-legacy/ (2 methods used)

Methods verified:
- configure() 
- configureNativeFetcher() 
- getNotificationStatus() 
- scheduleDailyNotification() 
- requestNotificationPermissions() 
- checkStatus() 
- checkPermissionStatus() 
- updateStarredPlans() 
- getExactAlarmStatus() 

Conclusion: No test-app updates required.
2025-12-24 09:20:24 +00:00
Matthew Raymer
154ffd1638 docs(progress): complete all automated and code analysis checks
Complete remaining automated checks from production readiness runbook.

Completed Sections (16 of 19):
- Section 5: Cross-platform behavior (code analysis)
  - 5.1: Pending definition verified (Android: storage, iOS: UNUserNotificationCenter)
  - 5.2: Date format verified (both use YYYY-MM-DD)
  - 5.3: TTL validation verified (iOS present, Android needs verification)
- Section 6: Logging consistency (code analysis)
  - 6.1: Required log patterns verified in code
  - 6.2: Failure logging verified in code
- Section 7.2: Release packaging
  - Clean archive created: daily-notification-plugin-release.tar.gz
  - No forbidden files verified
  - Source files included, build artifacts excluded

Status:
- Automated checks: 13 of 13 complete 
- Code analysis checks: 3 of 3 complete 
- Runtime testing: 3 sections pending (requires devices/emulators)

All checks that can be run without devices/emulators are now complete.
2025-12-24 09:06:33 +00:00
Matthew Raymer
96d4ee26b6 fix(android): resolve all Android build compilation errors
Complete fix for Section 3.1 production readiness build verification.

Kotlin Errors Fixed (10):
- Missing imports: Added AlarmManager, NotificationManagerCompat
- getExactAlarmStatus(): Fixed to use exactAlarmManager or fallback
- canRequestExactAlarmPermission(): Implemented inline logic
- requestExactAlarmPermission(): Fixed call sites (single parameter)
- JSObject.put ambiguity: Added explicit type casts
- enabledSchedules scope: Fixed variable scope in ReactivationManager

Java Errors Fixed (2):
- isAlarmScheduled(): Fixed Java call to Kotlin companion object
- getNextAlarmTime(): Fixed Java call to Kotlin companion object

Build Verification:
- Command: cd test-apps/android-test-app && ./gradlew assembleDebug
- Result: BUILD SUCCESSFUL 

All compilation errors resolved. Android build now passes production readiness check.
2025-12-24 08:48:06 +00:00
Matthew Raymer
481c8b0301 docs(progress): update Section 3.1 with complete fix details
Update execution log with all compilation errors fixed and verified.

Total errors fixed: 12
- Kotlin: 10 errors
- Java: 2 errors (Kotlin companion object calls)

Final status: BUILD SUCCESSFUL 
2025-12-24 08:37:53 +00:00
Matthew Raymer
25ba0ef0f0 fix(android): fix Java calls to Kotlin companion object methods
Fix Java compilation errors when calling Kotlin companion object methods.

Fixes:
- isAlarmScheduled(): Use NotifyReceiver.Companion with correct parameter types
- getNextAlarmTime(): Use NotifyReceiver.Companion with correct return type
- Kotlin Long? maps to java.lang.Long in Java (no conversion needed)

Errors Fixed:
- cannot find symbol: isAlarmScheduled(Context, String, Long)
- cannot find symbol: getNextAlarmTime(Context)

Verification:
- Java compilation: PASS
- Full assembleDebug build: BUILD SUCCESSFUL 
2025-12-24 08:37:40 +00:00
Matthew Raymer
012829456a docs(progress): update Section 3.1 status - Android build now passes
Section 3.1 Android build verification complete after fixing compilation errors.

Status:
- Initial: Failed (expected - Capacitor plugin standalone build constraint)
- Built from test-app: Found 10 compilation errors
- Fixed: All errors resolved (imports, method signatures, type casts, scope)
- Final: BUILD SUCCESSFUL 

All compilation errors have been fixed and verified.
2025-12-24 08:35:42 +00:00
Matthew Raymer
29fb30e4ec fix(android): resolve compilation errors in DailyNotificationPlugin
Fix all compilation errors identified in production readiness build check.

Fixes:
- Missing imports: Added AlarmManager and NotificationManagerCompat imports
- getExactAlarmStatus(): Fixed to use exactAlarmManager or fallback to PermissionManager
- canRequestExactAlarmPermission(): Implemented inline logic (method doesn't exist in PermissionManager)
- requestExactAlarmPermission(): Fixed call sites to use single-parameter signature
- JSObject.put ambiguity: Added explicit type casts for all put() calls
- enabledSchedules scope: Fixed variable scope issue in ReactivationManager.kt

Errors Fixed:
- Unresolved reference: AlarmManager (multiple locations)
- Unresolved reference: NotificationManagerCompat
- Unresolved reference: getExactAlarmStatus
- Unresolved reference: canRequestExactAlarmPermission
- Too many arguments for requestExactAlarmPermission
- Overload resolution ambiguity for JSObject.put
- Unresolved reference: enabledSchedules

Verification:
- Kotlin compilation: PASS
- Full assembleDebug build: PASS
- All compilation errors resolved
2025-12-24 08:35:26 +00:00