TubiExoPlayerView.java
Overview
`TubiExoPlayerView` is a custom Android UI component extending `FrameLayout` that integrates Google’s ExoPlayer video playback within a flexible, reusable player view. It serves as a comprehensive container managing:
Video rendering surface (either
SurfaceVieworTextureView) with aspect ratio handling.Subtitle rendering via ExoPlayer’s
SubtitleView, styled for clarity and accessibility.Injection and management of user interaction controls (e.g., playback buttons, seek bars).
Binding to a
SimpleExoPlayerinstance, managing player event listeners, video output surface attachment, and subtitle text output.Delegation of playback control and UI state management to an internal
UserController.
This class facilitates the display and interaction aspects of media playback by combining video rendering, subtitles, and user controls into a single encapsulated view, improving modularity and consistency across the app.
Class: TubiExoPlayerView
Description
The main class of the file, `TubiExoPlayerView`, is a highly configurable player view embedding ExoPlayer playback components. It manages the lifecycle of the video surface and subtitles, and provides interfaces for setting the player and custom user controls.
Key Fields
Field | Type | Description |
|---|---|---|
`contentFrame` | `AspectRatioFrameLayout` | Container that maintains video aspect ratio dynamically. |
`shutterView` | `View` | A view overlay shown while video is loading or the first frame is not rendered yet. |
`surfaceView` | `View` | The video rendering surface, either `SurfaceView` or `TextureView`. |
`subtitleView` | `SubtitleView` | Renders timed subtitles/captions synchronized with video playback. |
`mUserInteractionView` | `View` | Custom user interaction controls (play/pause, seek, etc.) injected dynamically. |
`componentListener` | `ComponentListener` | Internal listener handling video, text, and player events. |
`player` | `SimpleExoPlayer` | The ExoPlayer instance associated with this view. |
`userController` | `UserController` | Playback control interface managing user interaction and player state. |
Constructors
TubiExoPlayerView(Context context)TubiExoPlayerView(Context context, AttributeSet attrs)TubiExoPlayerView(Context context, AttributeSet attrs, int defStyleAttr)
**Functionality:**
Inflates a player layout (default or customized via XML attributes).
Determines which video surface type to use (
SurfaceVieworTextureView).Sets up aspect ratio layout, shutter view, and subtitle view with proper styling.
Handles special behavior when in layout editor mode (
isInEditMode()).Initializes
UserControllerfor playback control logic.
Public Methods
void addUserInteractionView(@Nullable View controlView)
Adds a playback control view to a placeholder within the player layout.
Parameters:
controlView: A customViewimplementing playback controls.
Behavior:
Replaces placeholder view (
R.id.exo_controller_placeholder) withcontrolView.If placeholder not found or
controlViewis null, logs error or sets interaction view to null.
Usage Example:
View customControls = LayoutInflater.from(context).inflate(R.layout.custom_controls, null);
tubiExoPlayerView.addUserInteractionView(customControls);
SimpleExoPlayer getPlayer()
Returns the currently associated ExoPlayer instance or null if none.
void setPlayer(SimpleExoPlayer player, @NonNull PlaybackActionCallback playbackActionCallback)
Binds a `SimpleExoPlayer` to this view, managing video surface assignment and event listeners.
Parameters:
player: The ExoPlayer instance to attach.playbackActionCallback: Callback interface to forward playback user actions.
Behavior:
Detaches listeners and surfaces from previous player if any.
Sets video surface (
SurfaceVieworTextureView) on the player.Registers
componentListenerfor video, text, and player events.Delegates player and callback to the internal
UserController.Shows shutter view initially until first rendered frame.
Usage Example:
SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build();
tubiExoPlayerView.setPlayer(player, playbackActionCallback);
void setResizeMode(@AspectRatioFrameLayout.ResizeMode int resizeMode)
Sets the video content resize mode on the aspect ratio container.
Parameters:
resizeMode: One of theAspectRatioFrameLayoutresize modes (e.g.,RESIZE_MODE_FIT).
Usage Example:
tubiExoPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);
SubtitleView getSubtitleView()
Returns the `SubtitleView` used for rendering subtitles, or null if not present.
void setMediaModel(@NonNull MediaModel mediaModel)
Sets the media metadata on the internal `UserController` to update UI state accordingly.
Parameters:
mediaModel: The media metadata model containing title, duration, etc.
void setAvailableAdLeft(int count)
Updates the number of available ads remaining (used by `UserController` to update UI).
Inner Class: ComponentListener
Implements the following interfaces to listen to player events and update UI components:
SimpleExoPlayer.VideoListenerTextRenderer.OutputExoPlayer.EventListener
Responsibilities
onCues(List cues)
Passes subtitle cues to theSubtitleViewfor rendering.onVideoSizeChanged(...)
Calculates video aspect ratio and updates theAspectRatioFrameLayout.onRenderedFirstFrame()
Hides the shutter view once the first video frame is rendered.Other player event callbacks (
onPlayerStateChanged,onPlayerError, etc.) are implemented but mostly empty, reserved for future event handling or logging.
Important Implementation Details
Surface Type Selection:
During construction, the view reads XML attributes or uses defaults to decide betweenSurfaceViewandTextureViewfor video rendering. This choice impacts performance and flexibility (e.g.,TextureViewallows transformations).Aspect Ratio Handling:
Video aspect ratio is dynamically calculated on video size changes and applied to the container layout (AspectRatioFrameLayout) to maintain correct visual proportions.Subtitle Styling:
Subtitles are styled with a white font, transparent background, and a custom font loaded viaVaudTextView. On TV devices, subtitle text size is increased for readability.Shutter View:
Acts as a placeholder overlay while video is loading or before the first frame is rendered. It is hidden upon receiving the first rendered frame event.Edit Mode Support:
When rendered in a layout editor (e.g., Android Studio), the view replaces video playback components with a static logo and background color to avoid runtime dependencies.User Interaction View Injection:
Allows external playback controls UI to be inserted and managed dynamically in the player view, enabling modular UI design.
Interaction with Other System Components
ExoPlayer (
SimpleExoPlayer):
The view directly binds to ExoPlayer instances, setting video surfaces and receiving playback events to update UI components like subtitles and aspect ratio layout.UserController:
Acts as a playback control interface that manages playback state, user commands, and UI data binding.TubiExoPlayerViewdelegates control logic and user interaction handling to this controller.MediaModel:
The view can receive media metadata models to inform UI components (e.g., title, duration) via theUserController.PlaybackActionCallback:
The view forwards user playback actions (play, pause, seek) to implementations of this callback, typically in the hosting activity or fragment.Layout and Resources:
The view inflates a layout resource (R.layout.tubi_player_view) that defines the visual structure, including placeholders for video surface, subtitles, shutter, and controls.
Usage Example
// Create the player view
TubiExoPlayerView playerView = new TubiExoPlayerView(context);
// Inflate and add custom controls
View controls = LayoutInflater.from(context).inflate(R.layout.custom_controls, null);
playerView.addUserInteractionView(controls);
// Initialize ExoPlayer instance
SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build();
// Set player and callback
playerView.setPlayer(player, playbackActionCallback);
// Set media metadata
MediaModel mediaModel = new MediaModel(...);
playerView.setMediaModel(mediaModel);
// Add playerView to your layout container
parentLayout.addView(playerView);
Mermaid Class Diagram
classDiagram
class TubiExoPlayerView {
-AspectRatioFrameLayout contentFrame
-View shutterView
-View surfaceView
-SubtitleView subtitleView
-View mUserInteractionView
-SimpleExoPlayer player
-UserController userController
+TubiExoPlayerView(Context, AttributeSet, int)
+addUserInteractionView(View)
+setPlayer(SimpleExoPlayer, PlaybackActionCallback)
+getPlayer() SimpleExoPlayer
+setResizeMode(int)
+getSubtitleView() SubtitleView
+setMediaModel(MediaModel)
+setAvailableAdLeft(int)
}
class ComponentListener {
+onCues(List~Cue~)
+onVideoSizeChanged(int, int, int, float)
+onRenderedFirstFrame()
+onPlayerStateChanged(boolean, int)
+onPlayerError(ExoPlaybackException)
...
}
TubiExoPlayerView o-- "1" SimpleExoPlayer : manages
TubiExoPlayerView o-- "1" AspectRatioFrameLayout : manages layout
TubiExoPlayerView o-- "1" SubtitleView : renders subtitles
TubiExoPlayerView o-- "0..1" View : user interaction controls
TubiExoPlayerView --> UserController : delegates control and state
TubiExoPlayerView *-- ComponentListener : listens to player events
Summary
`TubiExoPlayerView` is a foundational UI component designed for integrating ExoPlayer video playback with subtitle rendering and user controls in a modular, extensible manner. It abstracts video surface management, adapts to device form factors, and provides seamless binding between player events and UI updates. By delegating playback control logic to `UserController` and allowing dynamic control view injection, it supports diverse playback scenarios and UI customizations within the Tubi media playback ecosystem.