summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/work
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-08-22 22:42:15 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-08-22 22:42:15 +0000
commitbc891a67802c837d77726f618e68c2ac84ea22d7 (patch)
tree15a4810f8f7ed698b91334e554c949179038e3ee /app/src/main/java/org/terst/feedreader/work
parentef1cec60c91c2481ebad52d2d39da536606a1631 (diff)
Restore the 5am morning-fetch alarm
Reverts part of the previous commit: the explicit refresh button and fetch-on-launch stay, but the user still wants the background 5am alarm so articles are fresh before the app is opened, not just the periodic hourly WorkManager job.
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/work')
-rw-r--r--app/src/main/java/org/terst/feedreader/work/MorningFetchReceiver.kt78
1 files changed, 78 insertions, 0 deletions
diff --git a/app/src/main/java/org/terst/feedreader/work/MorningFetchReceiver.kt b/app/src/main/java/org/terst/feedreader/work/MorningFetchReceiver.kt
new file mode 100644
index 0000000..c897046
--- /dev/null
+++ b/app/src/main/java/org/terst/feedreader/work/MorningFetchReceiver.kt
@@ -0,0 +1,78 @@
+package org.terst.feedreader.work
+
+import android.app.AlarmManager
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.util.Log
+import java.util.Calendar
+
+private const val TAG = "MorningFetch"
+
+/**
+ * Wakes the device at a fixed time every morning to run a feed fetch, so the app has
+ * fresh articles ready before the user ever opens it. Uses an exact alarm
+ * (setExactAndAllowWhileIdle) specifically so this one wake survives Doze without
+ * requesting the much broader "ignore battery optimizations" exemption -- the user wants
+ * battery optimization left on otherwise, just this one daily wake-up.
+ */
+class MorningFetchReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ try {
+ // A reboot only needs the alarm re-armed (AlarmManager alarms don't survive a
+ // restart) -- an actual fetch isn't due just because the phone restarted.
+ if (intent.action != Intent.ACTION_BOOT_COMPLETED) {
+ FeedFetchWorker.fetchNow(context)
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "Failed to enqueue morning fetch for action=${intent.action}", e)
+ }
+ scheduleNext(context)
+ }
+
+ companion object {
+ private const val HOUR = 5
+ private const val MINUTE = 0
+ private const val ACTION_MORNING_FETCH = "org.terst.feedreader.MORNING_FETCH"
+
+ private fun nextTriggerMillis(): Long {
+ val now = Calendar.getInstance()
+ val next = Calendar.getInstance().apply {
+ set(Calendar.HOUR_OF_DAY, HOUR)
+ set(Calendar.MINUTE, MINUTE)
+ set(Calendar.SECOND, 0)
+ set(Calendar.MILLISECOND, 0)
+ }
+ if (next.timeInMillis <= now.timeInMillis) {
+ next.add(Calendar.DAY_OF_MONTH, 1)
+ }
+ return next.timeInMillis
+ }
+
+ /** No-ops quietly if the exact-alarm permission isn't granted yet (Android 12+) --
+ * MainActivity is what prompts for that; this just skips scheduling until it's there.
+ * Also survives any failure from AlarmManager itself (logged, not crashed): this runs
+ * unconditionally from MainActivity.onCreate/onResume on every single launch, so an
+ * unguarded exception here would crash the app on every open -- a background wake-up
+ * alarm failing to schedule isn't worth that; just log it and let the next app open
+ * try again. */
+ fun scheduleNext(context: Context) {
+ try {
+ val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager ?: return
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) {
+ return
+ }
+ val intent = Intent(context, MorningFetchReceiver::class.java).setAction(ACTION_MORNING_FETCH)
+ val pendingIntent = PendingIntent.getBroadcast(
+ context, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextTriggerMillis(), pendingIntent)
+ } catch (e: Exception) {
+ Log.e(TAG, "Failed to schedule morning fetch alarm", e)
+ }
+ }
+ }
+}