<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://nielsentest.mywikis.net/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=VenkataDodla</id>
	<title>Engineering Client Portal - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://nielsentest.mywikis.net/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=VenkataDodla"/>
	<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/wiki/Special:Contributions/VenkataDodla"/>
	<updated>2026-07-25T20:47:22Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.5</generator>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7121</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7121"/>
		<updated>2026-06-19T11:51:48Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1: Download the package here */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integration into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1:''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2:''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3:''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, Emulator Setup and Install the AndroidTV ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [https://d280mermnrvzn0.cloudfront.net/NielsenAndroidTVSampleVideoPlayerApp.zip here] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7120</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7120"/>
		<updated>2026-06-19T09:52:24Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Sample App: Download, Build, Emulator Setup, and Install the AndroidTV */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integration into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1:''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2:''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3:''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, Emulator Setup and Install the AndroidTV ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7119</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7119"/>
		<updated>2026-06-18T12:55:50Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 2: Configuring Android AppSDK Initialization Parameters */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integration into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1:''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2:''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3:''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, Emulator Setup, and Install the AndroidTV ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7118</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7118"/>
		<updated>2026-06-18T12:47:16Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR/DTVR) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integration into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1:''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2:''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3:''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, Emulator Setup, and Install the AndroidTV ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7117</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7117"/>
		<updated>2026-06-18T12:45:47Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Sample App: Download, Build, and Emulator Setup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integration into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, Emulator Setup, and Install the AndroidTV ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7116</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7116"/>
		<updated>2026-06-18T12:44:27Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Open up Android TV Emulator */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integration into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7115</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7115"/>
		<updated>2026-06-18T12:41:28Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Android AppSDK Integrations into Android TV App */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integration into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7114</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7114"/>
		<updated>2026-06-18T12:41:08Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR/DTVR) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7113</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7113"/>
		<updated>2026-06-18T12:34:04Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When need to check the current SDK version.&lt;br /&gt;
|-&lt;br /&gt;
|getOptOutStatus()&lt;br /&gt;
|Retrieve the Opt-Out or Opt-In state.&lt;br /&gt;
|When need to know the Opt-Out or Opt-In status.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7112</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7112"/>
		<updated>2026-06-18T12:27:54Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 7: Opting out of AppSDK measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement.&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to fetch the Nielsen opt-out web page URL&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Below code snippet is used to supply the response message captured from opt-out webpage to the AppSDK&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 8: Closing the AppSDK instance ====&lt;br /&gt;
Kindly call this API whenever the application is closing or before creating another AppSDK instance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7111</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7111"/>
		<updated>2026-06-18T12:18:34Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR/DTVR) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7110</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7110"/>
		<updated>2026-06-18T12:16:32Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR Video) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required for DCR Video]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // type of ad load i.e 1=linear, 2=dynamic [required for DTVR]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A comprehensive list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content. This is needed for DCR Video measurement.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.3''' The following example demonstrates the passing of Nielsen ID3 tags to AppSDK during the playback of content. This is needed for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
