Custom UI with the IMA SDK for Android

This guide shows how to implement your own custom UI using the IMA SDK for Android. To do so, you need to disable the default UI, set up a new custom UI, and then populate the new UI with ad information obtained from the SDK.

Disable the ad UI

To show a custom UI, first you must disable the default ad UI. To do this, call AdsRenderingSettings.setDisableUi() and then pass the AdsRenderingSettings to AdsManager.init():

MyActivity.java

ImaSdkFactory mSdkFactory = ImaSdkFactory.getInstance();
AdsManager mAdsManager;

@Override
public void onAdsManagerLoaded(AdsManagerLoadedEvent adsManagerLoadedEvent) {
    mAdsManager = adsManagerLoadedEvent.getAdsManager();

    ...
    AdsRenderingSettings settings = mSdkFactory.createAdsRenderingSettings();
    settings.setDisableUi(true);
    mAdsManager.init(settings);
}

Afterwards, whenever you need to decide whether to show your custom UI, check to see if there is an ad and call Ad.isUiDisabled() to check that the default ad UI has been disabled.

Show custom UI

Once the default UI has been disabled, the next step is to show a custom ad UI. For this example, add a new RelativeLayout to your existing video player layout, then show this layout when an ad is playing and hide it when no ads are playing.

Add the following to the fragment layout file:

fragment_video.xml

<com.google.ads.interactivemedia.v3.samples.samplevideoplayer.SampleVideoPlayer
    android:id="@+id/sampleVideoPlayer"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
<RelativeLayout
        android:id="@+id/customUi"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible">
                <TextView
                    android:id="@+id/adCounter"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@android:color/holo_green_light"
                    android:layout_alignParentTop="true"
                    android:layout_alignParentLeft="true"
                    android:text="@string/ad_counter" />
                <Button
                  android:id="@+id/learnMoreButton"
                  android:background="@android:color/holo_green_light"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_alignParentTop="true"
                  android:text="@string/learn_more"
                  android:layout_alignParentRight="true" />
                <Button
                  android:id="@+id/skipButton"
                  android:background="@android:color/holo_green_light"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_alignParentBottom="true"
                  android:text="@string/skip_ad"
                  android:enabled="false"
                  android:layout_alignParentRight="true" />
</RelativeLayout>

Then add the code to use the custom UI to the Activity. To update the UI, create a timer Handler and a Runnable that runs on it.

MyActivity.java

// The view containing the custom UI.
private View mCustomUi;
// The timer handler.
private Handler mTimerHandler = new Handler();

// The Runnable that runs your custom UI update loop.
private Runnable mTimerRunnable = new Runnable() {
    @Override
    public void run() {
        updateCustomUi();
        mTimerHandler.postDelayed(this, 500);
    }
};

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
...
    mCustomUi = rootView.findViewById(R.id.customUi);
    mAdCounterUi = (TextView) rootView.findViewById(R.id.adCounter);
}

@Override
public void onAdEvent(AdEvent adEvent) {
    ...
    switch (adEvent.getType()) {
        ...
            case STARTED:
            // Start your update loop.
            mTimerHandler.post(mTimerRunnable);
            Break;
                ...
        case COMPLETED:
            mCustomUi.setVisibility(View.INVISIBLE);
            mTimerHandler.removeCallbacks(mTimerRunnable);
            ...
    }
}

@Override
public void onPause() {
...
    // Stop ad UI update loop.
    mTimerHandler.removeCallbacks(mTimerRunnable);
}

@Override
Public void onResume() {
...
    // Start ad UI update loop.
    mTimerHandler.post(mTimerRunnable);
}

Ad counter and skip button

Now define the updateCustomUi() function to populate the UI with ad information. The details vary by ad format, but you commonly include the ad counter and a skip button or skip counter if the ad is skippable. Add the following:

MyActivity.java

