From ea4bc8880801501cbcf9495e6c6f97a67518c411 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Tue, 30 Dec 2025 09:17:18 +0000 Subject: [PATCH] fix: cancel existing alarm before scheduling new one for same scheduleId - Cancel existing alarm for scheduleId before scheduling new one in scheduleDailyNotification - Add verification logging to cancelNotification to confirm cancellation worked - Ensures 'one per day' semantics when updating schedule time Previously, when updating a schedule time: - cleanupExistingNotificationSchedules() only canceled OTHER schedules (excluded current scheduleId) - Old alarm for same scheduleId with different trigger time was not canceled - Result: 2 alarms existed (old + new) violating 'one per day' semantics The fix: - In ScheduleHelper.scheduleDailyNotification(), cancel existing alarm for scheduleId BEFORE scheduling new one - This ensures when updating schedule time, old alarm is canceled first - Enhanced logging with DNP-CANCEL tag to track cancellation and verify it worked Test 2 should now pass: updating schedule time will cancel old alarm before scheduling new one. --- .../dailynotification/DailyNotificationPlugin.kt | 6 ++++++ .../dailynotification/NotifyReceiver.kt | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt b/android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt index e10c447..22afec3 100644 --- a/android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt +++ b/android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt @@ -2635,6 +2635,12 @@ object ScheduleHelper { return try { val nextRunTime = calculateNextRunTime(config.schedule) + // CRITICAL: Cancel any existing alarm for this scheduleId BEFORE scheduling new one + // This ensures "one per day" semantics - when updating schedule time, old alarm is canceled + // The cleanupExistingNotificationSchedules() above only cancels OTHER schedules, not the current one + NotifyReceiver.cancelNotification(context, scheduleId) + Log.i("ScheduleHelper", "Cancelled existing alarm for scheduleId=$scheduleId before scheduling new one at $nextRunTime") + // Schedule AlarmManager notification as static reminder // (doesn't require cached content) NotifyReceiver.scheduleExactNotification( diff --git a/android/src/main/java/com/timesafari/dailynotification/NotifyReceiver.kt b/android/src/main/java/com/timesafari/dailynotification/NotifyReceiver.kt index 429bdbf..ecd53f0 100644 --- a/android/src/main/java/com/timesafari/dailynotification/NotifyReceiver.kt +++ b/android/src/main/java/com/timesafari/dailynotification/NotifyReceiver.kt @@ -481,7 +481,20 @@ class NotifyReceiver : BroadcastReceiver() { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) alarmManager.cancel(pendingIntent) - Log.i(TAG, "Notification alarm cancelled: scheduleId=$scheduleId, triggerAt=$triggerAtMillis, requestCode=$requestCode") + Log.i(TAG, "DNP-CANCEL: Notification alarm cancelled: scheduleId=$scheduleId, triggerAt=$triggerAtMillis, requestCode=$requestCode") + + // Verify cancellation by checking if alarm still exists + val verifyIntent = PendingIntent.getBroadcast( + context, + requestCode, + intent, + PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_IMMUTABLE + ) + if (verifyIntent == null) { + Log.d(TAG, "DNP-CANCEL: ✅ Cancellation verified - no PendingIntent found for requestCode=$requestCode") + } else { + Log.w(TAG, "DNP-CANCEL: ⚠️ Cancellation may have failed - PendingIntent still exists for requestCode=$requestCode") + } } /**