The following example code demonstrates the extraction of ID3 metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 5: '''Stopping the AppSDK Measurement (DCR/DTVR)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the pausing of AppSDK measurement whenever the video playback is paused or when switching between ad to content or content to ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snipped demonstrates the completion of AppSDK measurement in case of DCR Video typically used when content playback is completed. This is triggered 1) at the end of the content stream 2) if the user switches to another piece of content&lt;br /&gt;
&lt;br /&gt;
Note: In case of DTVR this acts as an interrupt similar to stop() api&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 6: Measuring Non Video Content (DCR Static) ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the measurement of static screens/pages by sending the metadata of the static page/screen to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following code snippet demonstrates the completion of static screens/pages measurement by invoking staticEnd() on AppSDK which will finalise the screen/page viewed time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 7: Opting out of AppSDK measurement ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7109</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7109"/>
		<updated>2026-06-18T11:39:44Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR Video) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR Video)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A detailed list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7108</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7108"/>
		<updated>2026-06-18T11:38:17Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR Video) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR Video)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A detailed list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7107</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7107"/>
		<updated>2026-06-18T11:37:47Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR Video) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR Video)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A detailed list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7106</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7106"/>
		<updated>2026-06-18T11:36:24Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR Video) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR Video)''' ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A detailed list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7105</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7105"/>
		<updated>2026-06-18T11:35:44Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step 4: Starting the AppSDK Measurement (DCR Video) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR Video)''' ====&lt;br /&gt;
The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
'''4.1''' The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A detailed list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
&lt;br /&gt;
'''4.2''' The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7104</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7104"/>
		<updated>2026-06-18T11:31:15Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Step1: Adding Nielsen AppSDK Dependency */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialization, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step 1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 2: Configuring Android AppSDK Initialization Parameters ====&lt;br /&gt;
Build the JSON object by providing required values (App ID and Debug level).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Step 3: Initializing Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager (Refer NielsenSdkManager.kt from the sample app source) and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''Step 4: Starting the AppSDK Measurement (DCR Video)''' ====&lt;br /&gt;
The following example code demonstrates the invocation of play() and loadMetadata() api calls whenever video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // name of the episode [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // type of ad load i.e 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)  // pass descriptive stream information through this parameter&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)        // Video URL value for the content that is being played&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A detailed list of parameters which can be passed to AppSDK are listed here - [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()]                  &lt;br /&gt;
                  &lt;br /&gt;
The following example demonstrates the passing of playhead positions to AppSDK every one second during the playback of content.                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7103</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7103"/>
		<updated>2026-06-18T11:04:15Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Android AppSDK Integrations into Android TV App */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
The below steps cover the complete integration process including AppSDK initialisation, metadata ingestion, playhead tracking, ID3 tag processing and user opt-out/opt-in implementation.&lt;br /&gt;
&lt;br /&gt;
==== Step1: Adding Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the Application module within the build.gradle file.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add the below dependencies.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7102</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7102"/>
		<updated>2026-06-18T10:49:21Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Open up Android TV Emulator */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7101</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7101"/>
		<updated>2026-06-18T10:47:42Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.8: User Opt-Out Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7100</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7100"/>
		<updated>2026-06-18T10:46:59Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.7: DTVR - ID3 Tag Processing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7099</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7099"/>
		<updated>2026-06-18T10:46:43Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.6: DCR Static - Non Video Content Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7098</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7098"/>
		<updated>2026-06-18T10:46:14Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.5: DCR Video - Stop/End Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7097</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7097"/>
		<updated>2026-06-18T10:45:50Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.4: DCR Video - Start Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7096</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7096"/>
		<updated>2026-06-18T10:45:22Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.1: Add Nielsen AppSDK Dependency */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7095</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7095"/>
		<updated>2026-06-18T10:44:38Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.1: Add Nielsen AppSDK Dependency */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7094</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7094"/>
		<updated>2026-06-18T10:44:18Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.8: User Opt-Out Implementation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                                                                                                                                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7093</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7093"/>
		<updated>2026-06-18T10:43:42Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.5: DCR Video - Stop/End Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                                                      &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2: Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7092</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7092"/>
		<updated>2026-06-18T10:40:56Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7091</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7091"/>
		<updated>2026-06-18T10:39:43Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.      &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.      &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7090</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7090"/>
		<updated>2026-06-18T10:38:45Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7089</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7089"/>
		<updated>2026-06-18T10:38:21Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7088</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7088"/>
		<updated>2026-06-17T10:20:48Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.4: DCR Video - Start Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SDK should receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7087</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7087"/>
		<updated>2026-06-17T09:04:40Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.6: DCR Static - Non Video Content Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7086</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7086"/>
		<updated>2026-06-17T09:03:41Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.4: DCR Video - Start Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7085</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7085"/>
		<updated>2026-06-17T09:00:07Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;     &lt;br /&gt;
