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).
2.6 KiB
Plugin: Android — Alarm set after edit doesn’t fire (cancel-before-reschedule)
Context: Consuming app (TimeSafari) — user sets reminder at 6:57pm (fires), then edits to 7:00pm. Only one scheduleDailyNotification call is made (skipSchedule fix). Logs show "Scheduling OS alarm" and "Updated schedule in database" for 19:00, but the notification never fires at 7:00pm.
Likely cause (plugin): In NotifyReceiver.kt, before calling setAlarmClock(pendingIntent) the code:
- Creates
pendingIntentwithPendingIntent.getBroadcast(..., requestCode, intent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE). - Gets
existingPendingIntentwithPendingIntent.getBroadcast(..., requestCode, intent, FLAG_NO_CREATE | FLAG_IMMUTABLE)(samerequestCode, sameintent). - If not null:
alarmManager.cancel(existingPendingIntent)andexistingPendingIntent.cancel(). - Then calls
alarmManager.setAlarmClock(alarmClockInfo, pendingIntent).
On Android, PendingIntent equality for caching is based on requestCode and Intent (action, component, etc.), not necessarily all extras. So existingPendingIntent is often the same (cached) PendingIntent as pendingIntent. Then we call existingPendingIntent.cancel(), which cancels that PendingIntent for future use. We then use the same (now cancelled) PendingIntent in setAlarmClock(..., pendingIntent). On some devices/versions, setting an alarm with a cancelled PendingIntent can result in the alarm not firing.
Suggested fix (plugin repo):
- Remove the
existingPendingIntent.cancel()call. Use onlyalarmManager.cancel(existingPendingIntent)to clear any existing alarm for this requestCode. That way the PendingIntent we pass tosetAlarmClockis not cancelled; only the previous alarm is removed. - Optionally: only run the “cancel existing” block when we know there was a previous schedule (e.g. from DB) for this scheduleId that hasn’t fired yet, so we don’t cancel when the previous alarm already fired (e.g. user edited after first fire).
Verification:
- In the consuming app: set reminder 2–3 min from now, let it fire, then edit to 2–3 min from then and save. Capture logcat through the second scheduled time.
- If the receiver never logs at the second time, the OS didn’t deliver the alarm; fixing the cancel-before-reschedule logic as above should be tried first in the plugin.
References:
- CONSUMING_APP_ANDROID_NOTES.md (double schedule, alarm scheduled but not firing).
- NotifyReceiver.kt around “Cancelling existing alarm before rescheduling” and the following
setAlarmClockuse ofpendingIntent.