diff --git a/app/src/main/java/de/jeanlucmakiola/clockula/domain/selfcheck/SelfCheck.kt b/app/src/main/java/de/jeanlucmakiola/clockula/domain/selfcheck/SelfCheck.kt index c6a208d..0450a24 100644 --- a/app/src/main/java/de/jeanlucmakiola/clockula/domain/selfcheck/SelfCheck.kt +++ b/app/src/main/java/de/jeanlucmakiola/clockula/domain/selfcheck/SelfCheck.kt @@ -186,21 +186,24 @@ object SelfCheck { /** * Compares Clockula's own computed next fire against what the system - * actually has registered. No alarm scheduled is not a problem; an - * unknown owner is given the benefit of the doubt (the platform does not - * always expose it), but a *confirmed* foreign owner, a missing system - * registration, or a mismatched time all mean the registration this app - * made is not the one the system will honour. + * actually has registered. The system reports only the earliest alarm + * clock of *any* app, so another app's alarm at or before Clockula's hides + * Clockula's registration rather than disproving it, and is not a problem. + * No alarm scheduled is not a problem either. A missing registration, our + * own at the wrong time, or anything later than our next fire all mean the + * registration this app made is not the one the system will honour. */ private fun nextAlarm(state: DeviceState): CheckResult { val expected = state.expectedNextFire + val system = state.systemNextAlarm val owner = state.systemNextAlarmOwnerPackage val ok = when { expected == null -> true - state.systemNextAlarm == null -> false - owner != null && owner != state.ownPackageName -> false - state.systemNextAlarm != expected -> false - else -> true + system == null -> false + system == expected -> true + system > expected -> false + // Earlier than ours: someone else's, unless the owner is confirmed as us. + else -> owner != state.ownPackageName } return CheckResult( SelfCheckId.NEXT_ALARM, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e50f974..e71127c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -371,7 +371,7 @@ Some manufacturers aggressively close background apps — see how to keep Clockula exempt Next alarm, as the system sees it - Matches what Clockula scheduled + Agrees with what Clockula scheduled Doesn\'t match what Clockula scheduled — open the app to re-check diff --git a/app/src/test/java/de/jeanlucmakiola/clockula/domain/selfcheck/SelfCheckTest.kt b/app/src/test/java/de/jeanlucmakiola/clockula/domain/selfcheck/SelfCheckTest.kt index 81b0739..310c8f1 100644 --- a/app/src/test/java/de/jeanlucmakiola/clockula/domain/selfcheck/SelfCheckTest.kt +++ b/app/src/test/java/de/jeanlucmakiola/clockula/domain/selfcheck/SelfCheckTest.kt @@ -189,7 +189,18 @@ class SelfCheckTest { } @Test - fun `the system's registration belonging to a different app is a problem`() { + fun `another app's alarm before Clockula's is fine, since it hides ours`() { + val state = allClear.copy( + expectedNextFire = Instant.fromEpochMilliseconds(2_000_000), + systemNextAlarm = Instant.fromEpochMilliseconds(1_000_000), + systemNextAlarmOwnerPackage = "com.other.clock", + ) + + assertThat(resultFor(state, SelfCheckId.NEXT_ALARM).status).isEqualTo(CheckStatus.OK) + } + + @Test + fun `another app's alarm at the same instant as Clockula's is fine`() { val at = Instant.fromEpochMilliseconds(1_000_000) val state = allClear.copy( expectedNextFire = at, @@ -197,6 +208,28 @@ class SelfCheckTest { systemNextAlarmOwnerPackage = "com.other.clock", ) + assertThat(resultFor(state, SelfCheckId.NEXT_ALARM).status).isEqualTo(CheckStatus.OK) + } + + @Test + fun `another app's alarm after Clockula's means ours is missing`() { + val state = allClear.copy( + expectedNextFire = Instant.fromEpochMilliseconds(1_000_000), + systemNextAlarm = Instant.fromEpochMilliseconds(2_000_000), + systemNextAlarmOwnerPackage = "com.other.clock", + ) + + assertThat(resultFor(state, SelfCheckId.NEXT_ALARM).status).isEqualTo(CheckStatus.PROBLEM) + } + + @Test + fun `our own registration earlier than expected is a problem`() { + val state = allClear.copy( + expectedNextFire = Instant.fromEpochMilliseconds(2_000_000), + systemNextAlarm = Instant.fromEpochMilliseconds(1_000_000), + systemNextAlarmOwnerPackage = OWN_PACKAGE, + ) + assertThat(resultFor(state, SelfCheckId.NEXT_ALARM).status).isEqualTo(CheckStatus.PROBLEM) }