diff --git a/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/AdWrapper.java b/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/AdWrapper.java index 7808afdc1..b997a8b30 100644 --- a/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/AdWrapper.java +++ b/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/AdWrapper.java @@ -6,6 +6,8 @@ import com.google.android.libraries.ads.mobile.sdk.common.AdLoadCallback; import com.google.android.libraries.ads.mobile.sdk.common.AdRequest; import com.google.android.libraries.ads.mobile.sdk.interstitial.InterstitialAd; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAd; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdRequest; import com.google.android.libraries.ads.mobile.sdk.rewarded.RewardedAd; import com.google.android.libraries.ads.mobile.sdk.rewardedinterstitial.RewardedInterstitialAd; @@ -67,4 +69,20 @@ public static AdWrapper forRewarded() { public static AdWrapper forRewardedInterstitial() { return new AdWrapper<>(RewardedInterstitialAd::load); } + + /** Creates a new AdWrapper for loading PictureInPictureAds. */ + public static AdWrapper forPictureInPicture() { + return new AdWrapper<>( + new AdLoader() { + @Override + public void load(AdRequest adRequest, AdLoadCallback callback) { + if (adRequest instanceof PictureInPictureAdRequest) { + PictureInPictureAd.load((PictureInPictureAdRequest) adRequest, callback); + } else { + throw new IllegalArgumentException( + "AdRequest must be of type PictureInPictureAdRequest for PiP Ads"); + } + } + }); + } } diff --git a/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityPictureInPictureAd.java b/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityPictureInPictureAd.java new file mode 100644 index 000000000..e62028c3d --- /dev/null +++ b/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityPictureInPictureAd.java @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2026 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.unity.ads.nextgen; + +import android.app.Activity; +import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import com.google.android.libraries.ads.mobile.sdk.common.AdLoadCallback; +import com.google.android.libraries.ads.mobile.sdk.common.AdRequest; +import com.google.android.libraries.ads.mobile.sdk.common.AdValue; +import com.google.android.libraries.ads.mobile.sdk.common.LoadAdError; +import com.google.android.libraries.ads.mobile.sdk.common.ResponseInfo; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAd; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdEventCallback; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdOptions; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdPosition; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdRequest; + +/** Native Java implementation for Picture-in-Picture Ads in the Google Mobile Ads Unity plugin. */ +public class UnityPictureInPictureAd { + + private static final String LOG_TAG = "GoogleMobileAds"; + + private final Activity activity; + private final UnityPictureInPictureAdCallback callback; + private final AdWrapper adWrapper; + @Nullable private PictureInPictureAd pipAd; + + public UnityPictureInPictureAd(Activity activity, UnityPictureInPictureAdCallback callback) { + this(activity, callback, AdWrapper.forPictureInPicture()); + } + + @VisibleForTesting + UnityPictureInPictureAd( + Activity activity, + UnityPictureInPictureAdCallback callback, + AdWrapper adWrapper) { + this.activity = activity; + this.callback = callback; + this.adWrapper = adWrapper; + } + + /** + * Loads a Picture-in-Picture ad on the UI thread. + * + * @param adUnitId The ad unit ID to load. + * @param adRequest The native AdRequest object. + */ + public void load(String adUnitId, AdRequest adRequest) { + activity.runOnUiThread( + () -> { + try { + PictureInPictureAdRequest pipRequest = + new PictureInPictureAdRequest.Builder(adUnitId).build(); + + adWrapper.load( + pipRequest, + new AdLoadCallback() { + @Override + public void onAdLoaded(@NonNull PictureInPictureAd ad) { + pipAd = ad; + pipAd.setAdEventCallback( + new PictureInPictureAdEventCallback() { + @Override + public void onAdShown() { + if (callback != null) { + callback.onAdShown(); + } + } + + @Override + public void onAdHidden() { + if (callback != null) { + callback.onAdHidden(); + } + } + + @Override + public void onAdClicked() { + if (callback != null) { + callback.onAdClicked(); + } + } + + @Override + public void onAdImpression() { + if (callback != null) { + callback.onAdImpression(); + } + } + + @Override + public void onAdShowedFullScreenContent() { + if (callback != null) { + callback.onAdShowedFullScreenContent(); + } + } + + @Override + public void onAdDismissedFullScreenContent() { + if (callback != null) { + callback.onAdDismissedFullScreenContent(); + } + } + + @Override + public void onAdPaid(@NonNull AdValue adValue) { + if (callback != null) { + callback.onPaidEvent( + Util.getAdValuePrecisionType(adValue.getPrecisionType()), + adValue.getValueMicros(), + adValue.getCurrencyCode()); + } + } + }); + + if (callback != null) { + callback.onAdLoaded(); + } + } + + @Override + public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { + if (callback != null) { + callback.onAdFailedToLoad(loadAdError); + } + } + }); + } catch (Throwable t) { + Log.e(LOG_TAG, "Failed to load PictureInPictureAd: " + t, t); + if (callback != null) { + callback.onAdFailedToLoad( + new LoadAdError( + LoadAdError.ErrorCode.INTERNAL_ERROR, + t.getMessage() != null ? t.getMessage() : t.toString(), + null)); + } + } + }); + } + + /** + * Shows the Picture-in-Picture ad at the given corner position. + * + * @param positionOrdinal 0=BOTTOM_RIGHT, 1=BOTTOM_LEFT, 2=TOP_LEFT, 3=TOP_RIGHT. + */ + public void show(int positionOrdinal) { + activity.runOnUiThread( + () -> { + if (pipAd == null) { + Log.e(LOG_TAG, "Failed to show PictureInPictureAd: ad is null."); + return; + } + PictureInPictureAdPosition position; + switch (positionOrdinal) { + case 1: + position = PictureInPictureAdPosition.BOTTOM_RIGHT; + break; + case 2: + position = PictureInPictureAdPosition.BOTTOM_LEFT; + break; + case 3: + position = PictureInPictureAdPosition.TOP_LEFT; + break; + case 4: + position = PictureInPictureAdPosition.TOP_RIGHT; + break; + case 0: + default: + position = PictureInPictureAdPosition.DEFAULT; + break; + } + PictureInPictureAdOptions options = + new PictureInPictureAdOptions.Builder().setPosition(position).build(); + pipAd.show(activity, options); + }); + } + + /** Hides the Picture-in-Picture ad. */ + public void hide() { + activity.runOnUiThread( + () -> { + if (pipAd != null) { + pipAd.hide(); + } + }); + } + + /** Destroys the Picture-in-Picture ad and cleans up references. */ + public void destroy() { + activity.runOnUiThread( + () -> { + if (pipAd != null) { + pipAd.destroy(); + pipAd = null; + } + }); + } + + /** Returns the current or last known position ordinal (0=DEFAULT, 1=BOTTOM_RIGHT, etc.). */ + public int getAdPosition() { + if (pipAd == null) { + return 0; + } + PictureInPictureAdPosition position = pipAd.getPosition(); + if (position == null) { + return 0; + } + switch (position) { + case DEFAULT: + return 0; + case BOTTOM_RIGHT: + return 1; + case BOTTOM_LEFT: + return 2; + case TOP_LEFT: + return 3; + case TOP_RIGHT: + return 4; + } + return 0; + } + + /** Returns ResponseInfo for the loaded ad, if available. */ + @Nullable + public ResponseInfo getResponseInfo() { + return pipAd != null ? pipAd.getResponseInfo() : null; + } +} diff --git a/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityPictureInPictureAdCallback.java b/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityPictureInPictureAdCallback.java new file mode 100644 index 000000000..1b7816a56 --- /dev/null +++ b/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityPictureInPictureAdCallback.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2026 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.unity.ads.nextgen; + +import com.google.android.libraries.ads.mobile.sdk.common.LoadAdError; + +/** + * An interface form of {@link UnityPictureInPictureAdCallback} that can be implemented via {@code + * AndroidJavaProxy} in Unity to receive ad events synchronously. + */ +public interface UnityPictureInPictureAdCallback extends UnityPaidEventListener { + + /** Called when the picture in picture ad is loaded. */ + void onAdLoaded(); + + /** Called when the picture in picture ad fails to load. */ + void onAdFailedToLoad(LoadAdError error); + + /** Called when the picture in picture ad is displayed on the screen. */ + void onAdShown(); + + /** Called when the picture in picture ad is hidden from the screen. */ + void onAdHidden(); + + /** Called when the picture in picture ad records an impression. */ + void onAdImpression(); + + /** Called when the picture in picture ad records a click. */ + void onAdClicked(); + + /** Called when the picture in picture ad opens an overlay that covers the screen. */ + void onAdShowedFullScreenContent(); + + /** Called when the picture in picture ad dismisses an overlay that it previously showed. */ + void onAdDismissedFullScreenContent(); +} diff --git a/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/test/java/com/google/unity/ads/nextgen/UnityPictureInPictureAdTest.java b/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/test/java/com/google/unity/ads/nextgen/UnityPictureInPictureAdTest.java new file mode 100644 index 000000000..a72c5c694 --- /dev/null +++ b/source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/test/java/com/google/unity/ads/nextgen/UnityPictureInPictureAdTest.java @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2026 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.unity.ads.nextgen; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.os.Bundle; +import com.google.android.libraries.ads.mobile.sdk.common.AdLoadCallback; +import com.google.android.libraries.ads.mobile.sdk.common.AdRequest; +import com.google.android.libraries.ads.mobile.sdk.common.AdValue; +import com.google.android.libraries.ads.mobile.sdk.common.LoadAdError; +import com.google.android.libraries.ads.mobile.sdk.common.PrecisionType; +import com.google.android.libraries.ads.mobile.sdk.common.ResponseInfo; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAd; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdEventCallback; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdOptions; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdPosition; +import com.google.android.libraries.ads.mobile.sdk.pip.PictureInPictureAdRequest; +import java.util.ArrayList; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; + +/** Unit tests for {@link UnityPictureInPictureAd} and {@link UnityPictureInPictureAdCallback}. */ +@RunWith(RobolectricTestRunner.class) +public final class UnityPictureInPictureAdTest { + + private static final String AD_UNIT_ID = "ca-app-pub-3940256099942544/6300978111"; + + @Rule public final MockitoRule mocks = MockitoJUnit.rule(); + + private Activity activity; + @Mock private UnityPictureInPictureAdCallback mockCallback; + @Mock private PictureInPictureAd mockPipAd; + @Mock private AdWrapper mockAdWrapper; + @Mock private AdRequest mockAdRequest; + + @Captor private ArgumentCaptor adRequestCaptor; + @Captor private ArgumentCaptor> adLoadCallbackCaptor; + @Captor private ArgumentCaptor adEventCallbackCaptor; + @Captor private ArgumentCaptor adOptionsCaptor; + + private UnityPictureInPictureAd unityPictureInPictureAd; + + @Before + public void setUp() { + activity = Robolectric.buildActivity(Activity.class).create().get(); + unityPictureInPictureAd = new UnityPictureInPictureAd(activity, mockCallback, mockAdWrapper); + } + + @Test + public void testPublicConstructor_createsInstance() { + UnityPictureInPictureAd ad = new UnityPictureInPictureAd(activity, mockCallback); + assertThat(ad).isNotNull(); + } + + @Test + public void testLoad_onAdLoaded_invokesCallback() { + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + + verify(mockAdWrapper).load(adRequestCaptor.capture(), adLoadCallbackCaptor.capture()); + assertThat(adRequestCaptor.getValue().getAdUnitId()).isEqualTo(AD_UNIT_ID); + + adLoadCallbackCaptor.getValue().onAdLoaded(mockPipAd); + verify(mockCallback).onAdLoaded(); + verify(mockPipAd).setAdEventCallback(any()); + } + + @Test + public void testLoad_onAdFailedToLoad_invokesCallback() { + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + + verify(mockAdWrapper).load(adRequestCaptor.capture(), adLoadCallbackCaptor.capture()); + LoadAdError loadAdError = + new LoadAdError(LoadAdError.ErrorCode.INTERNAL_ERROR, "error message", null); + adLoadCallbackCaptor.getValue().onAdFailedToLoad(loadAdError); + + verify(mockCallback).onAdFailedToLoad(loadAdError); + verify(mockCallback, never()).onAdLoaded(); + } + + @Test + public void testAdEventCallbacks_allEventsTriggered() { + // Load the ad first + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + verify(mockAdWrapper).load(any(), adLoadCallbackCaptor.capture()); + adLoadCallbackCaptor.getValue().onAdLoaded(mockPipAd); + + verify(mockPipAd).setAdEventCallback(adEventCallbackCaptor.capture()); + PictureInPictureAdEventCallback eventCallback = adEventCallbackCaptor.getValue(); + + // Verify onAdShown + eventCallback.onAdShown(); + verify(mockCallback).onAdShown(); + + // Verify onAdHidden + eventCallback.onAdHidden(); + verify(mockCallback).onAdHidden(); + + // Verify onAdClicked + eventCallback.onAdClicked(); + verify(mockCallback).onAdClicked(); + + // Verify onAdImpression + eventCallback.onAdImpression(); + verify(mockCallback).onAdImpression(); + + // Verify onAdShowedFullScreenContent + eventCallback.onAdShowedFullScreenContent(); + verify(mockCallback).onAdShowedFullScreenContent(); + + // Verify onAdDismissedFullScreenContent + eventCallback.onAdDismissedFullScreenContent(); + verify(mockCallback).onAdDismissedFullScreenContent(); + + // Verify onAdPaid + PrecisionType precisionType = PrecisionType.PRECISE; + long valueMicros = 1500000L; + String currencyCode = "USD"; + eventCallback.onAdPaid(new AdValue(precisionType, valueMicros, currencyCode)); + verify(mockCallback) + .onPaidEvent(Util.getAdValuePrecisionType(precisionType), valueMicros, currencyCode); + } + + @Test + public void testShow_whenAdNotLoaded_doesNotThrow() { + unityPictureInPictureAd.show(0); + verify(mockPipAd, never()).show(any(), any()); + } + + @Test + public void testShow_defaultPosition_passesDefaultOptions() { + // Load the ad + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + verify(mockAdWrapper).load(any(), adLoadCallbackCaptor.capture()); + adLoadCallbackCaptor.getValue().onAdLoaded(mockPipAd); + + // Call show(0) for Default + unityPictureInPictureAd.show(0); + + verify(mockPipAd).show(eq(activity), adOptionsCaptor.capture()); + assertThat(adOptionsCaptor.getValue().getPosition()) + .isEqualTo(PictureInPictureAdPosition.DEFAULT); + } + + @Test + public void testShow_explicitPositions_passesCorrectOptions() { + // Load the ad + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + verify(mockAdWrapper).load(any(), adLoadCallbackCaptor.capture()); + adLoadCallbackCaptor.getValue().onAdLoaded(mockPipAd); + + // Test position 1 -> BOTTOM_RIGHT + unityPictureInPictureAd.show(1); + verify(mockPipAd).show(eq(activity), adOptionsCaptor.capture()); + assertThat(adOptionsCaptor.getValue().getPosition()) + .isEqualTo(PictureInPictureAdPosition.BOTTOM_RIGHT); + + // Test position 2 -> BOTTOM_LEFT + unityPictureInPictureAd.show(2); + verify(mockPipAd, Mockito.times(2)).show(eq(activity), adOptionsCaptor.capture()); + assertThat(adOptionsCaptor.getValue().getPosition()) + .isEqualTo(PictureInPictureAdPosition.BOTTOM_LEFT); + + // Test position 3 -> TOP_LEFT + unityPictureInPictureAd.show(3); + verify(mockPipAd, Mockito.times(3)).show(eq(activity), adOptionsCaptor.capture()); + assertThat(adOptionsCaptor.getValue().getPosition()) + .isEqualTo(PictureInPictureAdPosition.TOP_LEFT); + + // Test position 4 -> TOP_RIGHT + unityPictureInPictureAd.show(4); + verify(mockPipAd, Mockito.times(4)).show(eq(activity), adOptionsCaptor.capture()); + assertThat(adOptionsCaptor.getValue().getPosition()) + .isEqualTo(PictureInPictureAdPosition.TOP_RIGHT); + } + + @Test + public void testHide_whenAdLoaded_callsPipAdHide() { + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + verify(mockAdWrapper).load(any(), adLoadCallbackCaptor.capture()); + adLoadCallbackCaptor.getValue().onAdLoaded(mockPipAd); + + unityPictureInPictureAd.hide(); + verify(mockPipAd).hide(); + } + + @Test + public void testHide_whenAdNotLoaded_doesNotThrow() { + unityPictureInPictureAd.hide(); + verify(mockPipAd, never()).hide(); + } + + @Test + public void testDestroy_whenAdLoaded_destroysAndCleansUp() { + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + verify(mockAdWrapper).load(any(), adLoadCallbackCaptor.capture()); + adLoadCallbackCaptor.getValue().onAdLoaded(mockPipAd); + + unityPictureInPictureAd.destroy(); + verify(mockPipAd).destroy(); + + // Verify subsequent show or hide does not invoke pipAd + unityPictureInPictureAd.show(0); + verify(mockPipAd, never()).show(any(), any()); + } + + @Test + public void testGetAdPosition_whenAdNotLoaded_returnsDefaultZero() { + assertThat(unityPictureInPictureAd.getAdPosition()).isEqualTo(0); + } + + @Test + public void testGetAdPosition_whenAdLoaded_mapsPositionsCorrectly() { + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + verify(mockAdWrapper).load(any(), adLoadCallbackCaptor.capture()); + adLoadCallbackCaptor.getValue().onAdLoaded(mockPipAd); + + // DEFAULT -> 0 + when(mockPipAd.getPosition()).thenReturn(PictureInPictureAdPosition.DEFAULT); + assertThat(unityPictureInPictureAd.getAdPosition()).isEqualTo(0); + + // BOTTOM_RIGHT -> 1 + when(mockPipAd.getPosition()).thenReturn(PictureInPictureAdPosition.BOTTOM_RIGHT); + assertThat(unityPictureInPictureAd.getAdPosition()).isEqualTo(1); + + // BOTTOM_LEFT -> 2 + when(mockPipAd.getPosition()).thenReturn(PictureInPictureAdPosition.BOTTOM_LEFT); + assertThat(unityPictureInPictureAd.getAdPosition()).isEqualTo(2); + + // TOP_LEFT -> 3 + when(mockPipAd.getPosition()).thenReturn(PictureInPictureAdPosition.TOP_LEFT); + assertThat(unityPictureInPictureAd.getAdPosition()).isEqualTo(3); + + // TOP_RIGHT -> 4 + when(mockPipAd.getPosition()).thenReturn(PictureInPictureAdPosition.TOP_RIGHT); + assertThat(unityPictureInPictureAd.getAdPosition()).isEqualTo(4); + } + + @Test + public void testGetResponseInfo_whenAdNotLoaded_returnsNull() { + assertThat(unityPictureInPictureAd.getResponseInfo()).isNull(); + } + + @Test + public void testGetResponseInfo_whenAdLoaded_returnsResponseInfo() { + ResponseInfo responseInfo = + new ResponseInfo("AdapterName", "responseId", new Bundle(), null, new ArrayList<>()); + when(mockPipAd.getResponseInfo()).thenReturn(responseInfo); + + unityPictureInPictureAd.load(AD_UNIT_ID, mockAdRequest); + verify(mockAdWrapper).load(any(), adLoadCallbackCaptor.capture()); + adLoadCallbackCaptor.getValue().onAdLoaded(mockPipAd); + + ResponseInfo actualResponseInfo = unityPictureInPictureAd.getResponseInfo(); + verify(mockPipAd).getResponseInfo(); + assertThat(actualResponseInfo).isEqualTo(responseInfo); + } +}