Skip to content

fix(export): stream large JSON downloads to a cache file - #304

Merged
ErikBjare merged 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/export-stream-native
Sep 23, 2026
Merged

ErikBjare merged 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/export-stream-native

Conversation

@TimeToBuildBob

@TimeToBuildBob TimeToBuildBob commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Why

#229 saved small-bucket blob downloads, but "Export all" / a huge bucket still dies silently on 0.14.2b4. The web UI waits for a fully-buffered JSON body (30s axios timeout + JSON.parse in the WebView).

Fixes #228

Companion PRs:

Change

  • Intercept /export XHRs in the injected hook and call Android.exportFromUrl
  • Native fetch with the dashboard API key streams into a cache file (not a JS string)
  • Existing Save-to picker / toast path unchanged

CSV of a huge bucket still materializes events in JS.

Tests

./gradlew :mobile:testStandardDebugUnitTest --tests net.activitywatch.android.fragments.WebUIFragmentTest

Small-bucket saves from ActivityWatch#229 still buffer the payload as a JS string. For
~500k events that hits the 30s axios timeout and OOMs the WebView.

- Intercept /export XHRs and call Android.exportFromUrl
- Fetch with auth on a background thread into a cache file
- Open the existing Save-to picker from that file

CSV of a huge bucket still loads events in JS.

Fixes ActivityWatch#228

Git-Session-Id: a180614b-5a5a-5d29-84d8-e1c4e076b990
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Review guide (auto-posted)

Structured warm-up for reviewers — what changed, what to run, where to look.

Key files

  • mobile/src/main/java/net/activitywatch/android/fragments/WebUIFragment.kt (+96/-11, Δ107)
  • mobile/src/test/java/net/activitywatch/android/fragments/WebUIFragmentTest.kt (+34/-0, Δ34)

Suggested verification

  • Run the repo's usual CI-equivalent checks locally

Known risks / watch points

  • No automatic high-risk tags; use file list + diff for judgment.

Suggested review focus

  • Confirm behavior matches the PR description acceptance criteria.
  • Skim the largest diffs first (listed above).
  • If CI is green, spot-check the highest-risk paths called out here.

Generated by scripts/github/pr-warmup-review-guide.py for #304.

@greptile-apps

greptile-apps Bot commented Sep 23, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the two lifecycle defects from the previous review are fixed and no new actionable issue was found.

Findings

  1. P1 WebView Access From Bridge Thread
  2. P1 Completed Exports Can Disappear
  3. P2 Required Profiling Evidence Missing

Summary

This PR routes large JSON exports from the embedded dashboard through an authenticated native download that streams directly to a cache file before entering the existing Android save flow. The latest revision:

  • Marshals JavaScript bridge work onto the main looper before accessing the WebView.
  • Handles download completion independently of the Fragment view and deletes completed files that can no longer be queued.
  • Adds unit coverage for streaming, URL resolution, bridge forwarding, and orphaned-cache cleanup.

Diagram

sequenceDiagram
    participant W as Dashboard WebView
    participant B as Android bridge
    participant F as WebUIFragment
    participant S as Local ActivityWatch server
    participant C as Export cache
    participant P as Android save picker
    W->>B: exportFromUrl(url, filename)
    B->>F: Marshal callback to main looper
    F->>F: Resolve and validate loopback URL
    F->>S: Authenticated export request
    S-->>C: Stream response into cache file
    C-->>F: Pending export
    alt Fragment remains added
        F->>P: Queue and launch save picker
    else Fragment detached
        F->>C: Delete orphaned cache file
    end
Loading

Reviews (2) · Last reviewed commit: "fix(export): marshal JS-bridge export on..."

Comment thread mobile/src/main/java/net/activitywatch/android/fragments/WebUIFragment.kt Outdated
Comment thread mobile/src/main/java/net/activitywatch/android/fragments/WebUIFragment.kt Outdated
JavaScript-interface callbacks run on the WebView bridge thread, so
reading webView.url there can throw before the native download starts.
A detached view also drops view?.post, leaking the streamed cache file.

Post both the URL resolve and the fetch completion through the
main-looper Handler; enqueue if the fragment is still added, otherwise
delete the file.

Git-Session-Id: a434bdbc-0d89-5467-a891-085a8060b1c3
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@ErikBjare
ErikBjare merged commit 6484f5c into ActivityWatch:master Sep 23, 2026
8 checks passed
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Erik merged this at 2026-09-23T01:08:14Z as 6484f5c. CI was green (Test, Test E2E 29, Greptile 5/5). All review threads resolved. No further action on this PR.

Companion stack also landed: ActivityWatch/aw-server-rust#721, ActivityWatch/aw-webui#993. #228 stays open until Export-all JSON is confirmed on a ~500k-event device; CSV of a huge bucket is still JS-bound.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export button in bucket view silently fails: WebView fetches the export but never saves the file

2 participants