RowList draws a row with missing tiles when LEFT/RIGHT is pressed just after moving off that row mid-scroll

Device: Roku Ultra 4800X
Roku OS: 16.0.4
Component: RowList (rowFocusAnimationStyle=“fixedFocus”, vertFocusAnimationStyle=“fixedFocus”)
Severity: High - visible to users, and easy to hit with a remote

Summary
If you move off a row while it is still scrolling sideways, and then press LEFT or RIGHT straight away, RowList draws the row you left with tiles missing. Usually there’s an empty space at the start of the row. Sometimes only one tile is left, at the far right. The row stays like that until focus goes back to it.

This happens on a bare RowList with static content and no code of its own, so it isn’t caused by anything the channel does.

Steps to reproduce

  1. Make a RowList with two rows: row 0 with 3 items, row 1 with 48 items (any item component, e.g. a Rectangle and a Label).rowFocusAnimationStyle=“fixedFocus”. A minimal channel is attached (probe-channel).
  2. Press RIGHT twice so row 0 is on its last item.
  3. Press DOWN to focus row 1.
  4. Hold RIGHT so row 1 auto-scrolls (about 1-2 seconds).
  5. Release RIGHT and, while row 1 is still scrolling, press UP and then LEFT (or RIGHT) straight away, within about 100ms.

Expected
Row 0 is focused. Row 1, now unfocused, is drawn from the item it came to rest on, with every slot filled.

Actual
Row 0 is focused, but row 1 is drawn with tiles missing:

  • Typically the first one to four slots are empty, and the remaining tiles start part way along the row.
  • In the worst case only one tile is drawn, at the far right edge (see screenshot.jpg).

app-ui shows the cause:

  • The row’s MarkupGrid (now visible=“false”) has its focusItem one item further on than where it was left.
  • The RenderableNode that RowList draws the unfocused row from was laid out from an earlier column.
  • The tile for that earlier column isn’t rendered anywhere.
  • The row counter label also still shows the earlier column (e.g. “5 of 48” with focusItem=7).

It looks like RowList applies the LEFT/RIGHT to the row it is leaving (currFocusColumn jumps on by an item as the vertical animation starts), after it has already taken that row’s resting layout.

The row is redrawn correctly as soon as focus moves back onto it.

Measured on the attached channel (20 cycles each):

  • UP, then LEFT within 0-100ms (row 0 on its last item): 15/20 broken
  • UP, then RIGHT within 0-100ms (row 0 on its last item, so RIGHT can’t move it): 11/20 broken
  • UP, then RIGHT within 0-100ms (row 0 on its first item): 1/20 broken
  • UP only, no LEFT/RIGHT after it: 0/20 broken

Workaround
Ignore LEFT/RIGHT in the RowList subclass’s onKeyEvent (return true) while currFocusRow is fractional, i.e. while the move between rows is still animating.