Skip to content

Recover video playback after network drops and hide Android system bars in fullscreen - #357

Merged
gumclaw merged 6 commits into
mainfrom
android-video-network-retry
Aug 31, 2026
Merged

gumclaw merged 6 commits into
mainfrom
android-video-network-retry

Conversation

@gumclaw

@gumclaw gumclaw commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

What

Makes the native video player survive the Android (and iOS) failures that show up in store reviews:

  1. Transient network errors no longer kill the session. Wi-Fi ↔ cell handoffs currently land on “This video failed to load” with no way back except force-quitting. Transient errors now reload the current source from the last position, up to three times. A Try again button does the same for hard failures.
  2. Native fullscreen hides Android system bars. The caption-overlay fullscreen path already hid the nav bar; the native VideoView fullscreen button did not, so 3-button navigation covered the scrubber. Native enter/exit now uses the same hide/restore.

Does not re-enable staysActiveInBackground on Android (PR #215 / #345). That still trips the media3 ExpoVideoPlaybackService ANR.

Why

Play Store is 3.6 vs iOS 4.7 on the same app. The 1-star Android reviews are the player: network switch → error, nav buttons covering controls, “close the app and start over.” This is the half we can ship without reopening the ANR.

Before / After

  • Before: a dropped connection shows a dead-end error; native fullscreen leaves the Android nav bar over the scrubber.
  • After: a dropped connection retries in place (then Try again); native fullscreen hides the nav bar and restores it on exit.

On-device Android (test_pixel, 3-button nav) at a3230b9:

Inline (nav bar visible, expand control reachable above it):

Native fullscreen (landscape, system bars hidden, scrubber fully tappable):

Exit fullscreen (portrait, 3-button nav restored):

Hard origin failure → Try again (not a dead end):

Try again after the origin is back:

In-flight Wi-Fi ↔ cell retry was not captured: the 10s local clip fully buffered, so killing the origin mid-play did not surface a transient error. Unit tests still cover that path. iOS staysActiveInBackground was not re-tested on a device this run.

Test Results

  • npx jest tests/lib/transient-playback-error.test.ts tests/app/video-player.test.tsx --runInBand — 83/83 passing
  • Mutation: forcing isTransientPlaybackError to always return false fails retries a transient network error without showing the failed screen; removing the recovery-progress retry reset fails resets the automatic retry budget after playback progresses again; disabling the iOS replaceAsync path fails uses asynchronous source replacement for iOS playback recovery; restored, 83/83 pass again
  • npx tsc --noEmit — clean
  • npx expo lint on the touched files — 0 new errors (same pre-existing warnings as on main)

QA steps

  1. Android, 3-button nav: play a purchased video, tap native fullscreen. System nav bar should hide; scrubber should be tappable. Exit fullscreen; nav bar returns. Done on test_pixel.
  2. Mid-video, toggle airplane mode on then off (or Wi-Fi → cell). Playback should resume from the same timestamp instead of the failed screen. After three failed recoveries, the failed screen appears with Try again. Try again + recover done on device. In-flight handoff not re-shot (clip fully buffered).
  3. Confirm iOS background playback is unchanged (staysActiveInBackground still iOS-only). Code still iOS-only; not re-run on a physical iPhone this pass.

Status

  • Scope — Android playback-recovery and native fullscreen-system-bar paths are covered.
  • Design — transient recovery stays bounded; retry budget resets only after playback progresses; iOS uses async source replacement.
  • Build — review feedback fixed on this branch.
  • QA — Android emulator fullscreen hide/restore + Try again/recover stills on this head. In-flight radio handoff not captured (see above).
  • Shipped — waiting for checks/ready.
  • Market — no public announcement needed.
  • Sell — no sales/support copy needed.

AI disclosure: Generated with Grok 4.6; review feedback verified with Sol.

Premerge review: clean @ 815a35f

…rs in fullscreen

Wi-Fi to cell handoffs currently dump buyers on a dead-end error screen, and
native fullscreen on Android leaves the navigation bar covering the scrubber.
Retry transient player errors from the last position, add a Try again button,
and hide system bars for native fullscreen the same way we already do for the
external-caption overlay.
@gumclaw gumclaw added the working An agent is actively building this label Aug 28, 2026
@gumclaw gumclaw self-assigned this Aug 28, 2026
@greptile-apps

greptile-apps Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds bounded video playback recovery with a manual retry action and hides Android system bars during native fullscreen playback.

  • Classifies transient playback errors and retries from the latest position.
  • Resets the automatic retry budget once playback advances after recovery.
  • Uses asynchronous source replacement on iOS and restores Android system bars after fullscreen.
  • Adds focused playback-recovery and fullscreen lifecycle tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
app/video-player.tsx Adds guarded playback recovery, retry UI, progress-based retry-budget reset, and native fullscreen system-bar handling; the previously reported issues are resolved at the current head.
lib/transient-playback-error.ts Adds a bounded transient-error classifier for common network and gateway playback failures.
tests/app/video-player.test.tsx Expands coverage for automatic and manual recovery, iOS asynchronous replacement, retry-budget reset, and fullscreen system-bar restoration.
tests/lib/transient-playback-error.test.ts Covers transient marker recognition, case handling, and non-transient playback failures.

Reviews (3): Last reviewed commit: "Continue iOS transient playback retries" | Re-trigger Greptile

Comment thread app/video-player.tsx
@gumclaw

gumclaw commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Stays draft: on-device Android QA is still owed (native fullscreen hides 3-button nav; Wi-Fi↔cell handoff retries instead of the failed screen). No booted emulator in this sandbox. CI green at 1d5551842eba.

@slavingia slavingia assigned gianfrancopiana and unassigned gumclaw Aug 29, 2026
On-device test_pixel, 3-button nav: native VideoView fullscreen hides system bars and restores them on exit. Hard origin failure shows Try again and recovers after the origin returns.

Co-authored-by: Gianfranco Piana <52470719+gianfrancopiana@users.noreply.github.com>
@gianfrancopiana

Copy link
Copy Markdown
Member

@greptileai

@gumclaw
gumclaw marked this pull request as ready for review August 31, 2026 01:58
@gumclaw
gumclaw merged commit 9c0a6d9 into main Aug 31, 2026
3 checks passed
@gumclaw
gumclaw deleted the android-video-network-retry branch August 31, 2026 01:58
@gumclaw

gumclaw commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Greptile's rerun was clean. While finishing the gate I found and fixed one additional iOS transient-retry edge, reran focused tests plus Sol, and merged this as 9c0a6d9.

@gumclaw gumclaw removed the working An agent is actively building this label Aug 31, 2026
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.

2 participants