[Bug]: Android Subscription usage widget lost the scrolling full list from #13474#15227

openedOct 3, 2026byTtris203

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/mobile

Steps to reproduce

  1. Connect an environment whose Codex or Claude subscription reports more than two limits (for example session, weekly and a scoped limit).
  2. Add the Subscription usage widget on Android.
  3. Try to see every limit in the widget.

Expected behavior

The behaviour #13474 shipped on 25 September: every limit is listed, the list scrolls inside the widget, the header reads Subscription usage (N) with the entry count, and the timestamp is labelled "Last checked".

Actual behavior

The widget shows at most two limits per provider and "N more in T3" for the rest. It does not scroll, has no header, and labels the timestamp "As of".

Impact

Limits beyond the first two per provider are not visible from the home screen, which is what #13474 fixed. The only way to see them is to open the app.

Version or commit

main at 18b21325c3. Introduced by #12046 (e41755cf8a), first shipped in v0.0.45-nightly.20261001.2552.

What happened

This looks like a fix lost in a rewrite, not a deliberate revert:

  • 16 Sep: #12046 is opened. It replaces the native widget module (apps/mobile/modules/t3-subscription-widget) with an expo-widgets layout.
  • 25 Sep: #13474 merges, fixing the native module.
  • 1 Oct: #12046 merges and deletes that module, including the #13474 changes to it.

The #12046 description lists what the old module did that expo-widgets does not (expiry re-render, cold-start tap). The #13474 behaviours are not on that list.

#13474 behaviourOld native widgetNow (SubscriptionUsage.android.tsx)
Every limit shownAll rows added to a RemoteCollectionItems listprovider.windows.slice(0, limit) with const limit = 2
List scrollsListView between a fixed header and footerFixed Column, no scrolling
No overflow countNot needed, the list scrollsN more in T3 per provider
Entry count in the headerSubscription usage (%1$d)No header
Timestamp labelLast checked %1$sAs of …

Before/after screenshots and a scrolling recording of the old behaviour are in #13474.

The data is still delivered

The half of #13474 that lives outside the deleted module survived, so this is a layout-only regression:

  • SubscriptionUsageCoordinator.tsx still passes Platform.OS === "android" ? Infinity : 6 as the per-provider limit, so the Android snapshot carries every limit. The layout then discards all but two.
  • subscriptionUsageSnapshot.ts still lists only configured providers, so a Codex-only setup does not get an invented Claude row. That part of #13474 is not regressed.

Fix direction

@expo/ui 58.0.11 exports LazyColumn, and the expo-widgets Android runtime renders LazyColumnView as a Glance lazy column. Putting the limits in a lazy column would restore scrolling and the full list, and remove the need for the limit constant and the "N more in T3" line. The header count and "Last checked" label are text changes.

One thing to check on a device: the whole card is currently a single Button so that a tap reaches the app. I have not tested whether a lazy column scrolls inside it. The old widget handled this with per-row click intents.

The tests in SubscriptionUsage.android.test.ts assert the current behaviour ("3 more in T3", "As of ") and would need updating.

  • #15225: the widget can no longer be resized below 4×3. Scrolling is also what makes smaller sizes usable, so the two fixes go together.
  • #15158: the widget picker preview, dropped in the same migration.
  • #14158: open PR that edits the deleted Kotlin module and now conflicts.
  • The old values/bools.xml and values-v32/bools.xml under apps/mobile/modules/t3-subscription-widget are orphaned and can be removed with the fix.

Environment

Traced from source; not captured on a device. expo-widgets 58.0.11, @expo/ui 58.0.11.

Note

Grok responding on behalf of Julius.

Triage

Thanks @tris203 for another careful trace, including the timeline. I confirmed this on current main (f391794a35). The Android widget layout hasn't changed since #12046 (e41755cf8a), and the merged #13474 (59abcd67ac) was already an ancestor of that commit, so the scrolling widget was on main when the rewrite landed.

What I verified

SubscriptionUsage.android.tsx still shows at most two windows per provider (const limit = 2, then provider.windows.slice(0, limit)), adds N more in T3, has no Subscription usage (N) header, and labels the timestamp As of …. SubscriptionUsage.android.test.ts asserts that behavior (3 more in T3, As of ).

The snapshot half of #13474 is still in place, as you said. SubscriptionUsageCoordinator passes Infinity on Android, with a comment that Android scrolls the full list, and subscriptionUsageSnapshot.test.ts still expects every limit in that case. So the published snapshot has every row and the Compose layout drops them. #12046's description names expiry re-render and cold-start tap as the old behaviors expo-widgets doesn't cover, but doesn't mention the scrolling list, the header count, or Last checked.

Likely fix area

A maintainer will decide on the fix direction. LazyColumn is exported from @expo/ui/jetpack-compose at the pinned 58.0.11, which fits your suggestion. Whether it scrolls inside the single card Button still needs a device check.

  • #15225 (resize floor) and #15158 (picker preview) come from the same migration but are separate defects.
  • Open PR #14158 still edits the deleted Kotlin module and conflicts.
  • The two bools.xml files under apps/mobile/modules/t3-subscription-widget are unreferenced now that #12046 deleted the receiver that used @bool/t3_subscription_widget_enabled. Removing them is cleanup, separate from restoring the list.

Android device verification is blocked in the triage environment: the device service reports "Agent device access is turned off for this environment." No runtime reproduction or fix has been verified. The report says it was traced from source; can you provide a recording from an Android device showing the widget with more than two subscription limits, including the app version and an attempted scroll?