PAL lets you send Google ad signals in your ad requests and during ad playback.

This guide covers adding the Android PAL SDK to your app. To see a sample app
that uses PAL to generate a nonce, download the Android example from
[GitHub](https://github.com/googleads/googleads-pal).

## Add the Android PAL SDK as a library

As of version 18.0.0, the PAL SDK is hosted on Google's Maven repository and
can be added to your app as follows:

    implementation("com.google.android.gms:play-services-pal:23.1.0")

Alternatively, the PAL SDK can be downloaded from [Google's Maven repository](https://maven.google.com/web/index.html?q=pal#com.google.android.gms:play-services-pal:23.1.0) and manually added to your app.

### Enable app desugaring

As of version 23.0.0, PAL requires you to enable app desugaring,
by setting `coreLibraryDesugaringEnabled true` and adding a dependency to
`com.android.tools:desugar_jdk_libs` in the **build.gradle** file. For more
details, see
[Java 11+ APIs available through desugaring with the nio specification](https://developer.android.com/studio/write/java11-nio-support-table).

    coreLibraryDesugaringEnabled = true

## Generate nonce

A nonce is a single encrypted string PAL generates using the `NonceLoader`
class. PAL requires each stream request to be accompanied by a
unique nonce. However, you can reuse nonces for multiple ad requests
in the same stream. To generate a nonce using the PAL SDK, make the
following changes to import and set up PAL, and create a function to generate
a nonce:

1. Import and set up PAL by doing the following:

   1. Import PAL classes:

          import com.google.ads.interactivemedia.pal.ConsentSettings;
          import com.google.ads.interactivemedia.pal.NonceLoader;
          import com.google.ads.interactivemedia.pal.NonceManager;
          import com.google.ads.interactivemedia.pal.NonceRequest;
          import com.google.android.gms.tasks.OnFailureListener;
          import com.google.android.gms.tasks.OnSuccessListener;
          import java.util.HashSet;
          import java.util.Set;

   2. Create private variables to store the `NonceLoader` and `NonceManager`
      instances:

          private NonceLoader nonceLoader;
          private NonceManager nonceManager;

   3. Initialize your `NonceLoader` instance with a `ConsentSettings` instance
      in the `onCreate` method:

          @Override
          protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            // By default, PAL automatically determines whether to enable limited ads
            // based on the user's TCF (Transparency and Consent Framework) consent data
            // on the device. If you must manually override the default behavior,
            // for example, to meet your app's requirements, use the
            // `ConsentSettings.Builder.forceLimitedAds` property.
            ConsentSettings consentSettings = ConsentSettings.builder().build();

            // It is important to instantiate the NonceLoader as early as possible to
            // allow it to initialize and preload data for a faster experience when
            // loading the NonceManager. A new NonceLoader will need to be instantiated
            // if the ConsentSettings change for the user.
            nonceLoader = new NonceLoader(this, consentSettings);

            adClickButton = findViewById(R.id.send_click_button);

            logView = findViewById(R.id.log_view);
            logView.setMovementMethod(new ScrollingMovementMethod());
          }

   In your app, create one instance of the `NonceLoader` class for each user
   session. If your app has multiple pages or equivalent constructs, create a
   new `NonceLoader` instance for each page or page-equivalent. By using the
   same `NonceLoader` instance, you keep the page correlator `&correlator`
   unchanged for the lifetime of a page or a user's session on the app. You
   still have control over the stream correlator `&scor`, which you must reset
   for each new stream by generating a new nonce.

   All ad requests of the same stream must share the same `NonceLoader` instance
   and stream correlator value for frequency capping and competitive exclusion
   features to happen.
2. Generate a nonce:

       public void generateNonceForAdRequest(View view) {
         logMessage("Generate Nonce Request");
         Set supportedApiFrameWorksSet = new HashSet();
         // The values 2, 7, and 9 correspond to player support for VPAID 2.0,
         // OMID 1.0, and SIMID 1.1.
         supportedApiFrameWorksSet.add(2);
         supportedApiFrameWorksSet.add(7);
         supportedApiFrameWorksSet.add(9);

         NonceRequest nonceRequest =
             NonceRequest.builder()
                 .descriptionURL("https://example.com/content1")
                 .iconsSupported(true)
                 .omidPartnerVersion("6.2.1")
                 .omidPartnerName("Example Publisher")
                 .playerType("ExamplePlayerType")
                 .playerVersion("1.0.0")
                 .ppid("testPpid")
                 .sessionId("Sample SID")
                 .supportedApiFrameworks(supportedApiFrameWorksSet)
                 .videoPlayerHeight(480)
                 .videoPlayerWidth(640)
                 .willAdAutoPlay(true)
                 .willAdPlayMuted(false)
                 .build();

         nonceLoader
             .loadNonceManager(nonceRequest)
             .addOnSuccessListener(
                 new OnSuccessListener<NonceManager>() {
                   @Override
                   public void onSuccess(NonceManager manager) {
                     nonceManager = manager;
                     String nonceString = manager.getNonce();
                     logMessage("Nonce generated");
                     logMessage(nonceString.substring(0, 20) + "...");
                     Log.i(LOG_TAG, "Generated nonce: " + nonceString);

                     // From here you would trigger your ad request and move on to initialize content.
                     exampleMakeAdRequest(DEFAULT_AD_TAG + "&givn=" + nonceString);

                     adClickButton.setEnabled(true);
                   }
                 })
             .addOnFailureListener(
                 new OnFailureListener() {
                   @Override
                   public void onFailure(Exception error) {
                     logMessage("Nonce generation failed");
                     Log.e(LOG_TAG, "Nonce generation failed: " + error.getMessage());
                   }
                 });
       }

   You only need one nonce for all the ad requests in a single stream playback.
   For testing purposes, call this function when clicking a button in
   your test app. The `NonceRequest` parameters set in this guide are example
   parameters. Set your parameters based on your own app characteristics.

   This function generates a nonce asynchronously. You must handle both
   success and failure cases of the nonce request.
   After the nonce manager is available, retrieve the nonce before you
   make an ad request using the `nonceManager.getNonce()` method.

## Attach nonce to the ad request

To use the generated nonce, append your ad tag with a `givn` parameter and the
nonce value before making your ad requests:

> [!CAUTION]
> **Caution:** If you previously provided a nonce using the `paln` parameter, it is strongly recommended to migrate to `givn` and stop sending `paln`. If both parameters are included, it is undefined behavior regarding which nonce one is used.

    // From here you would trigger your ad request and move on to initialize content.
    exampleMakeAdRequest(DEFAULT_AD_TAG + "&givn=" + nonceString);

If you are requesting and rendering ads from Google, you must render
the [AdChoices](https://support.google.com/My-Ad-Center-Help/answer/12155764) icon and overlay.
For details about parsing the VAST response and rendering icons, see
[AdChoices icon and overlay](https://developers.google.com/ad-manager/pal/android/wta).

## Track playback events

To track playback events, you must set up event handlers to send ad signals to
Google:

    // Triggered when a user clicks-through on an ad which was requested using a PAL nonce.
    public void sendAdClick(View view) {
      logMessage("Ad click sent");
      if (nonceManager != null) {
        nonceManager.sendAdClick();
      }
    }

    // In a typical PAL app, this is called when a user touch or click is detected,
    // on the ad other than an ad click-through.
    public void onVideoViewTouch(MotionEvent e) {
      if (nonceManager != null) {
        nonceManager.sendAdTouch(e);
      }
    }

    // In a typical PAL app, this is called when a content playback session starts.
    public void sendPlaybackStart() {
      logMessage("Playback start");
      if (nonceManager != null) {
        nonceManager.sendPlaybackStart();
      }
    }

    // In a typical PAL app, this is called when a content playback session ends.
    public void sendPlaybackEnd() {
      logMessage("Playback end");
      if (nonceManager != null) {
        nonceManager.sendPlaybackEnd();
      }
    }

Here is when to call each function in your implementation:

- `sendPlaybackStart()`: When your video playback session begins
- `sendPlaybackEnd()`: When your video playback session comes to an end
- `sendAdClick()`: Each time the viewer clicks an ad
- `sendAdTouch()`: On every touch interaction with the player

For testing purposes, attach the event handler methods to button click events.
In a production implementation, set up your app for player events to call the
event handler methods.

## (Optional) Send Google Ad Manager signals through third-party ad servers

When you set up your third-party ad server to work with Google Ad Manager, refer
to your server's documentation to capture and forward the nonce value in each ad
request. The provided example is of an ad request URL with the nonce parameter
included. The nonce parameter propagates from the PAL SDK, through your
intermediary servers, and then to Ad Manager, enabling better monetization.

> [!NOTE]
> **Note:** If you use multiple third-party solutions, for example, a third-party SSAI server calling another third-party ad server, you need to make sure the PAL SDK's encrypted nonce is forwarded to each third party.

Configure your third-party ad server to include the nonce in the server's
request to Ad Manager. Here's an example of an ad tag configured inside of the
third-party ad server:

    'https://pubads.serverside.net/gampad/ads?givn=%%custom_key_for_google_nonce%%&...'

For more details, see the [Google Ad Manager Server-side implementation
guide](https://support.google.com/admanager/answer/10668760).

Ad Manager looks for `givn=` to identify the nonce value. The third-party ad
server needs to support some macro of its own, such as
`%%custom_key_for_google_nonce%%`, and replace it with the nonce query parameter
you provided in the previous step. More information on how to accomplish this
is available in the third-party ad server's documentation.