Add doc/plugin-feedback-android-6-api23-zoneid-fix.md for the
daily-notification-plugin repo: replace java.time.ZoneId with
TimeZone.getDefault().id so the plugin runs on API 23 without
affecting behavior on API 26+.
- Fix typo in Android Chrome "Clear browsing data" step
- Use TimeSafari in Settings steps and clarify PWA vs native install
- Add Battery & background subsection (iOS and Android)
- Add Focus / Do Not Disturb note under Check App Permissions
- Add quick checklist at top before Full Test
- Replace hardcoded app names with AppString.APP_NAME and APP_NAME_NO_SPACES
Document that boot recovery can skip rescheduling after device restart
(duplicate PendingIntent check), causing the next daily notification to
fail to fire on devices that clear AlarmManager alarms on reboot. Include
Scenario 1 logcat (notification fired when alarm survived), two-scenario
distinction, recommended fix (skipPendingIntentIdempotence in boot path),
duplicate-alarm clarification, and Cursor-ready implementation section
for the daily-notification-plugin repo.
Document bug where daily reminder shows fallback text after device restart
(Intent extras not surviving reboot). Includes root cause, recommended
plugin fixes (persist/restore title/body, use DB in recovery), and
verification steps for the daily-notification-plugin repo.
Add docs/plugin-feedback-android-duplicate-reminder-notification.md
describing the duplicate notification on first-time reminder setup (one
correct + one fallback). Root cause: ScheduleHelper schedules the
static reminder alarm and also enqueues the prefetch worker, which
on fallback schedules a second alarm via DailyNotificationScheduler.
Suggested fix: for static-reminder schedules, do not enqueue prefetch
(or have prefetch skip scheduleNotificationIfNeeded). The suggested
plugin changes were applied and fixed the issue.
Exclude electron/src/rt/electron-plugins.js from clean in build-electron.sh
so the hand-maintained plugin list is not deleted. Update Podfile.lock
(TimesafariDailyNotificationPlugin 1.1.0 → 1.1.6) and electron
package-lock.json.
- Toast/notify: Keep dialog open until schedule flow finishes so success/error
$notify runs while component is mounted (fixes missing toast on Android).
Add success/error notify in edit-reminder callback (AccountViewView).
- Boot recovery: Split BootReceiver intent-filter so BOOT_COMPLETED and
LOCKED_BOOT_COMPLETED use a filter without <data>; use a separate filter
with <data scheme="package"/> for MY_PACKAGE_REPLACED/PACKAGE_REPLACED.
Boot broadcasts have no Uri and were not matching the previous filter,
so daily reminder now reschedules after device restart.
Resolves long-standing issue where the second scheduled time (after editing
the reminder) did not fire on Android.
- PushNotificationPermission: add open(..., options?: { skipSchedule }).
When skipSchedule is true (edit flow), dialog only invokes callback with
time/message; parent is sole scheduler so the plugin is not called twice.
- AccountViewView: pass { skipSchedule: true } when opening the dialog for
edit; keep cancel (iOS only) + single scheduleDailyNotification in callback.
- NativeNotificationService: serialize scheduleDailyNotification so only one
schedule runs at a time (scheduleLock + doScheduleDailyNotification).
- AccountViewView: guard edit-reminder callback with editReminderScheduleInProgress
so one schedule per user action.
- Gate pre-cancel on Android in edit flow (CONSUMING_APP brief): skip
cancelDailyNotification before schedule on Android; plugin cancels internally.
- Use single stable reminder id and always pass id on both platforms (plugin 1.1.2+).
- Add doc/plugin-android-edit-reschedule-alarm-not-firing.md for plugin repo
(cancel-before-reschedule may cancel the PendingIntent used for setAlarmClock).
- NativeNotificationService: use single stable reminder id on iOS and Android,
always pass id in scheduleOptions (plugin v1.1.2+ optional cleanup).
- Add doc/plugin-fix-scheduleExactNotification-calls.md for plugin repo
(fix Java call sites for scheduleExactNotification 8th parameter).
- package-lock.json: update lockfile.
Android second-schedule issue still present; to be revisited.
- NativeNotificationService: platform-specific schedule/cancel
- iOS: pass id "daily_timesafari_reminder", call cancelDailyReminder before schedule
- Android: no id (plugin uses "daily_notification"), skip pre-cancel to match test app
- Verification: return true when schedule succeeds but reminder not found (avoids error dialog)
- doc: android-daily-notification-second-schedule-issue.md
- Symptom, timing (re-schedule-too-soon), test app vs TimeSafari
- Plugin-side section: entry point, files, likely cause, suggested fixes, repro steps
- For use in plugin repo (e.g. Cursor) to fix second-schedule
Re-scheduled notifications on Android still fail to fire; fix expected in plugin (see doc).
Add native Android components for daily notification plugin integration:
- TimeSafariApplication: Custom Application class to register native fetcher
- TimeSafariNativeFetcher: Implements NativeNotificationContentFetcher interface
- network_security_config.xml: Allow cleartext for local development
Configuration updates:
- AndroidManifest.xml: Link custom Application class, add required permissions
- build.gradle: Add Java 17 compile options and required dependencies
- capacitor.config.ts: Add DailyNotification plugin configuration
- NativeNotificationService.ts: Use "daily_" prefixed ID for schedule rollover
Note: Subsequent notification scheduling after first fire still has issues
that require further investigation.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add comprehensive guide for building and testing TimeSafari on physical
Android devices, covering device setup, USB debugging, network
configuration for local development servers, and troubleshooting.
- Create doc/android-physical-device-guide.md with full instructions
- Update BUILDING.md to reference the new guide in two places
- Add "Android Emulator Without Android Studio" section under Android Build
- Document env setup, SDK components, and API 36 system images
- Include Mac Silicon (arm64-v8a) and Intel (x86_64) AVD instructions
- Add steps: start emulator, build, install APK, and launch app
- Document one-shot build-and-run (debug:run, test:run)
- Update Prerequisites to mention command-line-only option and link to section
- Link to doc/android-emulator-deployment-guide.md for troubleshooting
--sync was calling npx cap sync ios directly, so pod install failed
on Xcode 26 (objectVersion 70). Define run_cap_sync_with_workaround
once before sync-only and use it for both --sync and the full build;
remove the duplicate definition at Step 6.6.
Plugin fix is in @timesafari/daily-notification-plugin (explicit
PendingIntent component + id in Intent). Document resolution date,
summary of the fix, and follow-up steps (npm install, cap sync,
restore-local-plugins, test on device).
After changing DailyNotificationReceiver to exported="true", testing revealed
that while the receiver works when manually triggered, AlarmManager broadcasts
are not reaching it when alarms fire automatically. Alarms are scheduled and
fire correctly, but the PendingIntent broadcast does not trigger the receiver.
Added comprehensive documentation and diagnostic tools:
1. Documentation (doc/daily-notification-plugin-android-receiver-issue.md):
- Complete problem analysis with evidence from logs and dumpsys
- Root cause hypotheses focusing on PendingIntent creation in plugin
- Testing steps and expected behavior after fix
- Technical details for plugin maintainer reference
2. Test scripts:
- scripts/test-notification-receiver.sh: Manually trigger receiver to
verify it works and test with/without ID parameter
- scripts/check-alarm-logs.sh: Check logs and verify alarm scheduling
Findings:
- Receiver registration is correct (exported="true" works for manual tests)
- Alarms schedule and fire successfully (confirmed via dumpsys alarm)
- Issue is in plugin's PendingIntent creation - broadcasts don't reach receiver
- Additional issue: Intent extras missing scheduleId (causes "missing_id" error)
The exported="true" change was necessary and correct. The remaining issue
requires a fix in the plugin's PendingIntent creation code to explicitly
set the component and include the scheduleId in Intent extras.
This documentation is intended for use when working on the plugin project
to fix the PendingIntent delivery issue.
The DailyNotificationReceiver was not being triggered when scheduled alarms
fired, preventing notifications from appearing at the scheduled time.
Changed android:exported from "false" to "true" to allow AlarmManager
broadcasts to reach the receiver, especially when the app is closed or
the device is in doze mode.
This is a work-in-progress change to diagnose why notifications aren't
firing. The receiver should log "DN|RECEIVE_START" when triggered, but
we were not seeing these logs even when alarms were scheduled.
Next steps:
- Test if receiver is now triggered when alarm fires
- Verify notifications appear at scheduled time
- Consider adding permission check if keeping exported=true for security
- Auto-detect Java from Android Studio (JBR/JRE) or system PATH
- Auto-detect Android SDK from common locations or local.properties
- Auto-write SDK location to local.properties for Gradle
- Add KAPT JVM args to gradle.properties for Java 17+ module access
- Fix Java version command quoting for paths with spaces
- Comment out DailyNotificationPlugin (Java class not implemented)
Eliminates manual JAVA_HOME/ANDROID_HOME setup requirements and fixes
KAPT compilation errors when using Java 17+.
Author: Matthew Raymer
PushNotificationPermission:
- Swap hour/minute number inputs and AM/PM toggle for native <input type="time">
- Add timeValue computed to keep existing hour/minute/AM-PM state in sync
- Remove unused checkHourInput and checkMinuteInput
- Tighten copy and layout: headings, labels, char count, button spacing
AccountViewView:
- Show reminder time and message in a bordered box with Time/Message labels
- Adjust spacing in notifications section
- iOS: set UNUserNotificationCenter delegate and implement willPresent
so notifications show in foreground and DailyNotificationDelivered is
posted for rollover; implement didReceive for tap handling; re-set
delegate in applicationDidBecomeActive
- Android: move DailyNotificationReceiver and BootReceiver inside
<application>; add NotifyReceiver; extend BootReceiver with
LOCKED_BOOT_COMPLETED, MY_PACKAGE_REPLACED, directBootAware
- main.capacitor: import daily-notification-plugin at startup so
plugin (and recovery) load on launch
- doc: add daily-notification-alignment-outline.md
Fixes foreground notifications not showing and rollover recovery;
Android receivers were previously declared outside <application>.
Add com.timesafari.dailynotification.fetch and com.timesafari.dailynotification.notify
to BGTaskSchedulerPermittedIdentifiers in Info.plist to resolve registration
rejection errors. The plugin was attempting to register these identifiers but
they were not declared in the app's Info.plist, causing iOS to reject the
background task registrations.
Fixes Xcode log errors:
- Registration rejected; com.timesafari.dailynotification.fetch is not advertised
- Registration rejected; com.timesafari.dailynotification.notify is not advertised