Skip to content

Mobile Examples ​

The infillion-ads-android-examples repository contains two phone and tablet apps with the same integration of TrueX and IDVx ads into a Media3 player - one in Kotlin (kotlin-mobile-app) and one in Java (java-mobile-app):

ExampleAd sourceMidroll behavior
Manual CSAIVAST tags from a bundled JSON ad breakThe app schedules and plays the ad pod itself

Both apps have the same screens, flow, and sample configuration; only the language differs. The flow, VAST parsing, and renderer handling are the same as the Manual CSAI TV example - only the screen layout and the touch and lifecycle handling are mobile-specific. Each example has its own player, ad, and TruexAdRenderer code on purpose, so you can copy one package and read it from top to bottom.

Running the Apps ​

Requirements:

  • Android Studio with JDK 17
  • Android SDK 35
  • A phone or tablet device or emulator running API 28 or newer

Open the repository in Android Studio and run the kotlin-mobile-app or java-mobile-app configuration, or build them from the command line:

bash
./gradlew assembleDebug

Then install kotlin-mobile-app/build/outputs/apk/debug/kotlin-mobile-app-debug.apk or java-mobile-app/build/outputs/apk/debug/java-mobile-app-debug.apk on the device. The two apps have different application IDs, so both can be installed side by side. Tap an example card; the example shows its current state (content, linear ad, interactive ad, errors) in a status panel, and logs it with the InfillionAdsExamples tag.

Test IP parameter

The sample VAST tags include &ip=158.106.195.210, the IP of the Infillion NYC office. The TrueX ad server serves ads in the US and Canada only, and this parameter lets teams and CI runners outside those regions get filled test ads. Do not use it in production.

Manual CSAI ​

Use this example when your app or your own ad layer decides when an ad break starts and which ads it contains.

  1. Before content starts, the app fetches each Infillion VAST tag from the ad break fixture (manual_ad_break.json) and resolves its adParameters - the truex companion first, then <AdParameters>, as described in Integration Flow.
  2. At the midroll, the app saves the content position, turns off the touch controls, and plays the ads of the pod one by one in the same player.
  3. For a TrueX or IDVx ad, the app does not play the placeholder video: it stops and hides the player, hides the toolbar and status panel, and starts TruexAdRenderer in the overlay container.
  4. On AD_COMPLETED after AD_FREE_POD, the app ends the pod and returns to the content. Otherwise (opt-out, error, no ads, or IDVx) the next ad in the pod starts.
  5. After the pod, the content is restored at its saved position and the touch controls come back.
kotlin
private fun playCurrentAd() {
    val ad = currentAdOrNull()
    if (ad == null) {
        finishAdBreak("Ad pod complete")
        return
    }
    // The host owns playback, so interactive ads skip their placeholder video and start the renderer directly.
    if (ad.type != ManualAdType.LINEAR) {
        // Stop loading the paused media so it can't report errors while the renderer runs.
        player.stop()
        showInteractiveAd(ad)
        return
    }
    binding.playerView.visibility = View.VISIBLE
    player.setMediaItem(MediaItem.fromUri(ad.mediaUrl))
    player.prepare()
    player.play()
}
java
private void playCurrentAd() {
    ManualAdBreak.Ad ad = currentAdOrNull();
    if (ad == null) {
        finishAdBreak("Ad pod complete");
        return;
    }
    // The host owns playback, so interactive ads skip their placeholder video and start the renderer directly.
    if (ad.type != ManualAdBreak.AdType.LINEAR) {
        // Stop loading the paused media so it can't report errors while the renderer runs.
        player.stop();
        showInteractiveAd(ad);
        return;
    }
    playerView.setVisibility(View.VISIBLE);
    player.setMediaItem(MediaItem.fromUri(ad.mediaUrl));
    player.prepare();
    player.play();
}

Files:

Mobile-Specific Notes ​

  • POPUP_WEBSITE is fired on mobile only. The examples open the URL with Intent.ACTION_VIEW; the activity's onPause() / onResume() pause and resume the renderer while the browser is in front.
  • USER_CANCEL_STREAM (Back on the choice card) closes the player screen.
  • Forward onPause / onResume to the renderer while it is active - see Activity Lifecycle. Without a renderer, resume the player only if it was playing before the pause, so a pause the viewer made with the touch controls is kept.
  • If the activity is paused while the VAST tags are loading, the examples start content in onResume() instead of playing in the background, and they drop the result if the activity was destroyed in the meantime.
  • The player activity handles orientation and screen-size changes itself (android:configChanges), so rotating the device does not recreate the player or the renderer during an ad.
kotlin
override fun onResume() {
    super.onResume()
    if (startContentOnResume) {
        startContentOnResume = false
        startContent()
    } else if (truexAdRenderer != null) {
        truexAdRenderer?.resume()
    } else if (playWhenReadyBeforePause) {
        // Resume only what was playing before; keep a pause the viewer made with the touch controls.
        player.play()
    }
}

override fun onPause() {
    if (truexAdRenderer != null) {
        truexAdRenderer?.pause()
    }
    playWhenReadyBeforePause = player.playWhenReady
    player.pause()
    super.onPause()
}
java
@Override
protected void onResume() {
    super.onResume();
    if (startContentOnResume) {
        startContentOnResume = false;
        startContent();
    } else if (truexAdRenderer != null) {
        truexAdRenderer.resume();
    } else if (playWhenReadyBeforePause) {
        // Resume only what was playing before; keep a pause the viewer made with the touch controls.
        player.play();
    }
}

@Override
protected void onPause() {
    if (truexAdRenderer != null) {
        truexAdRenderer.pause();
    }
    playWhenReadyBeforePause = player.getPlayWhenReady();
    player.pause();
    super.onPause();
}

Integration documentation for Infillion Ads