fix(android): stabilize recent sessions overview#101161
Conversation
There was a problem hiding this comment.
Pull request overview
This PR stabilizes the Android Home “Recent Sessions” panel by making recent-session ordering deterministic and by smoothing UI row updates during refresh churn, aligning recency with the Sessions screen contract (lastActivityAt ?: updatedAtMs).
Changes:
- Reworked recent-session selection to dedupe by session key and sort by recency (
lastActivityAtpreferred), with deterministic tie-breaking. - Updated overview row metadata to prefer
lastActivityAtwhen available. - Added a small “stable rows” merge step so partial refresh frames don’t blank out previously rendered row fields.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| apps/android/app/src/test/java/ai/openclaw/app/ui/ShellScreenLogicTest.kt | Adds/updates unit tests to cover recency sorting, last-activity preference, deduping, stable tie ordering, and stable-row behavior during partial refresh. |
| apps/android/app/src/main/java/ai/openclaw/app/ui/ShellScreen.kt | Implements recency-based session ordering/deduping and introduces stable recent-session row handling in the Overview screen to reduce UI flashing. |
|
Codex review: needs maintainer review before merge. Reviewed July 6, 2026, 8:38 PM ET / 00:38 UTC. Summary PR surface: Other +136. Total +136 across 3 files. Reproducibility: yes. Current main is source-reproducible because Home still uses incoming session order and Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Land the focused Android Home stabilization after maintainer approval and current-main merge validation, without expanding this PR into broader session-cache merge semantics. Do we have a high-confidence way to reproduce the issue? Yes. Current main is source-reproducible because Home still uses incoming session order and Is this the best way to solve the issue? Yes. The PR is a narrow UI-layer fix that aligns Home with the existing Sessions recency contract and avoids changing global ChatController or cache merge semantics for a visible Home-only stability issue. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 74bb2ad7a533. Label changesLabel justifications:
Evidence reviewedPR surface: Other +136. Total +136 across 3 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (4 earlier review cycles)
|
3dc4a9d to
c719803
Compare
ade8999 to
2e8e728
Compare
|
@clawsweeper re-review Refreshed the branch against current Proof:
|
|
🦞🧹 I asked ClawSweeper to review this item again. |
2e8e728 to
1b2fa8c
Compare
|
@clawsweeper re-review Updated again after Proof:
|
Formatting drift landed via #101161; :app:ktlintCheck fails on main without this. Generated with ./gradlew :app:ktlintFormat.
Formatting drift landed via #101161; :app:ktlintCheck fails on main without this. Generated with ./gradlew :app:ktlintFormat.
* style(android): fix ktlint drift in ShellScreen.kt Formatting drift landed via #101161; :app:ktlintCheck fails on main without this. Generated with ./gradlew :app:ktlintFormat. * ci(android): add ktlint lane to the Android CI job Android formatting drift kept landing on main because CI never ran ktlintCheck (see the #100304 manual sweep). Adds an android-ktlint matrix lane mirroring pnpm android:lint. * chore(i18n): sync native inventory after ShellScreen.kt format The ktlint format fix shifted line numbers tracked in apps/.i18n/native-source.json; regenerated via pnpm native:i18n:sync. * style(android): fix new ktlint drift in NodeRuntime and ChatHardwareKeyTest Import-order/blank-line drift landed via the hardware-Enter changes (#101321 and follow-up) while this PR was open — the exact recurrence the new android-ktlint lane prevents. Generated with ktlintFormat; native i18n inventory resynced for the shifted line numbers.
* style(android): fix ktlint drift in ShellScreen.kt Formatting drift landed via openclaw#101161; :app:ktlintCheck fails on main without this. Generated with ./gradlew :app:ktlintFormat. * ci(android): add ktlint lane to the Android CI job Android formatting drift kept landing on main because CI never ran ktlintCheck (see the openclaw#100304 manual sweep). Adds an android-ktlint matrix lane mirroring pnpm android:lint. * chore(i18n): sync native inventory after ShellScreen.kt format The ktlint format fix shifted line numbers tracked in apps/.i18n/native-source.json; regenerated via pnpm native:i18n:sync. * style(android): fix new ktlint drift in NodeRuntime and ChatHardwareKeyTest Import-order/blank-line drift landed via the hardware-Enter changes (openclaw#101321 and follow-up) while this PR was open — the exact recurrence the new android-ktlint lane prevents. Generated with ktlintFormat; native i18n inventory resynced for the shifted line numbers.
* style(android): fix ktlint drift in ShellScreen.kt Formatting drift landed via openclaw#101161; :app:ktlintCheck fails on main without this. Generated with ./gradlew :app:ktlintFormat. * ci(android): add ktlint lane to the Android CI job Android formatting drift kept landing on main because CI never ran ktlintCheck (see the openclaw#100304 manual sweep). Adds an android-ktlint matrix lane mirroring pnpm android:lint. * chore(i18n): sync native inventory after ShellScreen.kt format The ktlint format fix shifted line numbers tracked in apps/.i18n/native-source.json; regenerated via pnpm native:i18n:sync. * style(android): fix new ktlint drift in NodeRuntime and ChatHardwareKeyTest Import-order/blank-line drift landed via the hardware-Enter changes (openclaw#101321 and follow-up) while this PR was open — the exact recurrence the new android-ktlint lane prevents. Generated with ktlintFormat; native i18n inventory resynced for the shifted line numbers.
* style(android): fix ktlint drift in ShellScreen.kt Formatting drift landed via openclaw#101161; :app:ktlintCheck fails on main without this. Generated with ./gradlew :app:ktlintFormat. * ci(android): add ktlint lane to the Android CI job Android formatting drift kept landing on main because CI never ran ktlintCheck (see the openclaw#100304 manual sweep). Adds an android-ktlint matrix lane mirroring pnpm android:lint. * chore(i18n): sync native inventory after ShellScreen.kt format The ktlint format fix shifted line numbers tracked in apps/.i18n/native-source.json; regenerated via pnpm native:i18n:sync. * style(android): fix new ktlint drift in NodeRuntime and ChatHardwareKeyTest Import-order/blank-line drift landed via the hardware-Enter changes (openclaw#101321 and follow-up) while this PR was open — the exact recurrence the new android-ktlint lane prevents. Generated with ktlintFormat; native i18n inventory resynced for the shifted line numbers.
What Problem This Solves
Android Home's Recent Sessions panel could visibly flash as gateway refreshes delivered duplicate or partial session rows. The panel could briefly reorder rows or replace nonblank row metadata with blank metadata during refresh churn.
Why This Change Was Made
This keeps Home's Recent Sessions ordering aligned with the Sessions screen recency contract (
lastActivityAt ?: updatedAtMs), deduplicates repeated session keys by the newest entry, and preserves prior nonblank row fields for the same visible session while a partial refresh frame is in flight.User Impact
The Recent Sessions section should stop flashing between row states during live refreshes while still reflecting the current recent-session candidates and newly active sessions.
Evidence
JAVA_HOME='/Applications/Android Studio.app/Contents/jbr/Contents/Home' ANDROID_HOME="$HOME/Library/Android/sdk" ANDROID_SDK_ROOT="$HOME/Library/Android/sdk" ./gradlew testPlayDebugUnitTest --tests ai.openclaw.app.ui.ShellScreenLogicTest.agents/skills/autoreview/scripts/autoreview --mode local-> clean, no accepted/actionable findingspnpm native:i18n:syncrefreshedapps/.i18n/native-source.jsonpnpm native:i18n:check->native-app-i18n: entries=2775 changed=falsegit diff --check./gradlew installPlayDebugonOpenClaw_StableProof_API_35(AVD) - 15ai.openclaw.app/.MainActivityand sampled Recent Sessions; row stayed stable asOpenClaw Windows Tray / OpenClaw / nowVisual Proof
Before = current
origin/mainwithout this PR. After = this PR branch.Before:
After: