fix(engine): tableau clipped off-screen after fold cycle — layout computed for stale window width #130

Closed
opened 2026-07-06 21:24:41 +00:00 by funman300 · 1 comment
Owner

Severity: Medium-High (Android foldables)

Observed on Galaxy Fold 7 running v0.41.0 during on-device verification of #116 (photo evidence from device testing, 2026-07-06).

Symptom

After a fold/unfold cycle, on the cover screen the tableau is laid out for a width wider than the actual screen: the leftmost column is clipped off the left edge (~15% of a card), the rightmost column sits flush against the right edge, and the bottom third of the screen is empty.

Evidence

  • adb logcat shows winit 0.30.13 printing TODO: find a way to notify application of content rect change on every resume, and TODO: forward onStart notification to application — the windowing layer does not reliably deliver the new surface size after a fold-while-backgrounded.
  • on_app_resumed (safe_area.rs) emits a synthetic WindowResized from window.resolution at WillResume time — if winit hasn't processed the new surface yet, that resolution is the old screen's, and the relayout runs with stale dimensions.
  • The safe-area re-poll (#116 fix) is orthogonal: insets resolved once at launch (top=110 bottom=0) and no further safe_area: log lines appeared during fold cycles — needs confirmation whether the re-poll fires at all (AppLifecycle::WillResume may never be emitted on Android; see winit TODOs).

Investigation plan

  1. With the device attached, stream logcat while folding/unfolding foreground and backgrounded; log whether Bevy receives WindowResized at all after the fold, and with what dimensions.
  2. Confirm whether AppLifecycle::WillResume fires on Android (instrument rearm_on_resumed).
  3. Candidate fix: poll the decor-view size via the existing JNI bridge (same cadence as the inset poller) and emit a synthetic WindowResized when it disagrees with Bevy's cached window.resolution — covers both the fold-size and the inset staleness in one mechanism.

Related: #116 (safe-area re-poll may share the same root cause: missing lifecycle events).

🤖 Generated with Claude Code

**Severity: Medium-High (Android foldables)** Observed on Galaxy Fold 7 running v0.41.0 during on-device verification of #116 (photo evidence from device testing, 2026-07-06). ## Symptom After a fold/unfold cycle, on the cover screen the tableau is laid out for a width wider than the actual screen: the leftmost column is clipped off the left edge (~15% of a card), the rightmost column sits flush against the right edge, and the bottom third of the screen is empty. ## Evidence - `adb logcat` shows winit 0.30.13 printing `TODO: find a way to notify application of content rect change` on every resume, and `TODO: forward onStart notification to application` — the windowing layer does not reliably deliver the new surface size after a fold-while-backgrounded. - `on_app_resumed` (safe_area.rs) emits a synthetic `WindowResized` from `window.resolution` at `WillResume` time — if winit hasn't processed the new surface yet, that resolution is the **old** screen's, and the relayout runs with stale dimensions. - The safe-area re-poll (#116 fix) is orthogonal: insets resolved once at launch (top=110 bottom=0) and no further `safe_area:` log lines appeared during fold cycles — needs confirmation whether the re-poll fires at all (AppLifecycle::WillResume may never be emitted on Android; see winit TODOs). ## Investigation plan 1. With the device attached, stream logcat while folding/unfolding foreground and backgrounded; log whether Bevy receives `WindowResized` at all after the fold, and with what dimensions. 2. Confirm whether `AppLifecycle::WillResume` fires on Android (instrument `rearm_on_resumed`). 3. Candidate fix: poll the decor-view size via the existing JNI bridge (same cadence as the inset poller) and emit a synthetic `WindowResized` when it disagrees with Bevy's cached `window.resolution` — covers both the fold-size and the inset staleness in one mechanism. Related: #116 (safe-area re-poll may share the same root cause: missing lifecycle events). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

On-device update (Fold 7, 2026-07-06): the dominant visual issue from the original photos was the pile-marker child-resize bug — fixed in PR #131, shipped as v0.41.1, and verified fixed on device through fold cycles. The clipped-tableau state did NOT reproduce in subsequent fold testing (foreground and backgrounded) on v0.41.x — it may have been a transient mid-fold-transition state. Safe-area insets read identically on both screens (top=110, bottom=0), so the #116 re-poll path was never exercised on this device. v0.41.1 ships an Android relayout log line (width/height/insets per relayout) — if the clip recurs, a single 'adb logcat -s RustStdoutStderr' grab will show exactly what dimensions the layout ran with. Keeping open at low priority pending recurrence.

On-device update (Fold 7, 2026-07-06): the dominant visual issue from the original photos was the pile-marker child-resize bug — fixed in PR #131, shipped as v0.41.1, and verified fixed on device through fold cycles. The clipped-tableau state did NOT reproduce in subsequent fold testing (foreground and backgrounded) on v0.41.x — it may have been a transient mid-fold-transition state. Safe-area insets read identically on both screens (top=110, bottom=0), so the #116 re-poll path was never exercised on this device. v0.41.1 ships an Android relayout log line (width/height/insets per relayout) — if the clip recurs, a single 'adb logcat -s RustStdoutStderr' grab will show exactly what dimensions the layout ran with. Keeping open at low priority pending recurrence.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: funman300/Ferrous-Solitaire#130