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)
}