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).
28 lines
2.6 KiB
Markdown
28 lines
2.6 KiB
Markdown
# 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:
|
||
|
||
1. Creates `pendingIntent` with `PendingIntent.getBroadcast(..., requestCode, intent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE)`.
|
||
2. Gets `existingPendingIntent` with `PendingIntent.getBroadcast(..., requestCode, intent, FLAG_NO_CREATE | FLAG_IMMUTABLE)` (same `requestCode`, same `intent`).
|
||
3. If not null: `alarmManager.cancel(existingPendingIntent)` and **`existingPendingIntent.cancel()`**.
|
||
4. 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 only **`alarmManager.cancel(existingPendingIntent)`** to clear any existing alarm for this requestCode. That way the PendingIntent we pass to `setAlarmClock` is 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 `setAlarmClock` use of `pendingIntent`.
|