Skip to content

Fix prediction reminder re-arming, daily reminder reliability, and alarm scheduling bugs#167

Merged
mapgie merged 1 commit into
mainfrom
claude/alarms-reminders-analysis-w9qkm8
Jul 7, 2026
Merged

Fix prediction reminder re-arming, daily reminder reliability, and alarm scheduling bugs#167
mapgie merged 1 commit into
mainfrom
claude/alarms-reminders-analysis-w9qkm8

Conversation

@mapgie

@mapgie mapgie commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Part of a cross-app review of how the four apps use AlarmManager for alarms and reminders. This PR fixes the GoFlo findings, the largest set of the four.

Bugs fixed

  • Prediction reminders never re-armed. Pre-period, ovulation, and daily reminders are one-shot alarms that were only armed at boot and from the reminder settings screen. After a reminder fired, or after the user logged a period (which moves every predicted date), nothing re-armed them, so the feature quietly degraded to "works until the first firing". A shared ReminderScheduler.refreshPredictionReminders() is now called from ReminderReceiver after each prediction firing and from every period mutation (log, edit, delete, undo, merge).
  • The daily during-period reminder used setRepeating, which is inexact and Doze-deferred since KitKat, so it could arrive hours late or not at all. It is now an exact one-shot that re-arms itself via the receiver while a period is active, and ends naturally when the period ends.
  • Pre-Android-12 devices always got inexact alarms. The gating condition SDK >= S && canScheduleExactAlarms() sent every pre-12 device down the inexact branch, even though exact alarms need no permission there. Centralised into canUseExactAlarms()/setAlarm() and applied to custom alarms, prediction reminders, and snooze.
  • Deleting or disabling a custom alarm left its snoozed firing armed. The snooze PendingIntent (request code 40000+id) was never cancelled, and the receiver did not check isEnabled at fire time. Snooze identity now lives in ReminderScheduler.customAlarmSnoozePendingIntent, cancelCustomAlarm cancels it, and the receiver checks isEnabled.
  • A repository exception could break a recurring alarm chain. Recurring custom alarms are now re-armed before condition evaluation and notification display.
  • DST drift. Next-trigger times were computed by adding 86,400,000 ms, which lands an hour off across DST transitions; they are now resolved per local calendar day.
  • Boot-only rescheduling. BootReceiver now also handles MY_PACKAGE_REPLACED, TIMEZONE_CHANGED, and TIME_SET (all exempt from implicit-broadcast restrictions, no new permission), since every alarm is armed at an absolute epoch computed from local times.

Known issue left out (needs a permissions discussion)

ALARM-type custom alarms call setFullScreenIntent, but the manifest does not declare USE_FULL_SCREEN_INTENT. On Android 14+ targets the full-screen alarm UI is silently downgraded to a heads-up notification. Adding the permission is a one-line change, but Play policy restricts full-screen intent for non-alarm-category apps and CLAUDE.md requires discussion before adding permissions, so it is flagged here rather than changed.

Changelog fragment: changelog/unreleased/alarm-reliability.json (patch). LESSONS.md gains an entry on re-arming data-dependent one-shot alarms. a11y_check.py passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Qs1UZLKHTxtaLpTheoUwTg


Generated by Claude Code

…arm scheduling bugs

- Pre-period, ovulation, and daily reminders re-arm after each firing
  (ReminderReceiver) and after any period mutation (log/edit/delete/undo/
  merge) via a shared ReminderScheduler.refreshPredictionReminders();
  previously they were only armed at boot or from the settings screen
- Replace the setRepeating daily during-period reminder with an exact
  one-shot that re-arms itself; setRepeating is inexact and Doze-deferred
- Fix exact-alarm gating that downgraded all pre-Android-12 devices to
  inexact delivery (exact alarms need no permission below API 31)
- Custom alarm snooze now uses a shared PendingIntent identity that
  cancelCustomAlarm also cancels, so deleting or disabling an alarm kills
  its pending snoozed firing; the receiver also checks isEnabled at fire
- Re-arm recurring custom alarms before condition evaluation so an
  exception cannot break the chain
- Compute next trigger times per local calendar day instead of adding
  24h of millis, which drifted an hour across DST transitions
- BootReceiver also handles MY_PACKAGE_REPLACED, TIMEZONE_CHANGED, and
  TIME_SET

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qs1UZLKHTxtaLpTheoUwTg
@mapgie mapgie marked this pull request as ready for review July 7, 2026 06:02
@mapgie mapgie merged commit 602c270 into main Jul 7, 2026
4 checks passed
@mapgie mapgie deleted the claude/alarms-reminders-analysis-w9qkm8 branch July 7, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants