Skip to content

fix(android): use ["app", "classname"] merge keys instead of ["app", "title"] - #964

Closed
TimeToBuildBob wants to merge 3 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/android-activity-merge-keys
Closed

TimeToBuildBob wants to merge 3 commits into
ActivityWatch:masterfrom
TimeToBuildBob:fix/android-activity-merge-keys

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Fixes #959

Problem

On Android, the Activity view shows Time active: 0s and Top Applications: No data even when the Timeline for the same host/day is full of events.

Root cause: canonicalEvents() merges Android events with keys ["app", "title"]:

// queries.ts:158
isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app", "title"]);' : ''

Android watcher events carry app, package, and classname — but not title. The aw-transform merge implementation skips any event that is missing a requested key, so the entire event list collapses to empty. The Activity view then sums zero duration.

The same bug appears in appQuery() where title_events is merged with ["app", "classname", "title"] — again dropping all Android events.

Fix

Use ["app", "classname"] as the merge keys for Android, which matches the keys that Android events actually carry:

- isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app", "title"]);' : ''
+ isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app", "classname"]);' : ''
- title_events = sort_by_duration(merge_events_by_keys(events, ["app", "classname", "title"]));
+ title_events = sort_by_duration(merge_events_by_keys(events, ["app", "classname"]));

Tests

Added a regression test suite in test/unit/queries.test.node.ts that guards both call sites:

  • canonicalEvents for AndroidQueryParams must use ["app", "classname"], not ["app", "title"]
  • appQuery must not include "title" in its Android merge keys

All 84 tests pass.

…"title"]

Android watcher events carry app/package/classname but NOT title.
aw-transform skips events missing a requested merge key, so
merge_events_by_keys with ["app", "title"] collapsed all events to
empty — causing "Time active: 0s" in the Activity view (ActivityWatch#959).

Fix:
- canonicalEvents: ["app", "title"] → ["app", "classname"] for Android
- appQuery: ["app", "classname", "title"] → ["app", "classname"] for title_events

Adds regression test to guard both call sites.

Closes ActivityWatch#959

Git-Session-Id: 0323
@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 63.63636% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.05%. Comparing base (3eebf68) to head (a0fe9f8).

Files with missing lines Patch % Lines
src/stores/activity.ts 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #964      +/-   ##
==========================================
+ Coverage   49.62%   50.05%   +0.43%     
==========================================
  Files          46       46              
  Lines        2783     2789       +6     
  Branches      630      603      -27     
==========================================
+ Hits         1381     1396      +15     
- Misses       1322     1373      +51     
+ Partials       80       20      -60     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR corrects source-specific event aggregation so Android events merge by app and classname, while imported ScreenTime events retain aggregation by app and title.

  • Propagates an iOS source discriminator through activity and categorization query paths.
  • Adds regression coverage for Android and ScreenTime merge keys.
  • Makes CI log collection support both standard and testing cache roots without failing when logs are absent.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/queries.ts Selects merge keys according to Android versus ScreenTime event shapes and preserves the expected query result contract.
src/stores/activity.ts Correctly derives and propagates the ScreenTime discriminator through application and category query paths.
src/views/settings/CategoryBuilder.vue Propagates ScreenTime source identity when the categorization helper selects a mobile bucket.
test/unit/queries.test.node.ts Adds focused regression assertions for Android and ScreenTime merge-key generation.
.github/workflows/nodejs.yml Makes log discovery tolerant of both ActivityWatch cache roots and missing log files.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  B[Selected mobile bucket] --> D{ScreenTime bucket?}
  D -->|Yes| I[Set isIos true]
  D -->|No| A[Use Android defaults]
  I --> IT[Merge by app and title]
  A --> AC[Merge by app and classname]
  IT --> Q[Categorize and aggregate events]
  AC --> Q
  Q --> V[Activity summaries and category views]
Loading

Reviews (2): Last reviewed commit: "fix(android): preserve ScreenTime merge ..." | Re-trigger Greptile

Comment thread src/queries.ts Outdated
`events = flood(${queryBucket(bid_window)});`,
// On Android, merge events to avoid overload of events
isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app", "title"]);' : '',
isAndroidParams(params) ? 'events = merge_events_by_keys(events, ["app", "classname"]);' : '',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 ScreenTime events lose aggregation

When an iOS/ScreenTime bucket is selected, the shared appQuery path sends events containing app and title through this merge requiring classname; the transform discards events missing that key, causing the iOS Activity view to report zero active time and no application data.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a0fe9f8. appQuery and canonicalEvents now select merge keys by source: Android keeps ["app", "classname"], while ScreenTime uses ["app", "title"]. The Activity store passes the ScreenTime flag through the app and category paths, and Category Builder does the same. Added an iOS query regression assertion; the focused query suite passes (19 tests).

… absence

Since ActivityWatch/aw-server-rust#652, --testing servers log to
~/.cache/activitywatch-testing/ while released builds use
~/.cache/activitywatch/. Use shopt nullglob to gracefully handle
both paths and avoid failing when no log files are present.

Git-Session-Id: 8fb4
Git-Session-Id: b9c4e8f0-fc2a-57bb-92bd-c1eff3b7e568
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Closing in favor of #960.

#960 fixes the same Android regression while preserving the shared iOS/ScreenTime path with source-aware merge keys. This duplicate's unconditional ["app", "classname"] merge drops ScreenTime events that carry app + title but no classname, as the open P1 review notes.

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.

On Android, the Activity view reports Time active: 0s

1 participant