fix(bedtime): keep the slot off the allow-while-idle ration
Android rations allow-while-idle wake-ups per app in doze, and the timer's expiry slot and the alarm's fallback share that ration, so a 07:00 wake-up fire could hold back a timer due at 07:04. The bedtime slot is now a plain exact alarm that doze may defer, which can move a mode boundary but never a ring. A restore of unchanged bedtime settings no longer forces the mode, and the screen skips its rule check while bedtime is off. Refs #1
This commit is contained in:
1 parent
8b182c999b
commit
1a5552a221
4 files changed
+31
-16
No files matched your search
@@ -99,7 +99,12 @@ class BackupEngine @Inject constructor(
|
||||
// with them), so the slot and the Do Not Disturb rule follow.
|
||||
// Its platform calls are guarded already; a failure here is
|
||||
// not a failed import. Nothing to follow if they never changed.
|
||||
if (settingsApplied) runCatching { bedtimeEngine.resync(refreshRule = true) }
|
||||
// Forced only when the bedtime settings really changed, so a
|
||||
// restore of the same schedule leaves a hand-switched mode be.
|
||||
if (settingsApplied) {
|
||||
val changed = previousSettings.bedtime != content.settings.bedtime
|
||||
runCatching { bedtimeEngine.resync(refreshRule = changed) }
|
||||
}
|
||||
}
|
||||
}
|
||||
failure?.let { throw it }
|
||||
|
||||
+13
-9
@@ -15,11 +15,17 @@ import javax.inject.Singleton
|
||||
/**
|
||||
* One wall-clock slot for the schedule's next event. Never `setAlarmClock`:
|
||||
* that slot is the status bar's "next alarm", and bedtime is not an alarm.
|
||||
* Exact while idle where the platform allows it, the same two branches the
|
||||
* timer's slot uses: a wake-up time that ends the mode an hour late, after a
|
||||
* doze maintenance window, is the failure this avoids. It is its own
|
||||
* PendingIntent (its own receiver, action and request code), so arming or
|
||||
* cancelling it can never touch an alarm's or a timer's registration.
|
||||
*
|
||||
* And never *allow-while-idle*. Android rations allow-while-idle wake-ups
|
||||
* per app while the device dozes (one per nine minutes on Android 10 and 11,
|
||||
* and for the inexact fallback without exact-alarm access), and the timer's
|
||||
* expiry slot and the alarm's fallback draw on the same ration. A 07:00
|
||||
* wake-up fire would hold back a timer due at 07:04 or a fallback alarm at
|
||||
* 07:05. So the slot is exact but doze-deferrable: in deep doze it waits for
|
||||
* the next maintenance window or for the next alarm clock to wake the device,
|
||||
* which only moves a mode boundary, never a ring. It is its own PendingIntent
|
||||
* (its own receiver, action and request code), so arming or cancelling it can
|
||||
* never touch an alarm's or a timer's registration.
|
||||
*/
|
||||
@Singleton
|
||||
class AndroidBedtimeScheduler @Inject constructor(
|
||||
@@ -31,12 +37,10 @@ class AndroidBedtimeScheduler @Inject constructor(
|
||||
override fun schedule(at: Instant) {
|
||||
val millis = at.toEpochMilliseconds()
|
||||
val pendingIntent = slotPendingIntent()
|
||||
val exact = runCatching {
|
||||
manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, millis, pendingIntent)
|
||||
}.isSuccess
|
||||
val exact = runCatching { manager.setExact(AlarmManager.RTC_WAKEUP, millis, pendingIntent) }.isSuccess
|
||||
// Guarded too: bedtime losing its slot is survivable, a crash in the
|
||||
// receiver's process is not.
|
||||
if (!exact) runCatching { manager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, millis, pendingIntent) }
|
||||
if (!exact) runCatching { manager.set(AlarmManager.RTC_WAKEUP, millis, pendingIntent) }
|
||||
}
|
||||
|
||||
override fun cancel() = manager.cancel(slotPendingIntent())
|
||||
|
||||
@@ -54,7 +54,8 @@ class BedtimeViewModel @Inject internal constructor(
|
||||
appScope.launch {
|
||||
// Also when access was granted while this screen was closed and
|
||||
// the system's broadcast did not reach the app: no rule yet.
|
||||
if (changed || (granted && engine.ruleId() == null)) {
|
||||
val enabled = (state.value as? BedtimeUiState.Loaded)?.settings?.enabled == true
|
||||
if (changed || (granted && enabled && engine.ruleId() == null)) {
|
||||
runCatching { engine.resync(refreshRule = true) }
|
||||
}
|
||||
ruleId.value = engine.ruleId()
|
||||
|
||||
Reference in new issue
Block a user