&lt;br /&gt;
Receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7084</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7084"/>
		<updated>2026-06-17T08:59:45Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7083</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7083"/>
		<updated>2026-06-17T08:59:19Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.4: DCR Video - Start Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call [https://engineeringportal.nielsen.com/wiki/play() play()] and [https://engineeringportal.nielsen.com/wiki/loadMetadata() loadMetadata()] when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Receive a [https://engineeringportal.nielsen.com/wiki/setPlayheadPosition() playhead position] update every one second on the playback of content. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7082</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7082"/>
		<updated>2026-06-17T08:50:30Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Receive a playhead position update every one second on the playback of content. The playhead position is the current location of the player from the beginning of the asset in seconds; When streaming live content, the playhead position passed to the AppSDK is the current Unix timestamp.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7081</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7081"/>
		<updated>2026-06-17T08:38:35Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.7: DTVR - ID3 Tag Processing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Receive a playhead position update every one second on the playback of content. The playhead position is the current location of the player from the beginning of the asset in seconds; When streaming live content, the playhead position passed to the AppSDK is the current Unix timestamp (seconds since Jan-1-1970 UTC).&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7080</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7080"/>
		<updated>2026-06-17T08:37:43Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: update setPlayheadp position&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Receive a playhead position update every one second on the playback of content. The playhead position is the current location of the player from the beginning of the asset in seconds; When streaming live content, the playhead position passed to the AppSDK is the current Unix timestamp (seconds since Jan-1-1970 UTC).&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
This sample code for extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7079</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7079"/>
		<updated>2026-06-17T08:32:45Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.9: Close AppSDK API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Reporting playhead position every 1 second during active playback.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
This sample code for extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Call this API to close the SDK instance on when App is closing.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7078</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7078"/>
		<updated>2026-06-17T08:26:21Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: updated content&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Reporting playhead position every 1 second during active playback.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Used when playback is paused and when switching between ad and content or content and ad.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Used to send the metadata for the static page.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used with DCR Static duration in between loadMetadata calls for static content when section name is the same but a new static view event and duration measurement restart is desired.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
This sample code for extracting the ID3 Metadata events from ExoPlayer.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to send the ID3 metadata to AppSDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Used to fetch the Nielsen opt-out web page URL.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Used to supply the response message from opt-out webpage to the SDK.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Call this API to retrieve the Opt-Out or Opt-In state. &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Close SDK (App Exit Only) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7077</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7077"/>
		<updated>2026-06-17T08:04:22Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: sub point 1.6 updated&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Reporting playhead position every 1 second during active playback.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Pause Playback :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Content Session (Video End) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Start Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Listen for ID3 Metadata (ExoPlayer) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Send ID3 Tags to Nielsen SDK :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Get Opt-Out URL :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Handle Opt-Out Response :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Check Opt-Out Status : &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Close SDK (App Exit Only) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7076</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7076"/>
		<updated>2026-06-17T07:56:33Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: install the apk section has updated&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Reporting playhead position every 1 second during active playback.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Pause Playback :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Content Session (Video End) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1.6: DCR Static - Non Video Content Measurement&lt;br /&gt;
&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Start Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Listen for ID3 Metadata (ExoPlayer) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Send ID3 Tags to Nielsen SDK :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Get Opt-Out URL :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Handle Opt-Out Response :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Check Opt-Out Status : &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Close SDK (App Exit Only) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
==== 3.4: Install the AndroidTV sample video player App ====&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7075</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7075"/>
		<updated>2026-06-17T07:51:37Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.10: Android AppSDK Getter Methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Reporting playhead position every 1 second during active playback.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Pause Playback :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Content Session (Video End) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1.6: DCR Static - Non Video Content Measurement&lt;br /&gt;
&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Start Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Listen for ID3 Metadata (ExoPlayer) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Send ID3 Tags to Nielsen SDK :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Get Opt-Out URL :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Handle Opt-Out Response :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Check Opt-Out Status : &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Close SDK (App Exit Only) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
=== Install the AndroidTV sample video player App ===&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7074</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7074"/>
		<updated>2026-06-17T07:49:49Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* Quick Reference - Android AppSDK Methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Reporting playhead position every 1 second during active playback.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Pause Playback :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Content Session (Video End) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1.6: DCR Static - Non Video Content Measurement&lt;br /&gt;
&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Start Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Listen for ID3 Metadata (ExoPlayer) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Send ID3 Tags to Nielsen SDK :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Get Opt-Out URL :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Handle Opt-Out Response :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Check Opt-Out Status : &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Close SDK (App Exit Only) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.10: Android AppSDK Getter Methods ====&lt;br /&gt;
These methods provide information like Android AppSDK Version, NielsenId details.&lt;br /&gt;
&lt;br /&gt;
Get Nielsen ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getNielsenId(): String = mAppSdk?.nielsenId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get Device ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getDeviceId(): String = mAppSdk?.deviceId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get Demographic ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getDemographicId(): String = mAppSdk?.demographicId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get SDK Meter Version :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getMeterVersion(): String = AppSdk.getMeterVersion()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|-&lt;br /&gt;
|getNielsenId()&lt;br /&gt;
|Retrieve Nielsen ID&lt;br /&gt;
|When you need to access the unique Nielsen identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDeviceId()&lt;br /&gt;
|Retrieve Device ID&lt;br /&gt;
|When you need to access the unique device identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getDemographicId()&lt;br /&gt;
|Retrieve Demographic ID&lt;br /&gt;
|When you need to access the AppSDK session identifier.&lt;br /&gt;
|-&lt;br /&gt;
|getMeterVersion()&lt;br /&gt;
|Retrieve SDK Meter Version&lt;br /&gt;
|When you need to check the current SDK version.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
=== Install the AndroidTV sample video player App ===&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7073</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7073"/>
		<updated>2026-06-17T07:34:40Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: /* 1.4: DCR Video - Start Measurement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adloadtype&amp;quot;, &amp;quot;2&amp;quot;)               // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Reporting playhead position every 1 second during active playback.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Pause Playback :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Content Session (Video End) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1.6: DCR Static - Non Video Content Measurement&lt;br /&gt;
&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Start Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Listen for ID3 Metadata (ExoPlayer) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Send ID3 Tags to Nielsen SDK :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Get Opt-Out URL :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Handle Opt-Out Response :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Check Opt-Out Status : &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Close AppSDK API ====&lt;br /&gt;
Close SDK (App Exit Only) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.10: Android AppSDK Getter Methods ====&lt;br /&gt;
These methods provide information like Android AppSDK Version, NielsenId details.&lt;br /&gt;
&lt;br /&gt;
Get Nielsen ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getNielsenId(): String = mAppSdk?.nielsenId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get Device ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getDeviceId(): String = mAppSdk?.deviceId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get Demographic ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getDemographicId(): String = mAppSdk?.demographicId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get SDK Meter Version :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getMeterVersion(): String = AppSdk.getMeterVersion()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
=== Install the AndroidTV sample video player App ===&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
	<entry>
		<id>https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7072</id>
		<title>AndroidTV</title>
		<link rel="alternate" type="text/html" href="https://nielsentest.mywikis.net/w/index.php?title=AndroidTV&amp;diff=7072"/>
		<updated>2026-06-17T07:31:00Z</updated>

		<summary type="html">&lt;p&gt;VenkataDodla: section title updated&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Breadcrumb|}} {{Breadcrumb|Digital}}{{Breadcrumb|DCR &amp;amp; DTVR}}{{CurrentBreadcrumb}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
This guide provides step-by-step instructions for integrating the Nielsen Android AppSDK into Android TV application.&lt;br /&gt;
&lt;br /&gt;
The SDK supports three measurement types: DCR  (Digital Content Ratings) Video for measuring VOD and live streaming video content by tracking playhead positions during playback, DCR Static for measuring non-video content such as web views, articles, and informational screens, and DTVR (Digital TV Ratings) for measuring live streams by processing Nielsen ID3  tags watermarks embedded in the broadcast signal.&lt;br /&gt;
&lt;br /&gt;
=== Android AppSDK Integrations into Android TV App ===&lt;br /&gt;
This steps covers the complete integration process including AppSDK initialization, content metadata configuration, playhead tracking, ID3 tag processing, and user opt-out/in implementation.&lt;br /&gt;
&lt;br /&gt;
==== 1.1: Add Nielsen AppSDK Dependency ====&lt;br /&gt;
Add the Nielsen Android AppSDK Jar maven dependency to the App module and configure build.gradle.&lt;br /&gt;
&lt;br /&gt;
In the app-level configuration file (build.gradle), add this below dependencies.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
dependencies {&lt;br /&gt;
    implementation 'com.nielsenappsdk.global:ad:10.2.0.0'&lt;br /&gt;
    implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0'&lt;br /&gt;
    implementation &amp;quot;androidx.work:work-runtime:2.11.2&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.2: Configure Android AppSDK Parameters ====&lt;br /&gt;
Build the JSON configuration with Nielsen credentials.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
val config = JSONObject()&lt;br /&gt;
    .put(&amp;quot;appid&amp;quot;, &amp;quot;NIELSEN_APP_ID&amp;quot;)         // Nielsen-provided App ID  [required]&lt;br /&gt;
    .put(&amp;quot;nol_devDebug&amp;quot;, &amp;quot;DEBUG&amp;quot;)           // only for debug builds    &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.3: Initialize Android AppSDK ====&lt;br /&gt;
The following example code is for creating a singleton manager and initializing the Android AppSDK when the app starts.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
private var mAppSdk: AppSdk? = null&lt;br /&gt;
&lt;br /&gt;
fun initializeAppSdk(context: Context, config: JSONObject) {&lt;br /&gt;
    mAppSdk = AppSdk(context, config, object : IAppNotifier {&lt;br /&gt;
        override fun onAppSdkEvent(timestamp: Long, code: Int, description: String?) {&lt;br /&gt;
            if (code == AppSdk.EVENT_STARTUP) {&lt;br /&gt;
                Log.d(&amp;quot;Nielsen&amp;quot;, &amp;quot;AppSdk initialized successfully&amp;quot;)&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
    &lt;br /&gt;
    if (mAppSdk?.isValid != true) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Failed to initialize AppSdk&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== '''1.4: DCR Video - Start Measurement''' ====&lt;br /&gt;
The following example code is to call play() and loadMetadata() when video playback begins.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStartMeteringVideo(video: Video) {&lt;br /&gt;
    // Build content metadata&lt;br /&gt;
    val metaData = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;content&amp;quot;)               // type of content [required]&lt;br /&gt;
        .put(&amp;quot;assetid&amp;quot;, &amp;quot;uniqueassetid&amp;quot;)      // unique ID for each asset [required]&lt;br /&gt;
        .put(&amp;quot;program&amp;quot;, &amp;quot;Program Name&amp;quot;)       // name of program [required]&lt;br /&gt;
        .put(&amp;quot;title&amp;quot;, &amp;quot;Episode Title&amp;quot;)        // ex: S1E3 [required]&lt;br /&gt;
        .put(&amp;quot;length&amp;quot;, &amp;quot;3600&amp;quot;)                // length of content [required]&lt;br /&gt;
        .put(&amp;quot;category&amp;quot;, &amp;quot;Entertainment&amp;quot;)     // content category [required]&lt;br /&gt;
        .put(&amp;quot;adModel&amp;quot;, &amp;quot;2&amp;quot;)                  // 1=linear, 2=dynamic [required]&lt;br /&gt;
    &lt;br /&gt;
    // Build channel information&lt;br /&gt;
    val channelInfo = JSONObject()&lt;br /&gt;
        .put(&amp;quot;channelName&amp;quot;, &amp;quot;channelName&amp;quot;)&lt;br /&gt;
        .put(&amp;quot;mediaURL&amp;quot;, &amp;quot;videoUrl&amp;quot;)&lt;br /&gt;
    &lt;br /&gt;
    // Start measurement&lt;br /&gt;
    mAppSdk?.play(channelInfo)&lt;br /&gt;
    mAppSdk?.loadMetadata(metaData)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Reporting playhead position every 1 second during active playback.&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun monitorPlayhead(exoPlayer: ExoPlayer) {&lt;br /&gt;
    monitorJob = lifecycle.coroutineScope.launch(Dispatchers.Main) {&lt;br /&gt;
      var ticks = 0&lt;br /&gt;
        while (isActive) {&lt;br /&gt;
            if (exoPlayer.isPlaying) {&lt;br /&gt;
                val positionMs = exoPlayer.currentPosition&lt;br /&gt;
                val durationMs = exoPlayer.duration&lt;br /&gt;
                &lt;br /&gt;
                ticks++&lt;br /&gt;
               // Report every 1 second (since loop runs every 500ms)&lt;br /&gt;
                if (ticks % 2 == 0) {&lt;br /&gt;
                val playheadToReport: Long = if (videoDuration &amp;lt;= 0) {&lt;br /&gt;
                     System.currentTimeMillis() / 1000  // Live: UTC time&lt;br /&gt;
                  } else {&lt;br /&gt;
                     videoPosition.toLong()  // VOD: Position from start&lt;br /&gt;
                   }&lt;br /&gt;
              &lt;br /&gt;
                mAppSdk?.setPlayheadPosition(playheadSeconds)&lt;br /&gt;
            }&lt;br /&gt;
            delay(500)&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.5: DCR Video - Stop/End Measurement ====&lt;br /&gt;
The following example code is for signal playback state changes for accurate measurement.&lt;br /&gt;
&lt;br /&gt;
Pause Playback :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appStopMeteringVideo() {&lt;br /&gt;
    mAppSdk?.stop()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Content Session (Video End) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appEndMeteringVideo() {&lt;br /&gt;
    mAppSdk?.end()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Close SDK (App Exit Only) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appCloseMeteringVideo() {&lt;br /&gt;
    mAppSdk?.close()&lt;br /&gt;
    mAppSdk = null&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.6: DCR Static - Non Video Content Measurement ====&lt;br /&gt;
The following example code is for measuring non video content like WebViews and articles.&lt;br /&gt;
&lt;br /&gt;
Start Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticLoadMetadata() {&lt;br /&gt;
    val metadata = JSONObject()&lt;br /&gt;
        .put(&amp;quot;type&amp;quot;, &amp;quot;static&amp;quot;)                    // type of content [required]&lt;br /&gt;
        .put(&amp;quot;section&amp;quot;, &amp;quot;Web View Screen&amp;quot;)        // section of site [required]&lt;br /&gt;
        .put(&amp;quot;segA&amp;quot;, &amp;quot;CustomSegmentA&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segB&amp;quot;, &amp;quot;CustomSegmentB&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;segC&amp;quot;, &amp;quot;CustomSegmentC&amp;quot;)            // custom segment [optional]&lt;br /&gt;
        .put(&amp;quot;crossId1&amp;quot;, &amp;quot;Standard Episode ID&amp;quot;)   // [optional]&lt;br /&gt;
        .put(&amp;quot;crossId2&amp;quot;, &amp;quot;Content Originator&amp;quot;)    // [optional]&lt;br /&gt;
    &lt;br /&gt;
    mAppSdk?.loadMetadata(metadata)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Static Measurement :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun staticEnd() {&lt;br /&gt;
    mAppSdk?.staticEnd()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.7: DTVR - ID3 Tag Processing ====&lt;br /&gt;
The following example code is for processing Nielsen ID3 tags from live streams for DTVR measurement.&lt;br /&gt;
&lt;br /&gt;
Listen for ID3 Metadata (ExoPlayer) :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
inner class PlayerEventListener : Player.Listener {&lt;br /&gt;
    override fun onMetadata(metadata: Metadata) {&lt;br /&gt;
        for (i in 0 until metadata.length()) {&lt;br /&gt;
            val entry = metadata.get(i)&lt;br /&gt;
            if (entry is PrivFrame) {&lt;br /&gt;
                val owner = entry.owner&lt;br /&gt;
                val data = String(entry.privateData, Charsets.UTF_8)&lt;br /&gt;
                &lt;br /&gt;
                // Check if it's a Nielsen ID3 tag&lt;br /&gt;
                if (owner.contains(&amp;quot;nielsen&amp;quot;, ignoreCase = true) ||&lt;br /&gt;
                    owner.contains(&amp;quot;www.nielsen.com&amp;quot;, ignoreCase = true)) {&lt;br /&gt;
                    appProcessID3tag(owner + data)&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Send ID3 Tags to Nielsen SDK :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun appProcessID3tag(id3String: String?) {&lt;br /&gt;
    try {&lt;br /&gt;
        mAppSdk?.sendID3(id3String)&lt;br /&gt;
    } catch (e: Exception) {&lt;br /&gt;
        Log.e(&amp;quot;Nielsen&amp;quot;, &amp;quot;Cannot process ID3 tag: ${e.message}&amp;quot;)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.8: User Opt-Out Implementation ====&lt;br /&gt;
The following example code is to provide users the ability to opt out of Nielsen measurement via WebView.&lt;br /&gt;
&lt;br /&gt;
Get Opt-Out URL :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutUrl(): String {&lt;br /&gt;
    return mAppSdk?.userOptOutURLString() ?: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// Load this URL in a WebView&lt;br /&gt;
webView.loadUrl(getOptOutUrl())&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Handle Opt-Out Response :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
webView.webViewClient = object : WebViewClient() {&lt;br /&gt;
    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {&lt;br /&gt;
        val url = request.url.toString()&lt;br /&gt;
        &lt;br /&gt;
        // Check for Nielsen opt-out response&lt;br /&gt;
        if (url.startsWith(&amp;quot;nielsenappsdk://&amp;quot;)) {&lt;br /&gt;
            mAppSdk?.userOptOut(url)&lt;br /&gt;
            // Navigate back or show confirmation&lt;br /&gt;
            return true&lt;br /&gt;
        }&lt;br /&gt;
        return false&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Check Opt-Out Status : &amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getOptOutStatus(): Boolean {&lt;br /&gt;
    return mAppSdk?.optOutStatus ?: false&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 1.9: Android AppSDK Getter Methods ====&lt;br /&gt;
These methods provide information like Android AppSDK Version, NielsenId details.&lt;br /&gt;
&lt;br /&gt;
Get Nielsen ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getNielsenId(): String = mAppSdk?.nielsenId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get Device ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getDeviceId(): String = mAppSdk?.deviceId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get Demographic ID :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getDemographicId(): String = mAppSdk?.demographicId ?: &amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Get SDK Meter Version :&amp;lt;syntaxhighlight lang=&amp;quot;kotlin&amp;quot;&amp;gt;&lt;br /&gt;
fun getMeterVersion(): String = AppSdk.getMeterVersion()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Quick Reference - Android AppSDK Methods ===&lt;br /&gt;
The table below provides a summary of the core Android AppSDK methods, their primary functions, and the appropriate triggers for calling them within your application lifecycle.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Method&lt;br /&gt;
!Purpose&lt;br /&gt;
!When to Call&lt;br /&gt;
|-&lt;br /&gt;
|play(channelInfo)&lt;br /&gt;
|Start content session&lt;br /&gt;
|Video playback begins.&lt;br /&gt;
|-&lt;br /&gt;
|loadMetadata(metadata)&lt;br /&gt;
|Send content/Ad/static info&lt;br /&gt;
|After play API call or for static content.&lt;br /&gt;
|-&lt;br /&gt;
|setPlayheadPosition(video playback pos)&lt;br /&gt;
|Report playhead position&lt;br /&gt;
|setPlayheadPosition(pos) - sets the playhead position in AppSDK as video playback time (seconds) in the content (VOD Video On Demand) or the current UTC time for live stream.&lt;br /&gt;
|-&lt;br /&gt;
|sendID3(tag)&lt;br /&gt;
|Process DTVR videos&lt;br /&gt;
|When ID3 tag received from stream.&lt;br /&gt;
|-&lt;br /&gt;
|stop()&lt;br /&gt;
|Pause measurement&lt;br /&gt;
|Video paused.&lt;br /&gt;
|-&lt;br /&gt;
|end()&lt;br /&gt;
|End content session&lt;br /&gt;
|Video playback ends.&lt;br /&gt;
|-&lt;br /&gt;
|staticEnd()&lt;br /&gt;
|End static session&lt;br /&gt;
|Leave static content screen.&lt;br /&gt;
|-&lt;br /&gt;
|close()&lt;br /&gt;
|Destroy SDK instance&lt;br /&gt;
|App exit only.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOutURLString()&lt;br /&gt;
|Get opt-out URL&lt;br /&gt;
|Display opt-out WebView.&lt;br /&gt;
|-&lt;br /&gt;
|userOptOut(url)&lt;br /&gt;
|Set opt-out preference&lt;br /&gt;
|When the user completes the opt-out.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample App: Download, Build, and Emulator Setup ===&lt;br /&gt;
The following section provides instructions for downloading the sample application, building the APK within Android Studio, and setting up the necessary Android TV emulator environment for testing.&lt;br /&gt;
&lt;br /&gt;
==== 3.1: Download the package here ====&lt;br /&gt;
Click [[Main Page|here]] to  download the project and open the project in Android Studio IDE.&lt;br /&gt;
&lt;br /&gt;
==== 3.2: Build the APK from this Project ====&lt;br /&gt;
Before building the apk, create an AndroidTV emulator from the IDE and install the App directly through Android Studio.&lt;br /&gt;
&lt;br /&gt;
Follow the steps to test AndroidTV sample Apps in TV Emulators and how to build the app from the client package.&lt;br /&gt;
&lt;br /&gt;
==== 3.3: Create the Android TV Emulator ====&lt;br /&gt;
To create an Android TV emulator, you primarily use [https://developer.android.com/studio Android Studio] to set up an Android Virtual Device (AVD).&lt;br /&gt;
&lt;br /&gt;
=== Install the AndroidTV sample video player App ===&lt;br /&gt;
Once you have built the APK and configured your Android TV emulator, use either of the following methods to install the sample video player application.&lt;br /&gt;
&lt;br /&gt;
Method 1: Drag and Drop (Easiest)&lt;br /&gt;
&lt;br /&gt;
Use your mouse to drag and drop the APK onto the running emulator :&lt;br /&gt;
&lt;br /&gt;
# Launch the Android TV emulator.&lt;br /&gt;
# Locate the .apk file on your computer.&lt;br /&gt;
# Drag the file and drop it directly onto the emulator window.&lt;br /&gt;
# Wait for the installation to automatically complete.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Method 2 : Use ADB (Command Line)&lt;br /&gt;
&lt;br /&gt;
Use the Android Debug Bridge (ADB) if you have the Android SDK Platform-Tools installed :&lt;br /&gt;
&lt;br /&gt;
# Open the terminal or command prompt.&lt;br /&gt;
# Ensure emulator is running and detected by typing: -&amp;gt; adb devices.&lt;br /&gt;
# Install the APK by running the following command:   -&amp;gt; adb install path/to/your/sample_app.apk.&lt;br /&gt;
&lt;br /&gt;
=== Open up Android TV Emulator ===&lt;br /&gt;
After installing the sample app, follow these steps to launch the Nielsen Sample TV application on your emulator.&lt;br /&gt;
&lt;br /&gt;
Select Nielsen Sample TV App  -&amp;gt; Select Legacy Option&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 133449.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 133705.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260527 134418.png|center|720x720px]]&lt;br /&gt;
[[File:Screenshot 20260529 152139.png|center|720x720px]]&lt;br /&gt;
&lt;br /&gt;
Setting page for  Select  Opt out/in options&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot 20260527 134647.png|center|720x720px|border]]&lt;br /&gt;
&lt;br /&gt;
=== Next Steps ===&lt;br /&gt;
If there are any questions or concerns then please reach out to the AppSDK team. Reference the following guides for product specific information :&lt;br /&gt;
&lt;br /&gt;
* [[DCR Video Android SDK|DCR Video]]&lt;br /&gt;
* [[DCR Static Android SDK|DCR Static]]&lt;br /&gt;
* [[DTVR Android SDK|DTVR]]&lt;br /&gt;
&lt;br /&gt;
For further technical details , please contact your Technical Account Manager (TAM).&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
[[Category:Digital]]&lt;/div&gt;</summary>
		<author><name>VenkataDodla</name></author>
	</entry>
</feed>