Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import net.activitywatch.android.EXTRA_OPEN_ACTIVITY_VIEW
import net.activitywatch.android.MainActivity
import net.activitywatch.android.R
import net.activitywatch.android.RustInterface
import net.activitywatch.android.watcher.SessionEventWatcher
import net.activitywatch.android.watcher.UsageStatsWatcher
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
Expand Down Expand Up @@ -168,14 +170,24 @@ internal interface NotifyBackend {
fun checkServer()
fun getSetting(key: String): String
fun androidQuery(timeperiod: String): String
fun ingestLatestUsage()
Comment thread
ErikBjare marked this conversation as resolved.
}

private class RustNotifyBackend(context: Context) : NotifyBackend {
private val appContext = context.applicationContext
private val ri = RustInterface(context)

override fun checkServer() { ri.getBucketsJSON() }
override fun getSetting(key: String): String = ri.getSetting(key)
override fun androidQuery(timeperiod: String): String = ri.androidQuery(timeperiod)

// Usage events otherwise reach the datastore only on the hourly (inexact) alarm, app
// open or widget refresh, so alerts were judged against data up to an hour old.
// processEventsSinceLastUpdate() skips if another ingestion run holds its lock.
override fun ingestLatestUsage() {
if (!UsageStatsWatcher.isUsageAllowed(appContext)) return
SessionEventWatcher(appContext).processEventsSinceLastUpdate()
}
}

class NotifyWorker internal constructor(
Expand Down Expand Up @@ -205,6 +217,12 @@ class NotifyWorker internal constructor(
// Keep the periodic worker scheduled so enabling later takes effect,
// but never query activity or create notifications when disabled.
if (alerts.isEmpty()) return Result.success()
try {
backend.ingestLatestUsage()
} catch (e: Exception) {
// Still check thresholds against what is already stored.
Log.w(TAG, "Failed to ingest usage events before checking thresholds", e)
}
val zone = ZoneId.systemDefault()
val startOfDayHour = parseStartOfDayHour(backend.getSetting("startOfDay"))
val now = LocalDateTime.now(zone)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import org.robolectric.annotation.Config
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [28], application = Application::class)
class NotifyWorkerExecutionTest {
private class FakeBackend(private val setting: String) : NotifyBackend {
private class FakeBackend(
private val setting: String,
private val failIngest: Boolean = false,
) : NotifyBackend {
val calls = mutableListOf<String>()

override fun checkServer() {
Expand All @@ -35,6 +38,11 @@ class NotifyWorkerExecutionTest {
calls += "query"
return """[{"cat_events":[{"duration":120,"data":{"${'$'}category":["Work"]}}]}]"""
}

override fun ingestLatestUsage() {
calls += "ingest"
if (failIngest) throw IllegalStateException("ingest failed")
}
}

private fun runWorker(backend: FakeBackend): ListenableWorker.Result {
Expand Down Expand Up @@ -92,7 +100,18 @@ class NotifyWorkerExecutionTest {
"""{"enabled":true,"alerts":[{"category":"Work","thresholds_minutes":[1]}]}"""
)
assertEquals(ListenableWorker.Result.success(), runWorker(backend))
assertEquals(listOf("server", "aw-notify", "startOfDay", "query"), backend.calls)
assertEquals(listOf("server", "aw-notify", "ingest", "startOfDay", "query"), backend.calls)
assertEquals(1, notificationCount())
}

@Test
fun ingestFailureStillChecksStoredData() {
val backend = FakeBackend(
"""{"enabled":true,"alerts":[{"category":"Work","thresholds_minutes":[1]}]}""",
failIngest = true,
)
assertEquals(ListenableWorker.Result.success(), runWorker(backend))
assertEquals(listOf("server", "aw-notify", "ingest", "startOfDay", "query"), backend.calls)
assertEquals(1, notificationCount())
}
}
Loading