Skip to content

Video player: lockscreen parity, playlist nav, aspect-fill, dimensions, teardown hardening#1

Open
danielwilliamson wants to merge 10 commits intomasterfrom
gm_video_player_changes
Open

Video player: lockscreen parity, playlist nav, aspect-fill, dimensions, teardown hardening#1
danielwilliamson wants to merge 10 commits intomasterfrom
gm_video_player_changes

Conversation

@danielwilliamson
Copy link
Copy Markdown
Collaborator

Summary

This branch bundles ten commits that extend the native video player with lockscreen/media-center parity across iOS and Android, adds playlist track navigation, introduces aspect-fill rendering and video-dimension events, and hardens controller/event-channel teardown. It also wires in a new iOS Live Text (video frame analysis) toggle.

Commits (oldest → newest)

  • a16def8 Add aspect-fill, dimensions events, and lockscreen controls fixes
  • 4c53506 Fix lockscreen seek and metadata parity on iOS/Android
  • d70afea Disable previous/restart transport seek for non-premium
  • dcafcde Set Android seek back/forward increment to 15 seconds
  • 34e9e03 FLTR-19614: Add video frame analysis toggle
  • f43964d FLTR-19614: Harden iOS video event teardown
  • bb77fff FLTR-19615: Emit Android video dimensions more reliably
  • c210261 FLTR-19589: Handle controller event channel teardown races
  • aa6e940 FLTR-19589: Add video playlist track navigation controls
  • eb56283 FLTR-19796: Fix mixed video/audio playlist media center Not Playing state

Changes in detail

Lockscreen / now-playing parity (iOS + Android)

  • iOS (VideoPlayerNowPlayingHandler) and Android (VideoPlayerNotificationHandler) were brought to parity for metadata, artwork, and seek behavior so the lockscreen/media center shows consistent state across platforms.
  • Android seek back/forward increments are set to 15 seconds to match iOS.
  • FLTR-19796: Fixes a bug in mixed video/audio playlists where, after a video track, the media center would display Not Playing — the notification handler now re-asserts the correct now-playing state when transitioning between media types.

Playlist track navigation (FLTR-19589)

  • Android: a ForwardingPlayer intercepts seekToPrevious() / seekToNext() and emits previousTrack / nextTrack events when the corresponding track-nav flags are set. getAvailableCommands() is overridden so the system notification shows ⏮/⏭ even for single-item playlists; flags are updated eagerly inside handleLoad so onAvailableCommandsChanged picks them up immediately.
  • iOS: registers previousTrackCommand / nextTrackCommand remote-command handlers, toggling their enabled state based on showSystemPreviousTrackControl / showSystemNextTrackControl. A disabled direction falls back to the corresponding skip-seconds button.
  • Dart: new PlayerControlState.previousTrackRequested / nextTrackRequested events, and new showSkipControls / showSystemPreviousTrackControl / showSystemNextTrackControl fields on NativeVideoPlayerMediaInfo.

Premium transport controls

  • Previous/restart transport seek actions can now be disabled for non-premium users via the new now-playing flags, so lockscreen controls reflect entitlement state.

Aspect-fill rendering + video dimensions

  • New useAspectFill constructor flag and setUseAspectFill(bool) method on NativeVideoPlayerController, implemented on both iOS (VideoPlayerView) and Android (VideoPlayerView.kt) to toggle between aspect-fit and aspect-fill (zoom/crop).
  • New getVideoDimensions() method and PlayerControlState.videoDimensionsUpdated event (videoDimensions on the wire).
  • FLTR-19615: Android now emits video dimensions more reliably by hooking additional ExoPlayer listeners so late/async size changes aren't missed.

iOS Live Text / frame analysis (FLTR-19614)

  • New allowsVideoFrameAnalysis constructor flag (default true) passed to AVPlayerViewController on iOS 16+, enabling the system analysis button over video.
  • VideoPlayerObserver teardown on iOS has been hardened: observer/KVO removal paths are made idempotent and safe against double-release so dismissing a player mid-event no longer crashes.

Controller event channel teardown races (FLTR-19589)

  • The iOS controller-level event channel (used for persistent PiP/AirPlay events) is now set up lazily with a retry schedule (0 / 50 / 100 / 200 / 400 ms) after the first platform view attaches, instead of eagerly in the constructor. This removes a race where the channel was created before the native side had registered its StreamHandler.
  • Stream cancellation now swallows MissingPluginException and the PlatformException('error', 'No active stream to cancel') variant that iOS can throw when the native side has already torn down.
  • Channel setup swallows the channel-error / Unable to establish connection on channel transient that occurs during hot restart and very early attach.

Files touched

  • lib/src/controllers/native_video_player_controller.dart
  • lib/src/platform/video_player_method_channel.dart
  • lib/src/enums/native_video_player_event.dart
  • lib/src/models/native_video_player_media_info.dart
  • ios/Classes/View/VideoPlayerView.swift
  • ios/Classes/View/VideoPlayerViewController+Delegate.swift
  • ios/Classes/Handlers/VideoPlayerMethodHandler.swift
  • ios/Classes/Handlers/VideoPlayerNowPlayingHandler.swift
  • ios/Classes/Handlers/VideoPlayerObserver.swift
  • android/.../VideoPlayerView.kt
  • android/.../handlers/VideoPlayerMethodHandler.kt
  • android/.../handlers/VideoPlayerNotificationHandler.kt
  • android/.../handlers/VideoPlayerObserver.kt
  • android/.../manager/SharedPlayerManager.kt

Test plan

  • iOS: play a video, lock device — artwork, title, subtitle, and seek buttons match expected state; 15s skip works
  • Android: same as above; ⏮/⏭ appear for single-item playlists when track-nav flags are set
  • Mixed video/audio playlist (FLTR-19796): after a video track, media center shows correct Now Playing (not "Not Playing")
  • Non-premium build: previous/restart lockscreen button is disabled/hidden
  • Aspect-fill: toggle useAspectFill and setUseAspectFill(bool) and confirm render mode switches on iOS + Android
  • getVideoDimensions() returns non-null once the first frame is available; videoDimensionsUpdated event fires on Android for late size changes
  • iOS 16+: Live Text analysis button appears when allowsVideoFrameAnalysis: true, hidden when false
  • Hot restart and rapid dispose/reattach does not log "Controller event channel error" spam; PiP/AirPlay events still arrive after releaseResources()

🤖 Generated with Claude Code

danielwilliamson and others added 10 commits March 5, 2026 19:42
…and iOS

- Android: ForwardingPlayer intercepts seekTo{Previous,Next}() to fire
  previousTrack/nextTrack events when track nav flags are set; overrides
  getAvailableCommands() so the system notification shows ⏮/⏭ for
  single-item playlists; flags are updated eagerly in handleLoad so
  onAvailableCommandsChanged reflects them immediately
- iOS: Register previousTrackCommand/nextTrackCommand remote command
  handlers; toggle enabled state based on showSystemPreviousTrackControl
  / showSystemNextTrackControl flags; disabled direction falls back to
  the corresponding skip button
- Dart: Add previousTrackRequested/nextTrackRequested to PlayerControlState
  and NativeVideoPlayerMediaInfo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…laying after video track

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

1 participant