From c36781e4408d25bfc56443be9cd65039e4d2f173 Mon Sep 17 00:00:00 2001 From: Jose Olarte III Date: Mon, 2 Mar 2026 16:41:14 +0800 Subject: [PATCH] fix(android): cancel only fetch-related WorkManager jobs when scheduling daily notification Prevents a second notification (UUID alarm) with fallback or placeholder text by cancelling pending prefetch/fetch work when the user schedules or reschedules. cleanupExistingNotificationSchedules only cancels alarms for DB schedule IDs; alarms from DailyNotificationFetchWorker use a UUID and were never cancelled. Add ScheduleHelper.cancelFetchRelatedWorkManagerJobs() to cancel only the prefetch and daily_notification_fetch tags (not display, dismiss, or maintenance). Call it after cleanup and before scheduleDailyNotification. Future fetched-content flows can use distinct WorkManager tags and will not be affected by this path. --- .../DailyNotificationPlugin.kt | 31 ++++++++++++++++++- 1 file changed, 30 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 f3e6ad4..5523fcd 100644 --- a/android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt +++ b/android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt @@ -1137,6 +1137,14 @@ open class DailyNotificationPlugin : Plugin() { Log.i(TAG, "scheduleDailyNotification: No cleanup needed - existing schedule will be updated via upsert: $scheduleId") } + // Cancel only fetch-related WorkManager jobs so they cannot create a second (UUID) alarm + // with fallback or placeholder text. Does not cancel display/dismiss; future fetched-content + // flows should use distinct tags so they are not affected. + val workCancelled = ScheduleHelper.cancelFetchRelatedWorkManagerJobs(context) + if (workCancelled) { + Log.i(TAG, "scheduleDailyNotification: Cancelled pending prefetch/fetch WorkManager jobs") + } + val config = UserNotificationConfig( enabled = true, schedule = cronExpression, @@ -2846,9 +2854,30 @@ object ScheduleHelper { } } + /** + * Cancel only WorkManager jobs that can create a second (UUID) alarm for the static-reminder path: + * prefetch and daily_notification_fetch. Does not cancel display, dismiss, or maintenance. + * Use this when handling scheduleDailyNotification so pending prefetch does not run and create + * a duplicate alarm; future fetched-content flows should use distinct tags so they are not affected. + * + * @param context Application context + * @return true if cancellation was successful + */ + suspend fun cancelFetchRelatedWorkManagerJobs(context: Context): Boolean { + return try { + val workManager = WorkManager.getInstance(context) + workManager.cancelAllWorkByTag("prefetch") + workManager.cancelAllWorkByTag("daily_notification_fetch") + true + } catch (e: Exception) { + Log.w("ScheduleHelper", "Failed to cancel fetch-related WorkManager jobs", e) + false + } + } + /** * Cancel all WorkManager jobs by tags - * + * * @param context Application context * @return true if cancellation was successful */