From 5c00f1af6e969dca187395336c32c9db2f9c771e Mon Sep 17 00:00:00 2001 From: Vishal Dhiman Date: Wed, 8 Jul 2026 11:45:46 -0700 Subject: [PATCH 1/6] UnityAds adapter: handle non-Activity context on show (GH-3077) Pass a nullable Activity to the Unity SDK instead of hard-rejecting a non-Activity context on show. Removes the unused ERROR_MSG_CONTEXT_NULL. Co-Authored-By: Claude Opus 4.8 --- .../ads/mediation/unity/UnityInterstitialAd.java | 6 ++---- .../mediation/unity/UnityMediationAdapter.java | 2 -- .../ads/mediation/unity/UnityRewardedAd.java | 14 +------------- .../mediation/unity/UnityInterstitialAdTest.kt | 14 ++++++++++++++ .../ads/mediation/unity/UnityRewardedAdTest.kt | 15 +++++---------- 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityInterstitialAd.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityInterstitialAd.java index 306d2721c..bdc9f5d11 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityInterstitialAd.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityInterstitialAd.java @@ -211,13 +211,11 @@ public void showAd(Context context) { "Unity Ads received call to show before successfully loading an ad."); } + Activity activity = context instanceof Activity ? (Activity) context : null; UnityAdsShowOptions unityAdsShowOptions = unityAdsLoader.createUnityAdsShowOptionsWithId(objectId); unityAdsShowOptions.set(KEY_WATERMARK, watermark); // UnityAds can handle a null placement ID so show is always called here. - // Note: Context here is the activity that the publisher passed to GMA SDK's show() method - // (https://developers.google.com/admob/android/reference/com/google/android/gms/ads/appopen/AppOpenAd#show(android.app.Activity)). - // So, this is guaranteed to be an activity context. - unityAdsLoader.show((Activity) context, placementId, unityAdsShowOptions, this); + unityAdsLoader.show(activity, placementId, unityAdsShowOptions, this); } } diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java index f47278b2f..50543acef 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java @@ -146,8 +146,6 @@ public class UnityMediationAdapter extends RtbAdapter { static final String ERROR_MSG_NON_ACTIVITY = "Unity Ads requires an Activity context to load ads."; - static final String ERROR_MSG_CONTEXT_NULL = "Activity context is null."; - static final String ERROR_MSG_INITIALIZATION_FAILURE = "Unity Ads initialization failed: [%s] %s"; /** diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityRewardedAd.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityRewardedAd.java index 887ad17fd..1ddb5b572 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityRewardedAd.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityRewardedAd.java @@ -16,10 +16,8 @@ import static com.google.ads.mediation.unity.UnityAdsAdapterUtils.createSDKError; import static com.google.ads.mediation.unity.UnityMediationAdapter.ADAPTER_ERROR_DOMAIN; -import static com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_CONTEXT_NOT_ACTIVITY; import static com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_INVALID_SERVER_PARAMETERS; import static com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_MISSING_PARAMETERS; -import static com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_NON_ACTIVITY; import static com.google.ads.mediation.unity.UnityMediationAdapter.KEY_WATERMARK; import static com.google.ads.mediation.unity.UnityMediationAdapter.TAG; @@ -139,22 +137,12 @@ public void loadAd(MediationRewardedAdConfiguration mediationRewardedAdConfigura @Override public void showAd(@NonNull Context context) { - if (!(context instanceof Activity)) { - AdError showError = - new AdError(ERROR_CONTEXT_NOT_ACTIVITY, ERROR_MSG_NON_ACTIVITY, ADAPTER_ERROR_DOMAIN); - Log.e(TAG, showError.toString()); - if (mediationRewardedAdCallback != null) { - mediationRewardedAdCallback.onAdFailedToShow(showError); - } - return; - } - Activity activity = (Activity) context; - // Check if the placement is ready before showing if (placementId == null) { Log.w(TAG, "Unity Ads received call to show before successfully loading an ad."); } + Activity activity = context instanceof Activity ? (Activity) context : null; UnityAdsShowOptions unityAdsShowOptions = unityAdsLoader.createUnityAdsShowOptionsWithId(objectId); unityAdsShowOptions.set(KEY_WATERMARK, watermark); diff --git a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityInterstitialAdTest.kt b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityInterstitialAdTest.kt index faa216772..9b8e928ff 100644 --- a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityInterstitialAdTest.kt +++ b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityInterstitialAdTest.kt @@ -2,6 +2,7 @@ package com.google.ads.mediation.unity import android.app.Activity import androidx.core.os.bundleOf +import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.ads.mediation.unity.UnityAdsAdapterUtils.getMediationErrorCode import com.google.ads.mediation.unity.UnityMediationAdapter.SDK_ERROR_DOMAIN @@ -21,10 +22,12 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq +import org.mockito.kotlin.isNull import org.mockito.kotlin.mock import org.mockito.kotlin.notNull import org.mockito.kotlin.spy @@ -133,6 +136,17 @@ class UnityInterstitialAdTest { assertThat(capturedError.domain).isEqualTo(SDK_ERROR_DOMAIN) } + @Test + fun showAd_withNonActivityContext_callsShowWithNullActivity() { + val unityAdsShowOptions: UnityAdsShowOptions = mock() + whenever(unityAdsLoader.createUnityAdsShowOptionsWithId(anyOrNull())) doReturn unityAdsShowOptions + unityInterstitialAd.onUnityAdsAdLoaded(PLACEMENT_ID) + + unityInterstitialAd.showAd(ApplicationProvider.getApplicationContext()) + + verify(unityAdsLoader).show(isNull(), any(), any(), any()) + } + @Test fun showAd_invokesUnityAdsShow() { doAnswer { invocation -> diff --git a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityRewardedAdTest.kt b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityRewardedAdTest.kt index 6f8022a7e..37ce43767 100644 --- a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityRewardedAdTest.kt +++ b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityRewardedAdTest.kt @@ -5,9 +5,6 @@ import androidx.core.os.bundleOf import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.ads.mediation.unity.UnityAdsAdapterUtils.getMediationErrorCode -import com.google.ads.mediation.unity.UnityMediationAdapter.ADAPTER_ERROR_DOMAIN -import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_CONTEXT_NOT_ACTIVITY -import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_NON_ACTIVITY import com.google.ads.mediation.unity.UnityMediationAdapter.SDK_ERROR_DOMAIN import com.google.android.gms.ads.AdError import com.google.android.gms.ads.mediation.MediationAdLoadCallback @@ -25,6 +22,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doReturn @@ -202,17 +200,14 @@ class UnityRewardedAdTest { } @Test - fun showAd_withNonActivityContext_invokesOnAdFailedToShow() { + fun showAd_withNonActivityContext_callsShowWithNullActivity() { + val unityAdsShowOptions: UnityAdsShowOptions = mock() + whenever(unityAdsLoader.createUnityAdsShowOptionsWithId(anyOrNull())) doReturn unityAdsShowOptions unityRewardedAd.unityLoadListener.onUnityAdsAdLoaded(TEST_PLACEMENT_ID) - val errorCaptor = argumentCaptor() unityRewardedAd.showAd(ApplicationProvider.getApplicationContext()) - verify(rewardedAdCallback).onAdFailedToShow(errorCaptor.capture()) - val capturedError = errorCaptor.firstValue - assertThat(capturedError.code).isEqualTo(ERROR_CONTEXT_NOT_ACTIVITY) - assertThat(capturedError.message).isEqualTo(ERROR_MSG_NON_ACTIVITY) - assertThat(capturedError.domain).isEqualTo(ADAPTER_ERROR_DOMAIN) + verify(unityAdsLoader).show(isNull(), any(), any(), any()) } @Test From f3bb9ceb1c6c8971b42df6f1faa0b30b937cfed8 Mon Sep 17 00:00:00 2001 From: Vishal Dhiman Date: Wed, 8 Jul 2026 11:47:38 -0700 Subject: [PATCH 2/6] UnityAds adapter: route null/empty bidding token to onFailure collectSignals treated a null/empty token as an empty success, so the bidder billed Unity as a no-fill. Route null/empty tokens to SignalCallbacks.onFailure via RoutingTokenListener (new error code 112). Co-Authored-By: Claude Opus 4.8 --- .../unity/UnityMediationAdapter.java | 48 ++++++++++++------ .../unity/UnityMediationAdapterTest.kt | 49 +++++++++++++++++++ 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java index 50543acef..44b999954 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java @@ -44,6 +44,7 @@ import com.google.android.gms.ads.mediation.rtb.RtbSignalData; import com.google.android.gms.ads.mediation.rtb.SignalCallbacks; import com.unity3d.ads.IUnityAdsInitializationListener; +import com.unity3d.ads.IUnityAdsTokenListener; import com.unity3d.ads.TokenConfiguration; import com.unity3d.ads.UnityAds; import java.lang.annotation.Retention; @@ -87,7 +88,8 @@ public class UnityMediationAdapter extends RtbAdapter { ERROR_UNITY_ADS_NOT_SUPPORTED, ERROR_FINISH, ERROR_BANNER_SIZE_MISMATCH, - ERROR_INITIALIZATION_FAILURE + ERROR_INITIALIZATION_FAILURE, + ERROR_TOKEN_GENERATION_FAILED }) @interface AdapterError { @@ -141,6 +143,9 @@ public class UnityMediationAdapter extends RtbAdapter { */ static final int ERROR_INITIALIZATION_FAILURE = 111; + /** UnityAds returned no usable bidding token; routed to onFailure so the bidder skips Unity. */ + static final int ERROR_TOKEN_GENERATION_FAILED = 112; + static final String ERROR_MSG_MISSING_PARAMETERS = "Missing or invalid server parameters."; static final String ERROR_MSG_NON_ACTIVITY = @@ -228,24 +233,35 @@ public void collectSignals( Log.w(TAG, "Unsupported ad format for Unity Ads: " + adFormat); } + IUnityAdsTokenListener listener = new RoutingTokenListener(signalCallbacks); if (unityAdFormat != null) { TokenConfiguration tokenConfiguration = new TokenConfiguration(unityAdFormat); - unityAdsWrapper.getToken( - tokenConfiguration, - token -> { - if (token == null) { - token = ""; - } - signalCallbacks.onSuccess(token); - }); + unityAdsWrapper.getToken(tokenConfiguration, listener); } else { - unityAdsWrapper.getToken( - token -> { - if (token == null) { - token = ""; - } - signalCallbacks.onSuccess(token); - }); + unityAdsWrapper.getToken(listener); + } + } + + /** Routes a null/empty token or a token failure to onFailure, invoking signalCallbacks once. */ + @VisibleForTesting + static final class RoutingTokenListener implements IUnityAdsTokenListener { + private final SignalCallbacks signalCallbacks; + + RoutingTokenListener(@NonNull SignalCallbacks signalCallbacks) { + this.signalCallbacks = signalCallbacks; + } + + @Override + public void onUnityAdsTokenReady(String token) { + if (TextUtils.isEmpty(token)) { + signalCallbacks.onFailure( + new AdError( + ERROR_TOKEN_GENERATION_FAILED, + "Unity Ads returned a null or empty bidding token.", + ADAPTER_ERROR_DOMAIN)); + return; + } + signalCallbacks.onSuccess(token); } } diff --git a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt index de393c1db..f5607c4c7 100644 --- a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt +++ b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt @@ -17,6 +17,7 @@ import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_INVALID_SERVER import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_INITIALIZATION_FAILURE import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_MISSING_PARAMETERS import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_NON_ACTIVITY +import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_TOKEN_GENERATION_FAILED import com.google.ads.mediation.unity.UnityMediationAdapter.SDK_ERROR_DOMAIN import com.google.ads.mediation.unity.UnityMediationBannerAd.ERROR_MSG_INITIALIZATION_FAILED_FOR_GAME_ID import com.google.ads.mediation.unity.UnityMediationBannerAd.ERROR_MSG_NO_MATCHING_AD_SIZE @@ -340,6 +341,54 @@ class UnityMediationAdapterTest { verifyNoMoreInteractions(signalCallbacks) } + @Test + fun collectSignals_whenSdkReturnsNullToken_routesToOnFailure() { + // Legacy SDK path: only onUnityAdsTokenReady is called, with null. + whenever(unityAdsWrapper.getToken(any(), any())) doAnswer + { invocation -> + val callback = invocation.arguments[1] as IUnityAdsTokenListener + callback.onUnityAdsTokenReady(null) + } + + val rtbSignalData = + RtbSignalData( + activity, + listOf(MediationConfiguration(AdFormat.INTERSTITIAL, /* serverParameters= */ bundleOf())), + /* networkExtras= */ bundleOf(), + null, + ) + + unityMediationAdapter.collectSignals(rtbSignalData, signalCallbacks) + + val adErrorCaptor = argumentCaptor() + verify(signalCallbacks).onFailure(adErrorCaptor.capture()) + assertEquals(ERROR_TOKEN_GENERATION_FAILED, adErrorCaptor.firstValue.code) + assertEquals(ADAPTER_ERROR_DOMAIN, adErrorCaptor.firstValue.domain) + verifyNoMoreInteractions(signalCallbacks) + } + + @Test + fun collectSignals_whenSdkReturnsEmptyToken_routesToOnFailure() { + whenever(unityAdsWrapper.getToken(any(), any())) doAnswer + { invocation -> + val callback = invocation.arguments[1] as IUnityAdsTokenListener + callback.onUnityAdsTokenReady("") + } + + val rtbSignalData = + RtbSignalData( + activity, + listOf(MediationConfiguration(AdFormat.INTERSTITIAL, /* serverParameters= */ bundleOf())), + /* networkExtras= */ bundleOf(), + null, + ) + + unityMediationAdapter.collectSignals(rtbSignalData, signalCallbacks) + + verify(signalCallbacks).onFailure(any()) + verify(signalCallbacks, never()).onSuccess(any()) + } + @Test fun collectSignals_forUnsupportedFormat_invokesSignalCallbacks() { whenever(unityAdsWrapper.getToken(any())) doAnswer From a0ce9fa94f54ddd0c3d2a86a3552676e2ab633ab Mon Sep 17 00:00:00 2001 From: Vishal Dhiman Date: Wed, 15 Jul 2026 15:28:08 -0700 Subject: [PATCH 3/6] Address PR feedback: remove banner Activity-context requirement BannerView accepts a plain Context since Unity Ads SDK 4.16.2, so drop the Activity checks in collectSignals and the banner load path and pass the context through directly. Also tighten the RoutingTokenListener Javadoc to the implemented behavior. Co-Authored-By: Claude Fable 5 --- .../unity/UnityBannerViewFactory.java | 6 ++-- .../unity/UnityMediationAdapter.java | 15 +--------- .../unity/UnityMediationBannerAd.java | 16 +--------- .../unity/UnityMediationAdapterTest.kt | 30 ++++++++----------- 4 files changed, 18 insertions(+), 49 deletions(-) diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityBannerViewFactory.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityBannerViewFactory.java index 678b5ed4a..4f6a7909a 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityBannerViewFactory.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityBannerViewFactory.java @@ -1,14 +1,14 @@ package com.google.ads.mediation.unity; -import android.app.Activity; +import android.content.Context; import com.unity3d.services.banners.BannerView; import com.unity3d.services.banners.UnityBannerSize; /** A factory to create UnityAds {@link BannerView} for Banner Ads */ class UnityBannerViewFactory { UnityBannerViewWrapper createBannerView( - Activity activity, String placementId, UnityBannerSize bannerSize) { - BannerView bannerView = new BannerView(activity, placementId, bannerSize); + Context context, String placementId, UnityBannerSize bannerSize) { + BannerView bannerView = new BannerView(context, placementId, bannerSize); return new UnityBannerViewWrapper(bannerView); } } diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java index 44b999954..a0c388c55 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java @@ -17,7 +17,6 @@ import static com.google.ads.mediation.unity.UnityAdsAdapterUtils.createSDKError; import static com.google.ads.mediation.unity.UnityAdsAdapterUtils.getAdFormat; -import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.text.TextUtils; @@ -211,18 +210,6 @@ public void collectSignals( AdFormat adFormat = getAdFormat(rtbSignalData); com.unity3d.ads.AdFormat unityAdFormat = null; - // For banner ad format, Unity Ads SDK requires an activity context to load the banner ad. So, - // fail here so that Unity bidder will not bid if the ad request was made with a non-activity - // context. - if (adFormat == AdFormat.BANNER && !(rtbSignalData.getContext() instanceof Activity)) { - signalCallbacks.onFailure( - new AdError( - ERROR_CONTEXT_NOT_ACTIVITY, - "Unity Ads RTB Banner ads require activity context", - ADAPTER_ERROR_DOMAIN)); - return; - } - if (adFormat == AdFormat.BANNER) { unityAdFormat = com.unity3d.ads.AdFormat.BANNER; } else if (adFormat == AdFormat.REWARDED || adFormat == AdFormat.REWARDED_INTERSTITIAL) { @@ -242,7 +229,7 @@ public void collectSignals( } } - /** Routes a null/empty token or a token failure to onFailure, invoking signalCallbacks once. */ + /** Routes a null or empty token to onFailure and a non-empty token to onSuccess. */ @VisibleForTesting static final class RoutingTokenListener implements IUnityAdsTokenListener { private final SignalCallbacks signalCallbacks; diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationBannerAd.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationBannerAd.java index 39c40f8a2..65dc4c9ab 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationBannerAd.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationBannerAd.java @@ -19,10 +19,8 @@ import static com.google.ads.mediation.unity.UnityAdsAdapterUtils.getMediationErrorCode; import static com.google.ads.mediation.unity.UnityMediationAdapter.ADAPTER_ERROR_DOMAIN; import static com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_MISSING_PARAMETERS; -import static com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_NON_ACTIVITY; import static com.google.ads.mediation.unity.UnityMediationAdapter.KEY_WATERMARK; -import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.text.TextUtils; @@ -176,18 +174,6 @@ public void loadAd( return; } - if (!(context instanceof Activity)) { - AdError adError = - new AdError( - UnityMediationAdapter.ERROR_CONTEXT_NOT_ACTIVITY, - ERROR_MSG_NON_ACTIVITY, - ADAPTER_ERROR_DOMAIN); - Log.w(UnityMediationAdapter.TAG, adError.toString()); - mediationBannerAdLoadCallback.onFailure(adError); - return; - } - final Activity activity = (Activity) context; - final String adMarkup = mediationBannerAdConfiguration.getBidResponse(); // It is RTB if adMarkup is not empty. @@ -224,7 +210,7 @@ public void onInitializationComplete() { if (unityBannerViewWrapper == null) { unityBannerViewWrapper = unityBannerViewFactory.createBannerView( - activity, bannerPlacementId, unityBannerSize); + context, bannerPlacementId, unityBannerSize); } unityBannerViewWrapper.setListener(UnityMediationBannerAd.this); diff --git a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt index f5607c4c7..17192bac8 100644 --- a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt +++ b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt @@ -12,11 +12,9 @@ import com.google.ads.mediation.unity.UnityInitializer.KEY_ADAPTER_VERSION import com.google.ads.mediation.unity.UnityInterstitialAd.ERROR_MSG_INTERSTITIAL_INITIALIZATION_FAILED import com.google.ads.mediation.unity.UnityMediationAdapter.ADAPTER_ERROR_DOMAIN import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_BANNER_SIZE_MISMATCH -import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_CONTEXT_NOT_ACTIVITY import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_INVALID_SERVER_PARAMETERS import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_INITIALIZATION_FAILURE import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_MISSING_PARAMETERS -import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_MSG_NON_ACTIVITY import com.google.ads.mediation.unity.UnityMediationAdapter.ERROR_TOKEN_GENERATION_FAILED import com.google.ads.mediation.unity.UnityMediationAdapter.SDK_ERROR_DOMAIN import com.google.ads.mediation.unity.UnityMediationBannerAd.ERROR_MSG_INITIALIZATION_FAILED_FOR_GAME_ID @@ -219,7 +217,13 @@ class UnityMediationAdapterTest { } @Test - fun collectSignals_forBannerFormatAndNonActivityContext_fails() { + fun collectSignals_forBannerFormatAndNonActivityContext_invokesSignalCallbacks() { + whenever(unityAdsWrapper.getToken(any(), any())) doAnswer + { invocation -> + val callback = invocation.arguments[1] as IUnityAdsTokenListener + callback.onUnityAdsTokenReady(TEST_TOKEN) + } + val rtbSignalData = RtbSignalData( nonActivityContext, @@ -230,12 +234,7 @@ class UnityMediationAdapterTest { unityMediationAdapter.collectSignals(rtbSignalData, signalCallbacks) - val adErrorCaptor = argumentCaptor() - verify(signalCallbacks).onFailure(adErrorCaptor.capture()) - val adError = adErrorCaptor.firstValue - assertThat(adError.code).isEqualTo(ERROR_CONTEXT_NOT_ACTIVITY) - assertThat(adError.domain).isEqualTo(ADAPTER_ERROR_DOMAIN) - verifyNoMoreInteractions(signalCallbacks) + verify(signalCallbacks).onSuccess(TEST_TOKEN) } @Test @@ -500,20 +499,17 @@ class UnityMediationAdapterTest { } @Test - fun loadBannerAd_withNonActivityContext_failsWithAdError() { - mediationBannerAdConfiguration = initializeBannerAd(ApplicationProvider.getApplicationContext()) + fun loadBannerAd_withNonActivityContext_callsInitializeUnityAds() { + mediationBannerAdConfiguration = initializeBannerAd(nonActivityContext) + whenever(mediationUtils.findClosestSize(eq(nonActivityContext), eq(AdSize.BANNER), any())) doReturn + AdSize.BANNER unityMediationAdapter.loadBannerAd( mediationBannerAdConfiguration, mediationBannerAdLoadCallback, ) - val adErrorCaptor = argumentCaptor() - verify(mediationBannerAdLoadCallback).onFailure(adErrorCaptor.capture()) - val capturedError = adErrorCaptor.firstValue - assertThat(capturedError.code).isEqualTo(ERROR_CONTEXT_NOT_ACTIVITY) - assertThat(capturedError.message).isEqualTo(ERROR_MSG_NON_ACTIVITY) - assertThat(capturedError.domain).isEqualTo(ADAPTER_ERROR_DOMAIN) + verify(unityInitializer).initializeUnityAds(any(), any(), any()) } @Test From eea4fd87934cc8e910a7124d4c2a620bffc84a0b Mon Sep 17 00:00:00 2001 From: Vishal Dhiman Date: Thu, 16 Jul 2026 09:00:01 -0700 Subject: [PATCH 4/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../com/google/ads/mediation/unity/UnityMediationAdapter.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java index a0c388c55..fa9efa3c8 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java @@ -147,8 +147,6 @@ public class UnityMediationAdapter extends RtbAdapter { static final String ERROR_MSG_MISSING_PARAMETERS = "Missing or invalid server parameters."; - static final String ERROR_MSG_NON_ACTIVITY = - "Unity Ads requires an Activity context to load ads."; static final String ERROR_MSG_INITIALIZATION_FAILURE = "Unity Ads initialization failed: [%s] %s"; From 3fe5a2e677d5457c0c1e4057619a430d249b98af Mon Sep 17 00:00:00 2001 From: Vishal Dhiman Date: Thu, 16 Jul 2026 09:02:12 -0700 Subject: [PATCH 5/6] Remove unused ERROR_CONTEXT_NOT_ACTIVITY and ERROR_MSG_NON_ACTIVITY No longer referenced after dropping the Activity-context requirements. Co-Authored-By: Claude Fable 5 --- .../google/ads/mediation/unity/UnityMediationAdapter.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java index fa9efa3c8..d2b58c070 100644 --- a/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java +++ b/ThirdPartyAdapters/unity/unity/src/main/java/com/google/ads/mediation/unity/UnityMediationAdapter.java @@ -82,7 +82,6 @@ public class UnityMediationAdapter extends RtbAdapter { ERROR_PLACEMENT_STATE_NO_FILL, ERROR_PLACEMENT_STATE_DISABLED, ERROR_NULL_CONTEXT, - ERROR_CONTEXT_NOT_ACTIVITY, ERROR_AD_NOT_READY, ERROR_UNITY_ADS_NOT_SUPPORTED, ERROR_FINISH, @@ -114,9 +113,6 @@ public class UnityMediationAdapter extends RtbAdapter { */ static final int ERROR_NULL_CONTEXT = 104; - /** Tried to load or show an ad with a non-Activity context. */ - static final int ERROR_CONTEXT_NOT_ACTIVITY = 105; - /** * Tried to show an ad that's not ready to be shown. */ @@ -147,7 +143,6 @@ public class UnityMediationAdapter extends RtbAdapter { static final String ERROR_MSG_MISSING_PARAMETERS = "Missing or invalid server parameters."; - static final String ERROR_MSG_INITIALIZATION_FAILURE = "Unity Ads initialization failed: [%s] %s"; /** From 7ce21a70ed7048bf96b582876e21f3f299852016 Mon Sep 17 00:00:00 2001 From: Vishal Dhiman Date: Thu, 16 Jul 2026 11:37:31 -0700 Subject: [PATCH 6/6] Address PR feedback: assert no unexpected callbacks in banner non-Activity test Copilot flagged that the test only checked onSuccess() and would still pass if onFailure or other callbacks were also invoked. Co-Authored-By: Claude Sonnet 5 --- .../com/google/ads/mediation/unity/UnityMediationAdapterTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt index 17192bac8..2287f8b3d 100644 --- a/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt +++ b/ThirdPartyAdapters/unity/unity/src/test/kotlin/com/google/ads/mediation/unity/UnityMediationAdapterTest.kt @@ -235,6 +235,7 @@ class UnityMediationAdapterTest { unityMediationAdapter.collectSignals(rtbSignalData, signalCallbacks) verify(signalCallbacks).onSuccess(TEST_TOKEN) + verifyNoMoreInteractions(signalCallbacks) } @Test