FwPlayerDeckView is a horizontal video feed component in the Firework Android SDK. It displays a scrollable row of video thumbnails with built-in autoplay support and product panel
This page covers how to integrate FwPlayerDeckView into your Android app and documents every public method and property.
1. Adding the View in XML
Add FwPlayerDeckView to your layout file. The recommended way to configure FwPlayerDeckView is programmatically via ViewOptions, so the XML tag only needs android:id, layout_width, and layout_height:
Note: Do not set custom XML attributes on FwPlayerDeckView. Use the ViewOptions.Builder API (described below) for all configuration. See the next section for how to choose the correct layout_height.
2. Recommended Height Configuration
Choosing the right height for FwPlayerDeckView is important for a good user experience. We recommend a height that shows approximately 1.5 deck items on screen, so the user can see the current item fully and get a visual hint that more content is available by scrolling horizontally.
How Item Width Is Derived from View Height
Each deck item fills the full height of the FwPlayerDeckView. The item consists of a 9:16 video area on top and a 72dp product panel at the bottom. The SDK calculates item width from the available height:
The number of items visible on screen is determined by: screenWidth / itemWidth.
The Formula
To display 1.5 items horizontally, set the view height to:
This is derived from solving itemWidth = screenWidth / 1.5:
Reference Values for Common Screen Widths
Screen Width (dp)
Recommended Height (dp)
Example Devices
360
~499
Budget / mid-range phones
390
~534
Pixel 7, iPhone-class widths
412
~560
Pixel 7 Pro, Samsung Galaxy S series
Tip: For most portrait-mode phones, a height of 500dp is a reasonable default that works well across common screen sizes. For a more precise fit, compute the height dynamically at runtime.
Dynamic Calculation at Runtime
To compute the optimal height programmatically based on the device's actual screen width:
In traditional Views (Kotlin):
In Jetpack Compose:
Note: If you configure feedPadding or itemSpacing in LayoutOption, the effective visible area changes slightly. The formula above ignores these values for simplicity; in practice the difference is negligible.
3. Programmatic Initialization (Fragment)
The typical lifecycle for FwPlayerDeckView in a Fragment is:
Build a ViewOptions instance via ViewOptions.Builder.
Call init(viewOptions, fragmentManager) to start loading content.
Call destroy() in onDestroyView() to release resources.
Full Example
Key Points
feedResource determines the content source. Common options include:
FeedResource.Discovery — curated discovery feed
FeedResource.Channel("channelId") — all videos from a channel
FeedResource.Playlist("channelId", "playlistId") — a specific playlist
autoplay in PlayerOption controls whether the first visible video plays automatically.
init() can be called multiple times to reinitialize with new options (e.g., switching channels). Each call generates a new feedId.
destroy() must always be called when the view is no longer needed to prevent memory leaks.
4. Compose Integration
Embed FwPlayerDeckView inside Jetpack Compose using AndroidView. Use the factory block for creation and initialization, and onRelease for cleanup.
Key Points
The hosting Activity must extend FragmentActivity (or AppCompatActivity) so that supportFragmentManager is available.
onRelease is called when the AndroidView is removed from the composition. This is the correct place to call destroy().
Wrap ViewOptions in remember { } to avoid rebuilding on every recomposition.
5. PlayerDeck Options
PlayerDeckOption configures UI elements specific to the inline PlayerDeck feed, such as the fullscreen icon, share button, and subtitle appearance. These options do not affect the fullscreen player (use PlayerOption for that).
Initializes the view with configuration options and starts loading content.
Parameter
Description
options
A ViewOptions instance built via ViewOptions.Builder. Pass null to use XML-declared attributes or defaults.
fragmentManager
The FragmentManager from the hosting Fragment (childFragmentManager) or Activity (supportFragmentManager).
Usage notes:
Must be called before any content is displayed.
Can be called multiple times to reinitialize with new options. Each call generates a new embed instance ID (feedId).
If the Firework SDK has not been initialized, the error listener will receive SdkNotInitialized.
destroy()
Releases all resources held by the view: cancels coroutines, unbinds dependency injection, destroys impression trackers, and stops visibility tracking.
Usage notes:
Must be called when the view is no longer needed (e.g., in onDestroyView() for Fragments, or onRelease for Compose AndroidView).
If a fullscreen player or PiP session is active for this view, the DI scope is preserved until the player closes.
refresh()
Clears the current feed and reloads content from the data source.
Usage notes:
Useful for pull-to-refresh implementations.
If the SDK is not initialized, the error listener receives SdkNotInitialized.
setOnErrorListener(listener: FwErrorListener)
Registers a callback to receive SDK errors.
Parameter
Type
Description
listener
FwErrorListener
A functional interface: fun onFwError(error: FwError)
Usage notes:
Set this before calling init() so that initialization errors (e.g., SdkNotInitialized) are captured.
Only one listener can be active at a time. Setting a new listener replaces the previous one.
Registers a click listener with interception support. If the listener returns true, the SDK will not open the fullscreen player (the click is intercepted). If it returns false, the SDK handles the click normally.
Parameter
Type
Description
index
Int
Position of the clicked item in the feed
videoInfo
VideoInfo
Detailed video metadata
Return value:Boolean — true to intercept, false to allow the SDK to open the player.
Registers a callback for feed loading state changes.
State
Description
Loading
The feed is currently fetching data.
LoadData
Data has been successfully loaded and displayed.
EmptyFeed
The data source returned no content.
EndOfFeed
All available content has been loaded (no more pages).
Error(message)
An error occurred during loading.
setVisibilityTrackingEnabled(enabled: Boolean)
Enables or disables automatic visibility-based autoplay control.
When enabled, the view uses a ViewTreeObserver-based tracker (OnScrollChangedListener + OnGlobalLayoutListener + getGlobalVisibleRect) to automatically detect when the view scrolls in or out of the visible area. Playback is paused when less than 50% of the view is visible and resumed when at least 50% is visible again.
Usage notes:
Can be called before or after init().
See Page 2: Handling Autoplay in Scrollable Containers for details and known Compose limitations.
onViewPortEntered()
Manually notifies the view that it has become visible in the viewport. Resumes autoplay if applicable.
Usage notes:
Use this when you are manually tracking visibility (Approach 1 in Page 2).
Has no effect if init() has not been called.
onViewPortLeft()
Manually notifies the view that it has left the viewport. Pauses autoplay.
Usage notes:
Use this when you are manually tracking visibility (Approach 1 in Page 2).
Has no effect if init() has not been called.
feedId: String (read-only property)
Returns the current embed instance ID. This value is unique per initialization cycle and changes each time init() is called.
Usage notes:
Useful for analytics or debugging to correlate events with a specific initialization cycle.
import android.content.res.Resources
fun calculateRecommendedHeight(): Int {
val screenWidthDp = Resources.getSystem().configuration.screenWidthDp
val bottomPanelDp = 72
val recommendedHeightDp = (screenWidthDp * 32.0 / 27.0 + bottomPanelDp).toInt()
// Convert dp to pixels for use in LayoutParams
val density = Resources.getSystem().displayMetrics.density
return (recommendedHeightDp * density).toInt()
}
// Usage:
playerDeckView.layoutParams.height = calculateRecommendedHeight()
playerDeckView.requestLayout()
override fun onDestroyView() {
playerDeckView.destroy()
super.onDestroyView()
}
playerDeckView.refresh()
playerDeckView.setOnErrorListener { error ->
when (error) {
is SdkLevelError.SdkNotInitialized -> { /* SDK not initialized */ }
is VideoFeedError -> { /* Feed loading error, check error.cause */ }
is PlayerError -> { /* Playback error */ }
else -> { /* Other errors */ }
}
}
playerDeckView.setOnClickFeedItemListener { index, videoInfo ->
Log.i("PlayerDeck", "Video clicked at index $index: ${videoInfo.videoId}")
// Return true to intercept (prevent SDK from opening the player)
// Return false to let the SDK handle the click normally
false
}
playerDeckView.setOnFeedViewStateListener { state ->
when (state) {
is FeedViewState.Loading -> { /* Feed is loading */ }
is FeedViewState.LoadData -> { /* Data loaded successfully */ }
is FeedViewState.EmptyFeed -> { /* No content available */ }
is FeedViewState.EndOfFeed -> { /* All content has been loaded */ }
is FeedViewState.Error -> { /* Error: ${state.message} */ }
}
}
// Enable before or after init()
playerDeckView.setVisibilityTrackingEnabled(true)