DoubleViewTubiPlayerActivity.java
Overview
`DoubleViewTubiPlayerActivity` is an Android activity class designed for advanced video playback scenarios involving **two simultaneous ExoPlayer instances**: one for the main content (movie) playback and another for advertisements (ads). It extends from `TubiPlayerActivity` and implements interfaces for dual player control (`DoublePlayerInterface`) and auto-play functionality (`AutoPlay`).
This class orchestrates the lifecycle, initialization, and coordination of these two players, integrates a finite state machine (FSM) for robust playback state management, handles VPAID ads via a WebView, and supports rich user interactions and UI updates through injected controllers.
Key Responsibilities:
Initialize and manage two separate ExoPlayer instances:
Content player for movie playback (
mMoviePlayerinherited from superclass)Ad player for advertisement playback (
adPlayerin this class)
Inject and prepare dependencies via Dagger 2, including FSM player, UI controllers, ad logic controllers, and monitors.
Coordinate playback states and transitions using a finite state machine (
FsmPlayer).Handle media source preparation for both content and ads.
Track and update resume positions independently for content and ad players.
Manage VPAID ads through a WebView with proper back navigation handling.
Provide user interaction view integration and handle playback events/callbacks like progress, seek, subtitles, and quality changes.
Class: DoubleViewTubiPlayerActivity
public class DoubleViewTubiPlayerActivity extends TubiPlayerActivity implements DoublePlayerInterface, AutoPlay
Description
An activity class that extends the base `TubiPlayerActivity` to support **dual media playback** with two ExoPlayer instances, enabling seamless content and advertisement playback. It implements `DoublePlayerInterface` for controlling two players and `AutoPlay` for automated playback features.
Fields
Field | Type | Description |
|---|---|---|
`TAG` | `String` | Logging tag for debugging (`"DoubleViewTubiPlayerAct"`) |
`BANDWIDTH_METER_AD` | `DefaultBandwidthMeter` | Bandwidth meter for ad player adaptive track selection |
`adPlayer` | `SimpleExoPlayer` | ExoPlayer instance dedicated to ad playback |
`fsmPlayer` | `FsmPlayer` | Injected FSM player managing playback states |
`playerUIController` | `PlayerUIController` | Injected UI controller updating player views |
`adPlayingMonitor` | `AdPlayingMonitor` | Injected monitor for ad playback events |
`cuePointMonitor` | `CuePointMonitor` | Injected monitor for cue point events |
`adRetriever` | `AdRetriever` | Injected component to retrieve ad media |
`cuePointsRetriever` | `CuePointsRetriever` | Injected component to retrieve cue points |
`adInterface` | `AdInterface` | Injected interface for ad server communication |
`playerComponentController` | `PlayerAdLogicController` | Injected controller coordinating ad playback logic |
`vpaidClient` | `VpaidClient` | Injected client managing VPAID ads in WebView |
`trackSelector_ad` | `DefaultTrackSelector` | Track selector for the ad player |
Constructor and Lifecycle Methods
onCreate(Bundle savedInstanceState)
Purpose: Activity creation lifecycle method.
Functionality:
Calls superclass
onCreate.Injects dependencies (
injectDependency()).Prepares injected dependencies (
dependencyPrepare()).
Usage: First lifecycle method called during activity startup.
Dependency Injection
injectDependency()
Purpose: Inject dependencies using Dagger 2.
Details:
Builds a Dagger component with default player module and injects dependencies into this activity.
Intended to be overridden by subclasses if custom injection is needed.
Example:
protected void injectDependency() {
DaggerFsmComonent.builder()
.playerModuleDefault(new PlayerModuleDefault())
.build()
.inject(this);
}
dependencyPrepare()
Purpose: Hook for subclasses to prepare injected dependencies.
Details: Empty in base class; override to perform post-injection setup.
Player Initialization and Lifecycle
initMoviePlayer()
Overrides:
TubiPlayerActivity.initMoviePlayer()Purpose: Initialize the content player and conditionally initialize the ad player.
Details:
Calls superclass to initialize the movie player and create media source.
Checks device capability (
PlayerDeviceUtils.useSinglePlayer()) to decide whether to initialize the ad player.
Algorithm:
If dual player mode, calls
setupAdPlayer().
setupAdPlayer()
Purpose: Create and initialize the ad player.
Details:
Creates an adaptive track selection factory using
BANDWIDTH_METER_AD.Initializes
trackSelector_adwith adaptive track selection.Creates a new
SimpleExoPlayerinstance for ad playback.
Usage Example:
TrackSelection.Factory adaptiveTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(BANDWIDTH_METER_AD);
trackSelector_ad = new DefaultTrackSelector(adaptiveTrackSelectionFactory);
adPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector_ad);
releaseMoviePlayer()
Overrides:
TubiPlayerActivity.releaseMoviePlayer()Purpose: Release the content and ad players and clean up.
Details:
Calls superclass to release movie player.
If dual player mode, calls
releaseAdPlayer()to release ad player and clear VPAID WebView.
releaseAdPlayer()
Purpose: Release resources held by the ad player.
Details:
Updates ad resume position before release.
Releases
adPlayerand sets to null.Clears and resets the VPAID WebView URL and history.
Playback Position Management
updateResumePosition()
Overrides:
TubiPlayerActivity.updateResumePosition()Purpose: Save current playback positions for both content and ad players.
Details:
Stores movie player resume window and position in
playerUIController.If the FSM is in
AdPlayingState, stores ad player resume info similarly.
Algorithm:
Checks if players are valid and not idle before saving position.
updateAdResumePosition()
Purpose: Store current ad player playback position to allow resuming later.
Details:
Retrieves current window index and position if seekable.
Updates
playerUIControllerwith this info.
FSM Preparation
prepareFSM()
Overrides:
TubiPlayerActivity.prepareFSM()Purpose: Prepare and configure the finite state machine player (
fsmPlayer) with all required components and data.Details:
Assigns content and ad players to the UI controller.
Sets player views (
mTubiPlayerViewandvpaidWebView) to the UI controller.Injects media models, ad retrievers, cue point retrievers, and ad server interface into the FSM player.
Sets up
playerComponentControllerwith monitors, interfaces, and clients.Sets lifecycle awareness for the FSM player.
Checks FSM initialization and triggers state update or initialization.
Usage Example:
playerUIController.setContentPlayer(mMoviePlayer);
if (!PlayerDeviceUtils.useSinglePlayer()) {
playerUIController.setAdPlayer(adPlayer);
}
playerUIController.setExoPlayerView(mTubiPlayerView);
playerUIController.setVpaidWebView(vpaidWebView);
fsmPlayer.setController(playerUIController);
fsmPlayer.setMovieMedia(mediaModel);
fsmPlayer.setAdRetriever(adRetriever);
fsmPlayer.setCuePointsRetriever(cuePointsRetriever);
fsmPlayer.setAdServerInterface(adInterface);
playerComponentController.setAdPlayingMonitor(adPlayingMonitor);
playerComponentController.setTubiPlaybackInterface(this);
playerComponentController.setDoublePlayerInterface(this);
playerComponentController.setCuePointMonitor(cuePointMonitor);
playerComponentController.setVpaidClient(vpaidClient);
fsmPlayer.setPlayerComponentController(playerComponentController);
fsmPlayer.setLifecycle(getLifecycle());
if (fsmPlayer.isInitialized()) {
fsmPlayer.updateSelf();
Utils.hideSystemUI(this, true);
} else {
fsmPlayer.transit(Input.INITIALIZE);
}
User Interaction View
addUserInteractionView()
Overrides: Abstract method from superclass.
Purpose: Provide a view that handles user interactions like play/pause, seek, etc.
Returns: A configured
UIControllerViewbound to the player controller.
Intent Handling and Navigation
onNewIntent(Intent intent)
Overrides:
Activity.onNewIntent()Purpose: Reset movie resume info on receiving a new intent.
Details: Clears any saved movie resume info in the UI controller.
onBackPressed()
Overrides:
Activity.onBackPressed()Purpose: Handles back navigation with special handling for VPAID WebView.
Functionality:
If current FSM state is
VpaidStateand WebView can navigate back, performs WebView back navigation.Uses
ingoreWebViewBackNavigation()to avoid navigating back to empty or blank URLs.Otherwise, calls superclass back press behavior.
ingoreWebViewBackNavigation(WebView vpaidWebView)
Purpose: Determine if WebView back navigation should be ignored based on history.
Returns:
trueif the previous WebView history item URL is empty (e.g.,"about:blank"), otherwisefalse.
Media Source and Ads Preparation
createMediaSource(MediaModel videoMediaModel)
Purpose: Create and assign a
MediaSourcefor the provided media model.Details: Calls
buildMediaSource()(inherited or implemented elsewhere) and sets it on the media model.
onPrepareAds(@Nullable AdMediaModel adMediaModel)
Overrides: From interface or superclass.
Purpose: Prepare media sources for each ad in the provided ad media model.
Details: Iterates through ads and builds media sources for each.
Playback Event Callbacks
These methods respond to playback events and update monitors or UI accordingly:
onProgress(MediaModel mediaModel, long milliseconds, long durationMillis)
Updates cue point monitor with current movie progress.onSeek(MediaModel mediaModel, long oldPositionMillis, long newPositionMillis)
(Currently logs seek events, can be extended.)onPlayToggle(MediaModel mediaModel, boolean playing)
(Currently logs play/pause toggles.)onLearnMoreClick(MediaModel mediaModel)
Opens the click-through URL in a browser if available and not a TV device.onSubtitles(MediaModel mediaModel, boolean enabled)
(Currently logs subtitle enable/disable.)onQuality(MediaModel mediaModel)
(Currently logs quality changes.)onCuePointReceived(long[] cuePoints)
Updates UI cue point indicator with formatted cue points.
Playback Control
playNext(MediaModel nextVideo)
Overrides: From
DoublePlayerInterface.Purpose: Play the next video media.
Details:
Creates media source for the next video.
Sets it to FSM player and restarts FSM playback state.
Important Implementation Details
Dual Player Architecture:
The class maintains two separateSimpleExoPlayerinstances to manage content and ad playback independently, avoiding resource contention and enabling smooth transitions.Finite State Machine (FSM) Integration:
Playback states and transitions, especially between content playback and ads, are managed via the injectedFsmPlayer, which simplifies complex playback logic and enforces clear state transitions.Dependency Injection:
Uses Dagger 2 (DaggerFsmComonent) for clean and testable injection of players, controllers, monitors, and ad-related components.VPAID WebView Handling:
Supports interactive VPAID ads using a WebView, with careful back navigation management to prevent unwanted navigation to blank pages.Resume Position Tracking:
Maintains separate resume information for content and ads to allow seamless resumption post-interruption or lifecycle changes.User Interaction View:
Provides a customUIControllerViewbound to the player controller for rich user interaction.
Interaction with Other Components
Superclass:
Inherits fromTubiPlayerActivity, leveraging its movie player setup and lifecycle management.FSM Player (
FsmPlayer):
Core orchestrator of playback states, transitions, and coordination of content/ad player behaviors.Player UI Controller (
PlayerUIController):
Bridges UI components with player instances; manages views and player state representation.Ad Components:
IncludesAdRetriever,CuePointsRetriever,AdInterface,PlayerAdLogicController, andVpaidClientfor ad retrieval, cue monitoring, ad logic, and VPAID ad playback.ExoPlayer:
UsesSimpleExoPlayerinstances for media playback with adaptive track selection and bandwidth metering.Utilities:
Uses utility classes for device capability checks (PlayerDeviceUtils), UI hiding (Utils), and logging (ExoPlayerLogger).
Usage Example
// Starting the activity with a media model (from somewhere in the app)
Intent intent = new Intent(context, DoubleViewTubiPlayerActivity.class);
intent.putExtra(TubiPlayerActivity.TUBI_MEDIA_KEY, mediaModel);
context.startActivity(intent);
Inside the activity, the dual players are initialized, and playback begins with FSM coordination, automatically handling ads and content according to cue points and playback state.
Mermaid Class Diagram
classDiagram
class DoubleViewTubiPlayerActivity {
-static final String TAG
-static final DefaultBandwidthMeter BANDWIDTH_METER_AD
-SimpleExoPlayer adPlayer
-FsmPlayer fsmPlayer
-PlayerUIController playerUIController
-AdPlayingMonitor adPlayingMonitor
-CuePointMonitor cuePointMonitor
-AdRetriever adRetriever
-CuePointsRetriever cuePointsRetriever
-AdInterface adInterface
-PlayerAdLogicController playerComponentController
-VpaidClient vpaidClient
-DefaultTrackSelector trackSelector_ad
+onCreate(Bundle)
+addUserInteractionView() View
+injectDependency()
+dependencyPrepare()
+initMoviePlayer()
+onPlayerReady()
+releaseMoviePlayer()
+updateResumePosition()
+prepareFSM()
+onNewIntent(Intent)
+onBackPressed()
+createMediaSource(MediaModel)
+onPrepareAds(AdMediaModel)
+onProgress(MediaModel, long, long)
+onSeek(MediaModel, long, long)
+onPlayToggle(MediaModel, boolean)
+onLearnMoreClick(MediaModel)
+onSubtitles(MediaModel, boolean)
+onQuality(MediaModel)
+onCuePointReceived(long[])
+playNext(MediaModel)
}
DoubleViewTubiPlayerActivity --|> TubiPlayerActivity
DoubleViewTubiPlayerActivity ..> FsmPlayer : injected
DoubleViewTubiPlayerActivity ..> PlayerUIController : injected
DoubleViewTubiPlayerActivity ..> AdPlayingMonitor : injected
DoubleViewTubiPlayerActivity ..> CuePointMonitor : injected
DoubleViewTubiPlayerActivity ..> AdRetriever : injected
DoubleViewTubiPlayerActivity ..> CuePointsRetriever : injected
DoubleViewTubiPlayerActivity ..> AdInterface : injected
DoubleViewTubiPlayerActivity ..> PlayerAdLogicController : injected
DoubleViewTubiPlayerActivity ..> VpaidClient : injected
DoubleViewTubiPlayerActivity o-- SimpleExoPlayer : adPlayer
DoubleViewTubiPlayerActivity o-- DefaultTrackSelector : trackSelector_ad
Summary
`DoubleViewTubiPlayerActivity` is a specialized Android activity enabling advanced dual-player video playback scenarios, managing separate ExoPlayer instances for content and ads. It tightly integrates with a finite state machine to manage playback states and transitions, supports VPAID ads via WebView, and leverages dependency injection for modular design. This class is pivotal in delivering a smooth, robust video playback experience with advanced ad insertion capabilities on the Tubi platform.