private void updateCustomUi() {
    // Runs from the update loop to update the custom UI.
    Ad ad = mAdsManager.getCurrentAd();
    if (ad != null && ad.isUiDisabled()) {
        // Show the UI.
        Log.i(LOGTAG, "UI disabled, show custom UI!");
        AdPodInfo podInfo = ad.getAdPodInfo();
        VideoProgressUpdate update = mAdsManager.getAdProgress();
        SimpleDateFormat format = new SimpleDateFormat("mm:ss", Locale.US);

        // Handle ad counter.
        String adProgress = format.format(
                (update.getDuration() - update.getCurrentTime()) * 1000);
        String adUiString = String.format(
                Locale.US, "Ad %d of %d (%s)", podInfo.getAdPosition(),
                podInfo.getTotalAds(), adProgress);
        mAdCounterUi.setText(adUiString);

        // Handle skippable ads.
        if (ad.isSkippable()) {
            if (update.getCurrentTime() >= ad.getSkipTimeOffset()) {
                // Allow skipping.
                mSkipButton.setText(getString(R.string.skip_ad));
                mSkipButton.setEnabled(true);
            } else {
                String skipString = String.format(
                        Locale.US, "You can skip this ad in %d",
                        (int) (ad.getSkipTimeOffset() -
                                update.getCurrentTime()));
                mSkipButton.setText(skipString);
                mSkipButton.setEnabled(false);
            }
            mSkipButton.setVisibility(View.VISIBLE);
        } else {
            mSkipButton.setVisibility(View.INVISIBLE);
        }
        mCustomUi.setVisibility(View.VISIBLE);
        mCustomUi.bringToFront();
    } else {
        // Hide the UI.
        mCustomUi.setVisibility(View.INVISIBLE);
        mTimerHandler.removeCallbacks(mTimerRunnable);
    }
}

In the above code, after checking to see if there is an ad and calling Ad.isUiDisabled() to check that the default ad UI has been disabled, call Ad.getAdPodInfo() and AdsManager.getAdProgress() to find the ad's position in the pod and the ad's progress. For skippable ads, show a skip counter if you can't yet skip the ad; otherwise, show a skip button. Here's a summary of common ad information and associated calls:

Information Call
Current ad in pod Ad.getAdPodInfo().getAdPosition()
Total ads in pod Ad.getPodInfo().getTotalAds()
Is ad skippable Ad.isSkippable()
Seconds until ad can be skipped Ad.getSkipTimeOffset() - AdsManager.getAdProgress().getCurrentTime()
Seconds remaining in ad (AdsManager.getAdProgress().getDuration() - AdsManager.getAdProgress().getCurrentTime()) * 1000

Clicking on the Skip Ad button should skip the ad, so set that up in addition to the Learn More button:

MyActivity.java

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
...
mCustomUi = rootView.findViewById(R.id.customUi);
mAdCounterUi = (TextView) rootView.findViewById(R.id.adCounter);

// Set up the 'learn more' button handler for the custom UI.
mLearnMoreButton = (Button) rootView.findViewById(R.id.learnMoreButton);
mLearnMoreButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        // Only works if the UI has been disabled.
        mAdsManager.clicked();
    }
});

// Set up the skip button handler for the custom UI.
mSkipButton = (Button) rootView.findViewById(R.id.skipButton);
mSkipButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        mAdsManager.skip();
    }
});

The UI must be disabled for AdsManager.clicked() to work.

Troubleshooting

Do you have a sample tag that is enabled for disabling ad UI?
You can copy the URL of this sample tag and paste it into your IMA implementation.
I can't disable the default UI.
Check to make sure that you call AdsRenderingSettings.setDisableUi() and pass it to the AdsManager. Check to see that Ad.isUiDisabled() returns true. In addition, your network must be enabled in Ad Manager to disable an ad UI. If you are enabled, your VAST contains an Extension that looks like:
<Extension type="uiSettings">
<UiHideable>1</UiHideable>
</Extension>
If you are still having trouble, check with your account manager to confirm that you are enabled. Some ad types require a specific UI; these ads return with a <UiHideable> value of 0. If you encounter this, your trafficking team will need to make changes to ensure that these ad types do not serve.