Skip to content

Commit be4e332

Browse files
Mobile Ads Developer Relationscopybara-github
authored andcommitted
This change introduces the UnityBannerAdPreloader class, which wraps the GMA SDK's BannerAdPreloader. It provides methods to start preloading banner ads, check ad availability, poll preloaded ads, and manage preload configurations. Callbacks from the GMA SDK are executed on a separate thread to avoid blocking the Unity main thread. Unit tests are included to verify the functionality of the UnityBannerAdPreloader.
END_PUBLIC PiperOrigin-RevId: 909744560
1 parent 4f174bd commit be4e332

8 files changed

Lines changed: 590 additions & 8 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (C) 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.unity.ads.nextgen;
18+
19+
import java.util.concurrent.ExecutorService;
20+
import java.util.concurrent.Executors;
21+
import java.util.concurrent.ThreadFactory;
22+
23+
/** Centralized executor service for running nextgen ad preloader callbacks. */
24+
public final class PreloaderExecutor {
25+
private static final ExecutorService service =
26+
Executors.newSingleThreadExecutor(
27+
new ThreadFactory() {
28+
@Override
29+
public Thread newThread(Runnable r) {
30+
return new Thread(r, "GMAUnityThread");
31+
}
32+
});
33+
34+
public static ExecutorService getExecutor() {
35+
return service;
36+
}
37+
38+
private PreloaderExecutor() {}
39+
}

source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityAppOpenAdPreloader.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import com.google.android.libraries.ads.mobile.sdk.common.ResponseInfo;
1313
import java.util.Map;
1414
import java.util.concurrent.ExecutorService;
15-
import java.util.concurrent.Executors;
1615

1716
/** Unity implementation of the {@link AppOpenAdPreloader}. */
1817
public class UnityAppOpenAdPreloader {
@@ -36,7 +35,7 @@ public UnityAppOpenAdPreloader(Activity activity, UnityPreloadCallback preloadCa
3635
activity,
3736
preloadCallback,
3837
new AppOpenAdPreloaderWrapper(),
39-
Executors.newSingleThreadExecutor());
38+
PreloaderExecutor.getExecutor());
4039
}
4140

4241
@VisibleForTesting

source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityBannerAd.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import android.widget.FrameLayout;
2727
import androidx.annotation.NonNull;
2828
import androidx.annotation.Nullable;
29-
import androidx.annotation.VisibleForTesting;
3029
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAd;
3130
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAdEventCallback;
3231
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAdRequest;
@@ -99,7 +98,6 @@ public UnityBannerAd(Activity activity, UnityBannerAdCallback callback) {
9998
this(activity, callback, AdWrapper.forBanner());
10099
}
101100

