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.
This commit is contained in:
Matthew Raymer
2025-12-30 09:17:18 +00:00
parent 63e5b4535e
commit ea4bc88808
2 changed files with 20 additions and 1 deletions

View File

@@ -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(

View File

@@ -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")
}
}
/**