fix(bedtime): bounded fallback window, fresh-screen access check
Without exact-alarm access the slot falls back to a ten-minute window instead of plain set(), whose slack could end an eight-hour night hours late. A freshly opened bedtime screen reads whether bedtime is on from the store, not from its still-loading state, so access granted while the screen was closed creates the rule. A restore that rolled back no longer forces the mode. Refs #1
This commit is contained in:
1 parent
1a5552a221
commit
131a28c1be
4 files changed
+18
-4
No files matched your search
@@ -102,7 +102,8 @@ class BackupEngine @Inject constructor(
|
||||
// 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
|
||||
// After a rollback the stored settings are the previous ones.
|
||||
val changed = rowsReplaced && previousSettings.bedtime != content.settings.bedtime
|
||||
runCatching { bedtimeEngine.resync(refreshRule = changed) }
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -40,11 +40,20 @@ class AndroidBedtimeScheduler @Inject constructor(
|
||||
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.set(AlarmManager.RTC_WAKEUP, millis, pendingIntent) }
|
||||
// A bounded window rather than `set`, whose slack grows with the
|
||||
// distance to the trigger and could end an 8-hour night hours late.
|
||||
if (!exact) {
|
||||
runCatching { manager.setWindow(AlarmManager.RTC_WAKEUP, millis, FALLBACK_WINDOW_MILLIS, pendingIntent) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() = manager.cancel(slotPendingIntent())
|
||||
|
||||
private companion object {
|
||||
/** The platform's own minimum window from Android 12 on. */
|
||||
const val FALLBACK_WINDOW_MILLIS = 10 * 60_000L
|
||||
}
|
||||
|
||||
private fun slotPendingIntent(): PendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
BedtimeIntents.REQUEST_SLOT,
|
||||
|
||||
@@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.DayOfWeek
|
||||
@@ -54,7 +55,9 @@ 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.
|
||||
val enabled = (state.value as? BedtimeUiState.Loaded)?.settings?.enabled == true
|
||||
// Read from the store, not from [state]: on a fresh screen that
|
||||
// is still Loading at the first resume.
|
||||
val enabled = engine.bedtime.first().enabled
|
||||
if (changed || (granted && enabled && engine.ruleId() == null)) {
|
||||
runCatching { engine.resync(refreshRule = true) }
|
||||
}
|
||||
|
||||
@@ -2759,7 +2759,8 @@ engines (`ArchitectureRulesTest` holds it to no `android.*` import):
|
||||
- `BedtimeScheduler`, **one** AlarmManager slot of its own. Its PendingIntent
|
||||
targets `BedtimeReceiver` with its own action and request code, so arming or
|
||||
cancelling it cannot replace or cancel an alarm's or a timer's registration.
|
||||
It is `RTC_WAKEUP` and `setExact` (plain `set` without exact-alarm access),
|
||||
It is `RTC_WAKEUP` and `setExact` (a ten-minute `setWindow` without
|
||||
exact-alarm access, since plain `set`'s slack grows with the distance),
|
||||
and deliberately **not** allow-while-idle: Android rations allow-while-idle
|
||||
wake-ups per app in doze (one per nine minutes on Android 10 and 11, and for
|
||||
the inexact fallback without exact-alarm access), and the timer's expiry slot
|
||||
|
||||
Reference in new issue
Block a user