102-
@VisibleForTesting
103101
UnityBannerAd(Activity activity, UnityBannerAdCallback callback, AdWrapper<BannerAd> adWrapper) {
104102
unityPlayerActivity = activity;
105103
this.callback = callback;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package com.google.unity.ads.nextgen;
2+
3+
import android.app.Activity;
4+
import androidx.annotation.NonNull;
5+
import androidx.annotation.Nullable;
6+
import androidx.annotation.VisibleForTesting;
7+
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAd;
8+
import com.google.android.libraries.ads.mobile.sdk.banner.BannerAdPreloader;
9+
import com.google.android.libraries.ads.mobile.sdk.common.AdLoadCallback;
10+
import com.google.android.libraries.ads.mobile.sdk.common.AdRequest;
11+
import com.google.android.libraries.ads.mobile.sdk.common.LoadAdError;
12+
import com.google.android.libraries.ads.mobile.sdk.common.PreloadCallback;
13+
import com.google.android.libraries.ads.mobile.sdk.common.PreloadConfiguration;
14+
import com.google.android.libraries.ads.mobile.sdk.common.ResponseInfo;
15+
import java.util.Map;
16+
import java.util.concurrent.ExecutorService;
17+
18+
/** Unity implementation of the {@link BannerAdPreloader}. */
19+
public class UnityBannerAdPreloader {
20+
21+
/** The {@code Activity} on which the banner ad will display. */
22+
private final Activity activity;
23+
24+
/** An executor used to run the callbacks. */
25+
private final ExecutorService service;
26+
27+
/**
28+
* A {@code UnityPreloadCallback} implemented in Unity via {@code AndroidJavaProxy} to receive ad
29+
* events.
30+
*/
31+
private final UnityPreloadCallback preloadCallback;
32+
33+
private final BannerAdPreloaderWrapper preloaderWrapper;
34+
35+
public UnityBannerAdPreloader(Activity activity, UnityPreloadCallback preloadCallback) {
36+
this(
37+
activity, preloadCallback, new BannerAdPreloaderWrapper(), PreloaderExecutor.getExecutor());
38+
}
39+
40+
@VisibleForTesting
41+
public UnityBannerAdPreloader(
42+
Activity activity,
43+
UnityPreloadCallback preloadCallback,
44+
BannerAdPreloaderWrapper preloaderWrapper,
45+
ExecutorService service) {
46+
this.activity = activity;
47+
this.preloadCallback = preloadCallback;
48+
this.service = service;
49+
this.preloaderWrapper = preloaderWrapper;
50+
}
51+
52+
public boolean start(String preloadId, PreloadConfiguration preloadConfiguration) {
53+
return preloaderWrapper.start(
54+
preloadId,
55+
preloadConfiguration,
56+
new PreloadCallback() {
57+
@Override
58+
public void onAdPreloaded(@NonNull String preloadId, ResponseInfo responseInfo) {
59+
service.execute(
60+
() -> {
61+
if (preloadCallback != null) {
62+
preloadCallback.onAdPreloaded(preloadId, responseInfo);
63+
}
64+
});
65+
}
66+
67+
@Override
68+
public void onAdsExhausted(@NonNull String preloadId) {
69+
service.execute(
70+
() -> {
71+
if (preloadCallback != null) {
72+
preloadCallback.onAdsExhausted(preloadId);
73+
}
74+
});
75+
}
76+
77+
@Override
78+
public void onAdFailedToPreload(@NonNull String preloadId, @NonNull LoadAdError adError) {
79+
service.execute(
80+
() -> {
81+
if (preloadCallback != null) {
82+
preloadCallback.onAdFailedToPreload(preloadId, adError);
83+
}
84+
});
85+
}
86+
});
87+
}
88+
89+
public boolean isAdAvailable(String preloadId) {
90+
return preloaderWrapper.isAdAvailable(preloadId);
91+
}
92+
93+
public int getNumAdsAvailable(String preloadId) {
94+
return preloaderWrapper.getNumAdsAvailable(preloadId);
95+
}
96+
97+
@SuppressWarnings("VisibleForTests")
98+
@Nullable
99+
public UnityBannerAd pollAd(String preloadId, UnityBannerAdCallback callback) {
100+
final BannerAd pooledAd = preloaderWrapper.pollAd(preloadId);
101+
if (pooledAd == null) {
102+
return null;
103+
}
104+
AdWrapper<BannerAd> preloadedWrapper =
105+
new AdWrapper<BannerAd>(
106+
new AdWrapper.AdLoader<BannerAd>() {
107+
@Override
108+
public void load(AdRequest adRequest, AdLoadCallback<BannerAd> loadCallback) {
109+
loadCallback.onAdLoaded(pooledAd);
110+
}
111+
});
112+
return new UnityBannerAd(activity, callback, preloadedWrapper);
113+
}
114+
115+
@Nullable
116+
public PreloadConfiguration getConfiguration(String preloadId) {
117+
return preloaderWrapper.getConfiguration(preloadId);
118+
}
119+
120+
public Map<String, PreloadConfiguration> getConfigurations() {
121+
return preloaderWrapper.getConfigurations();
122+
}
123+
124+
public void destroy(String preloadId) {
125+
boolean unused = preloaderWrapper.destroy(preloadId);
126+
}
127+
128+
/** Wrapper for BannerAdPreloader static methods to facilitate testing. */
129+
@VisibleForTesting
130+
public static class BannerAdPreloaderWrapper {
131+
public boolean start(String preloadId, PreloadConfiguration config, PreloadCallback callback) {
132+
return BannerAdPreloader.start(preloadId, config, callback);
133+
}
134+
135+
public boolean isAdAvailable(String preloadId) {
136+
return BannerAdPreloader.isAdAvailable(preloadId);
137+
}
138+
139+
public int getNumAdsAvailable(String preloadId) {
140+
return BannerAdPreloader.getNumAdsAvailable(preloadId);
141+
}
142+
143+
public BannerAd pollAd(String preloadId) {
144+
return BannerAdPreloader.pollAd(preloadId);
145+
}
146+
147+
public PreloadConfiguration getConfiguration(String preloadId) {
148+
return BannerAdPreloader.getConfiguration(preloadId);
149+
}
150+
151+
public Map<String, PreloadConfiguration> getConfigurations() {
152+
return BannerAdPreloader.getConfigurations();
153+
}
154+
155+
public boolean destroy(String preloadId) {
156+
return BannerAdPreloader.destroy(preloadId);
157+
}
158+
}
159+
}

source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityInterstitialAdPreloader.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import com.google.android.libraries.ads.mobile.sdk.interstitial.InterstitialAdPreloader;
1313
import java.util.Map;
1414
import java.util.concurrent.ExecutorService;
15-
import java.util.concurrent.Executors;
1615

1716
/** Unity implementation of the {@link InterstitialAdPreloader}. */
1817
public class UnityInterstitialAdPreloader {
@@ -36,7 +35,7 @@ public UnityInterstitialAdPreloader(Activity activity, UnityPreloadCallback prel
3635
activity,
3736
preloadCallback,
3837
new InterstitialAdPreloaderWrapper(),
39-
Executors.newSingleThreadExecutor());
38+
PreloaderExecutor.getExecutor());
4039
}
4140

4241
@VisibleForTesting

source/plugin/Assets/Plugins/Android/GoogleMobileAdsPlugin.androidlib/src/main/java/com/google/unity/ads/nextgen/UnityRewardedAdPreloader.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import com.google.android.libraries.ads.mobile.sdk.rewarded.RewardedAdPreloader;
1313
import java.util.Map;
1414
import java.util.concurrent.ExecutorService;
15-
import java.util.concurrent.Executors;
1615

1716
/** Unity implementation of the {@link RewardedAdPreloader}. */
1817
public class UnityRewardedAdPreloader {
@@ -36,7 +35,7 @@ public UnityRewardedAdPreloader(Activity activity, UnityPreloadCallback preloadC
3635
activity,
3736
preloadCallback,
3837
new RewardedAdPreloaderWrapper(),
39-
Executors.newSingleThreadExecutor());
38+
PreloaderExecutor.getExecutor());
4039
}
4140

4241
@VisibleForTesting

0 commit comments

Comments
 (0)