How to Add Custom Player Actions in SmartTube: A Complete Developer Guide
SmartTube Player Actions are user interactions—from basic playback controls to custom buttons—that are handled by the VideoPlayerGlue class and routed through the PlayerActionListener interface in PlaybackFragment.java to execute logic via the PlaybackPresenter.
SmartTube is an advanced open-source YouTube client engineered for Android TV and set-top boxes. For developers extending the default playback interface with functionality like "Subscribe," "Download," or "Like" buttons, understanding the Player Actions architecture is essential. This guide examines how these actions are structured in the yuliskov/SmartTube repository and provides a complete implementation path for adding new controls.
What Are Player Actions in SmartTube?
Player Actions represent every interactive element within the playback overlay, ranging from standard transport controls to application-specific feature buttons. The architecture separates the UI presentation layer (managed by VideoPlayerGlue) from the business logic layer (handled by PlaybackPresenter), connected through a strict listener contract defined in VideoPlayerGlue.OnActionClickedListener.
The concrete implementation of this listener resides in PlaybackFragment.java as the inner class PlayerActionListener (lines 90–118). This class intercepts all user inputs—including clicks, long-presses, and key events—and delegates them to the presenter for execution.
Core Action Types
The PlayerActionListener defines distinct handler methods for different interaction patterns:
- Transport Controls:
onPrevious(),onNext(),onPlay(), andonPause()manage standard media navigation - Custom Buttons:
onAction(int actionId, int actionIndex)handles short-clicks on UI buttons defined by integer IDs - Long-Press Gestures:
onLongAction(int actionId, int actionIndex)triggers alternative functionality when users hold a button - Focus Navigation:
onTopEdgeFocused()manages overlay visibility when navigating to the top of the player - Hardware Keys:
onKeyDown(int keyCode)captures remote control button presses for custom shortcuts
How the Player Action Architecture Works
The event flow follows a unidirectional pattern from the UI layer to the data layer. In VideoPlayerGlue.java (located at smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/ui/playback/other/VideoPlayerGlue.java), the glue class constructs the PlaybackControlsRow and defines the OnActionClickedListener interface.
When a user interacts with any control, VideoPlayerGlue invokes the corresponding method on the registered listener. The PlayerActionListener instance (implemented in PlaybackFragment.java at smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/ui/playback/PlaybackFragment.java) receives these callbacks and immediately forwards them to mPlaybackPresenter.
For example, when the "Next" button is clicked, the execution chain is:
VideoPlayerGluedetects the clickPlayerActionListener.onNext()is invoked- Method calls
mPlaybackPresenter.onNextClicked()to load the subsequent video
How to Add a New Custom Player Action
Extending the player interface requires modifications across the UI glue, the fragment listener, and resource files. Follow these implementation steps to inject a custom button into the playback controls.
Step 1: Define a Unique Action ID
Create a constant identifier in your VideoPlayerGlue subclass or companion object to prevent collisions with existing actions (which typically use IDs below 1000).
public class CustomVideoPlayerGlue extends VideoPlayerGlue {
private static final int ACTION_LIKE = 1001;
private static final int ACTION_DOWNLOAD = 1002;
}
Step 2: Create the UI Button
Instantiate a PlaybackControlsRow.Action within the method that builds your control row, typically inside VideoPlayerGlue or a subclass constructor. You must provide the action ID, a label string, and a drawable icon.
Drawable likeIcon = context.getResources().getDrawable(R.drawable.ic_like, null);
PlaybackControlsRow.Action likeAction = new PlaybackControlsRow.Action(
ACTION_LIKE,
context.getString(R.string.action_like),
likeIcon
);
controlsRow.addAction(likeAction);
Store the string resource in smarttubetv/src/main/res/values/strings.xml and the vector drawable in smarttubetv/src/main/res/drawable/ic_like.xml.
Step 3: Handle the Click Event
Extend the PlayerActionListener inner class in PlaybackFragment.java to intercept your custom action ID within the onAction method.
@Override
public void onAction(int actionId, int actionIndex) {
if (actionId == ACTION_LIKE) {
mPlaybackPresenter.toggleLikeStatus();
} else if (actionId == ACTION_DOWNLOAD) {
mPlaybackPresenter.startDownload();
} else {
// Delegate to default handler for standard actions
mPlaybackPresenter.onButtonClicked(actionId, actionIndex);
}
}
Step 4: Handle Long-Press Events (Optional)
For secondary functionality—such as opening a settings menu—implement the long-press handler in the same listener class.
@Override
public void onLongAction(int actionId, int actionIndex) {
if (actionId == ACTION_LIKE) {
mPlaybackPresenter.showLikeOptions();
} else {
mPlaybackPresenter.onButtonLongClicked(actionId, actionIndex);
}
}
Step 5: Update UI Resources
Ensure all visual assets meet Android TV Leanback specifications:
- Add vector drawables at
smarttubetv/src/main/res/drawable/using 24dp base size - Define action labels in
smarttubetv/src/main/res/values/strings.xmlwith descriptive, localization-ready keys - Rebuild the project—the new buttons will render immediately in the playback overlay without modifying the presenter logic
Summary
- Player Actions in SmartTube connect user interface controls to playback logic through the
VideoPlayerGlue.OnActionClickedListenerinterface - The
PlayerActionListenerinner class inPlaybackFragment.javaserves as the exclusive bridge betweenVideoPlayerGlueandPlaybackPresenter - Adding custom actions requires defining a unique integer ID, instantiating a
PlaybackControlsRow.Action, and extending theonAction()handler - Long-press interactions are supported through the separate
onLongAction()callback method - All UI resources—including icons and labels—must be stored in the module's
resdirectory following Android TV Leanback guidelines
Frequently Asked Questions
What is the role of VideoPlayerGlue in SmartTube?
VideoPlayerGlue is the controller class that manages the playback overlay UI, instantiates the PlaybackControlsRow, and dispatches user interactions to the OnActionClickedListener. It abstracts the Android Leanback library's complexity from the fragment layer, allowing PlaybackFragment to focus on business logic rather than view management.
How do I handle long-press actions for custom buttons?
Implement the onLongAction(int actionId, int actionIndex) method within your PlayerActionListener implementation. This callback triggers when a user holds the select button on a remote control for approximately one second, enabling secondary functionality like "Add to Playlist" or "Show Details" without cluttering the primary interface.
Where are action labels and icons defined in the SmartTube source?
Action labels are stored as string resources in smarttubetv/src/main/res/values/strings.xml, while icons are placed as vector drawables in smarttubetv/src/main/res/drawable/. The VideoPlayerGlue constructor loads these resources when building the PlaybackControlsRow.Action objects, ensuring proper theming and localization support across different device configurations.
Can I remove or modify existing default player actions?
Yes, you can modify the default control set by subclassing VideoPlayerGlue and overriding the method that constructs the PlaybackControlsRow. Remove specific addAction() calls for buttons you wish to hide, or replace the drawable resources in the res/drawable folder to change icons without altering Java code.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →