On Android TV, the pause ad format lets you show an ad during the time the user pauses the video stream.
To prevent ad latency, Interactive Media Ads (IMA) SDK requests the pause ad after the user pauses the content video. After receiving the ad response, IMA SDK displays the pause ad after a one-second delay.
This guide covers integrating pause ads into your Video on Demand (VOD) streams using Google Dynamic Ad Insertion (DAI) SDK. You can only request pause ads for VOD streams.
Prerequisites
Before you continue, you must have IMA SDK for DAI version 3.38.0 or
later. For details, see
Set up IMA SDK for DAI.
Step 1: Prepare the UI layout
To display ads over your paused video, provide a ViewGroup object as a
pause ad container. Do the following:
- Keep the pause ads container object in the view hierarchy for the duration of the stream. This process lets IMA SDK populate the container with ad content.
Toggle the pause ads container's visibility accordingly to your video player's state.
Follow these sizing guidelines:
- Account for TV safe areas by setting the video player view to fill the screen. Leave a 5% to 10% padding on the edges of the TV safe area.
- Set the ad display container and the pause ad container to the same size as the video player view.
Arrange your UI elements in the following order:
- Video layer: plays the content stream.
- Stream display container: renders the ad break UI elements during the content stream playback.
- Pause ad container: displays the ads when the content stream is paused. When the user closes the ad or resumes content playback, hide this layer.
For IMA SDK for DAI to measure ad view, make sure that video controls or UI elements don't obstruct the ad display and pause ad containers.
The following example sets the video layer, stream display container, and pause ad container:
<!-- Example layout configuration -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Video layer: plays the content stream. -->
<androidx.media3.ui.PlayerView
android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Stream display container: renders the ad break UI elements during the
content stream playback. -->
<FrameLayout
android:id="@+id/streamDisplayContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Pause ad container: displays the ads when the content stream is paused.
Initialize this container to invisible, not gone. This process lets
Android measure the dimensions during layout, while keeping the layout
hidden during video playback. -->
<FrameLayout
android:id="@+id/pauseAdContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</RelativeLayout>
Step 2: Create and set the ad slot size
Before the user starts playing the video stream, create an AdSlot object and
set the size to the density-independent pixel (dp) size of the pause ad
container. IMA SDK uses the ad slot size to request ads every time the user
pauses the current video stream. If you provide an incorrect size, the pause ad
might fail to render.
The following example creates an AdSlot object and sets the object size in dp
relative to the pause ad container:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
ViewGroup pauseAdContainer = findViewById(R.id.pauseAdContainer);
// Instantiate a persistent AdSlot for pause ads. This reusable instance is
// sufficient for the duration of the Activity's lifecycle.
AdSlot pauseAdSlot = ImaSdkFactory.getInstance().createAdSlot(pauseAdContainer);
setAdSlotSizeInDp(pauseAdSlot);
}
/**
* Configures an AdSlot's dimensions using its container view's measurements
* converted from raw pixels to DPs.
*/
private void setAdSlotSizeInDp(AdSlot adSlot) {
View container = adSlot.getContainer();
if (container != null) {
// Get the device's screen density (e.g., 2.0 for a 1080p screen)
float density = getResources().getDisplayMetrics().density;
// Convert the view's raw pixels into DPs by dividing by density
int width = (int) (container.getWidth() / density);
int height = (int) (container.getHeight() / density);
adSlot.setSize(width, height);
}
}
If your app resizes the video player during playback, such as an app config
change in the manifest, TV rotation, or Picture-in-Picture mode, you must call
the pauseAdSlot.setSize method again with the updated dimensions. This
process makes sure IMA SDK requests the correct ad size.
Step 3: Register the pause ad slot
When creating your stream display container, register the pause ad slot you
created. Before registering the AdSlot object, make sure that you've
configured the width and height greater than zero. This process informs IMA
SDK where to render the pause ad when a pause occurs.
The following example registers the pause ad slot:
@Override
public void onCreate(Bundle savedInstanceState) {
// ...
// 1. Configure the ad slot dimensions before setting it on the display
// container.
setAdSlotSizeInDp(pauseAdSlot);
// ...
// Assign the stream display container view and assume videoStreamPlayer is
// created
ViewGroup streamDisplayContainer = findViewById(R.id.streamDisplayContainer);
StreamDisplayContainer displayContainer =
ImaSdkFactory.createStreamDisplayContainer(
streamDisplayContainer, videoStreamPlayer);
// 2. Register the pause ad slot.
// Before you call setPauseAdSlot, make sure the value from
// pauseAdSlot.getWidth() and pauseAdSlot.getHeight() are greater than zero.
displayContainer.setPauseAdSlot(pauseAdSlot);
// Continue to initialize your AdsLoader.
AdsLoader adsLoader =
sdkFactory.createAdsLoader(context, imaSdkSettings, displayContainer);
}
Step 4: Sync playback state
To pause the ad and resume content, invoke the onResume callback method on
the
VideoStreamPlayer.VideoStreamPlayerCallback
interface. Make sure actions, such as pressing the play or back buttons,
invoke your player to resume playback. This process invokes the callback to
dismiss the ad.
If you are using Media3 ExoPlayer, you can override the playback behavior
using a
ForwardingPlayer
class.
The following example signals to IMA SDK that content has paused and resumed:
playerView.setPlayer(new ForwardingPlayer(player) {
@Override
public void pause() {
super.pause();
// Signal IMA that content has paused
if (videoStreamPlayerCallback != null) {
videoStreamPlayerCallback.onPause();
}
}
@Override
public void play() {
super.play();
// Signal IMA that content has resumed
if (videoStreamPlayerCallback != null) {
videoStreamPlayerCallback.onResume();
}
}
});
IMA SDK doesn't automatically detect when the user pauses or resumes the content. Your app is responsible for handling these video player events and forwarding the events to IMA SDK.
You must ensure that your implementation of the
VideoStreamPlayer
interface notifies IMA SDK by invoking the onPause and onResume
callbacks. For details, see
Integrate the IMA DAI SDK.
Step 5: (Optional) Handle ad events
When a pause ad loads is ready to display, IMA SDK emits a PAUSE_AD_READY
event. You can listen for this event using the
AdEventListener
interface. This process handles specific UI treatments, such as hiding your
video player controls and managing Directional Pad (D-pad) focus on Android TV.
The following example checks if the pause ad slot is ready and filled:
@Override
public void onAdEvent(AdEvent event) {
switch (event.getType()) {
case PAUSE_AD_READY:
// The ad slot is ready; perform UI preparations here
if (pauseAdSlot.getContainer() != null) {
// Example: For Android TV, move D-pad focus to the ad
pauseAdSlot.getContainer().requestFocus();
}
break;
case STARTED:
// Check if the pause ad slot was the one that got filled
if (pauseAdSlot.isFilled()) {
Log.i("IMA", "The Pause Ad Slot is currently filled and displaying an ad.");
}
break;
default:
break;
}
}
Step 6: Clean up ad resources
To clean up ad resources, do the following:
- When a user stops watching a stream or an error occurs, destroy the
stream manager. To stop stream monitoring, call the
streamManager.destroymethod. - When a user starts watching a new stream, create an
AdSlotobject using the same pause ad container across streaming sessions. - When a user transitions away from the video playing activity, call the
streamManager.destroyandadsLoader.releasemethods.
The following example cleans up resources during stream transitions and activity destruction:
/**
* Cleans up the previous stream manager and creates a fresh ad slot when
* switching to a new VOD stream or upon stream completion.
*/
public void onSwitchStream() {
if (streamManager != null) {
// Destroying the stream manager cleans up stream-specific resources,
// including the pause ad slot associated with this stream.
streamManager.destroy();
streamManager = null;
}
// 1. Reuse the existing pause ad container from your view hierarchy
ViewGroup pauseAdContainer = findViewById(R.id.pauseAdContainer);
// 2. Instantiate a fresh AdSlot object for the upcoming VOD stream
pauseAdSlot = ImaSdkFactory.getInstance().createAdSlot(pauseAdContainer);
setAdSlotSizeInDp(pauseAdSlot);
// 3. Re-create or re-configure your StreamDisplayContainer with the new slot
displayContainer = ImaSdkFactory.createStreamDisplayContainer(streamDisplayContainer, videoStreamPlayer);
displayContainer.setPauseAdSlot(pauseAdSlot);
// Continue requesting ads for the new stream using your persistent AdsLoader
}
@Override
public void onDestroy() {
// Release ad resources to prevent memory leaks during activity destruction
if (streamManager != null) {
streamManager.destroy();
streamManager = null;
}
if (adsLoader != null) {
adsLoader.release();
adsLoader = null;
}
super.onDestroy();
}
Verify user interactions with pause ads
To verify that your pause ads setup is successful, check for the following behavior in your app:
- Ad display: When you pause the video stream, the pause ad container displays an ad over the paused content in the TV safe area. For details, see Overscan.
- Ad dismissal: When you press standard remote control buttons such as Play or Back, your app resumes playback and signals IMA SDK to dismiss the ad.