Skip to content

Commit

Permalink
Allow serving Banner ads in AdLoaderAd
Browse files Browse the repository at this point in the history
Allow the `AdLoaderAd` instance to serve `Banner` ads, which are
instances of:

  * `AdManagerAdView` under Android, and
  * `GAMBannerView` under iOS
  • Loading branch information
msbit committed Dec 12, 2022
1 parent 70d33b1 commit 08231cb
Show file tree
Hide file tree
Showing 22 changed files with 1,094 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class AdMessageCodec extends StandardMessageCodec {
private static final byte VALUE_VIDEO_OPTIONS = (byte) 145;
private static final byte VALUE_INLINE_ADAPTIVE_BANNER_AD_SIZE = (byte) 146;
private static final byte VALUE_REQUEST_CONFIGURATION_PARAMS = (byte) 148;
private static final byte VALUE_AD_MANAGER_AD_VIEW_OPTIONS = (byte) 149;
private static final byte VALUE_BANNER_PARAMETERS = (byte) 150;

@NonNull Context context;
@NonNull final FlutterAdSize.AdSizeFactory adSizeFactory;
Expand Down Expand Up @@ -202,6 +204,15 @@ protected void writeValue(ByteArrayOutputStream stream, Object value) {
writeValue(stream, options.clickToExpandRequested);
writeValue(stream, options.customControlsRequested);
writeValue(stream, options.startMuted);
} else if (value instanceof FlutterAdManagerAdViewOptions) {
stream.write(VALUE_AD_MANAGER_AD_VIEW_OPTIONS);
FlutterAdManagerAdViewOptions options = (FlutterAdManagerAdViewOptions) value;
writeValue(stream, options.manualImpressionsEnabled);
} else if (value instanceof FlutterBannerParameters) {
stream.write(VALUE_BANNER_PARAMETERS);
FlutterBannerParameters bannerParameters = (FlutterBannerParameters) value;
writeValue(stream, bannerParameters.sizes);
writeValue(stream, bannerParameters.adManagerAdViewOptions);
} else {
super.writeValue(stream, value);
}
Expand Down Expand Up @@ -336,6 +347,12 @@ protected Object readValueOfType(byte type, ByteBuffer buffer) {
rcb.setTagForUnderAgeOfConsent((Integer) readValueOfType(buffer.get(), buffer));
rcb.setTestDeviceIds((List<String>) readValueOfType(buffer.get(), buffer));
return rcb.build();
case VALUE_AD_MANAGER_AD_VIEW_OPTIONS:
return new FlutterAdManagerAdViewOptions((Boolean) readValueOfType(buffer.get(), buffer));
case VALUE_BANNER_PARAMETERS:
return new FlutterBannerParameters(
(List<FlutterAdSize>) readValueOfType(buffer.get(), buffer),
(FlutterAdManagerAdViewOptions) readValueOfType(buffer.get(), buffer));
default:
return super.readValueOfType(type, buffer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import androidx.annotation.NonNull;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.LoadAdError;
import com.google.android.gms.ads.admanager.AdManagerAdView;
import com.google.android.gms.ads.formats.OnAdManagerAdViewLoadedListener;
import com.google.android.gms.ads.nativead.NativeAd;
import com.google.android.gms.ads.nativead.NativeAd.OnNativeAdLoadedListener;
import java.lang.ref.WeakReference;
Expand Down Expand Up @@ -118,3 +120,20 @@ public void onNativeAdLoaded(@NonNull NativeAd nativeAd) {
}
}
}

/** {@link OnAdManagerAdViewLoadedListener} for banner ads. */
class FlutterAdManagerAdViewLoadedListener implements OnAdManagerAdViewLoadedListener {

private final WeakReference<OnAdManagerAdViewLoadedListener> reference;

FlutterAdManagerAdViewLoadedListener(OnAdManagerAdViewLoadedListener listener) {
reference = new WeakReference<>(listener);
}

@Override
public void onAdManagerAdViewLoaded(AdManagerAdView adView) {
if (reference.get() != null) {
reference.get().onAdManagerAdViewLoaded(adView);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdLoader;
import com.google.android.gms.ads.AdRequest;
Expand Down Expand Up @@ -142,18 +143,33 @@ public void loadAdManagerNativeAd(

/** Load an ad loader ad. */
public void loadAdLoaderAd(
@NonNull String adUnitId, @NonNull AdListener adListener, @NonNull AdRequest request) {
new AdLoader.Builder(context, adUnitId).withAdListener(adListener).build().loadAd(request);
@NonNull String adUnitId,
@NonNull AdListener adListener,
@NonNull AdRequest request,
@Nullable FlutterAdLoaderAd.BannerParameters bannerParameters) {
AdLoader.Builder builder = new AdLoader.Builder(context, adUnitId);
if (bannerParameters != null) {
builder = builder.forAdManagerAdView(bannerParameters.listener, bannerParameters.adSizes);
if (bannerParameters.adManagerAdViewOptions != null) {
builder.withAdManagerAdViewOptions(bannerParameters.adManagerAdViewOptions);
}
}
builder.withAdListener(adListener).build().loadAd(request);
}

/** Load an ad manager ad loader ad. */
public void loadAdManagerAdLoaderAd(
@NonNull String adUnitId,
@NonNull AdListener adListener,
@NonNull AdManagerAdRequest adManagerAdRequest) {
new AdLoader.Builder(context, adUnitId)
.withAdListener(adListener)
.build()
.loadAd(adManagerAdRequest);
@NonNull AdManagerAdRequest adManagerAdRequest,
@Nullable FlutterAdLoaderAd.BannerParameters bannerParameters) {
AdLoader.Builder builder = new AdLoader.Builder(context, adUnitId);
if (bannerParameters != null) {
builder = builder.forAdManagerAdView(bannerParameters.listener, bannerParameters.adSizes);
if (bannerParameters.adManagerAdViewOptions != null) {
builder.withAdManagerAdViewOptions(bannerParameters.adManagerAdViewOptions);
}
}
builder.withAdListener(adListener).build().loadAd(adManagerAdRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,31 @@
package io.flutter.plugins.googlemobileads;

import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.BaseAdView;
import com.google.android.gms.ads.admanager.AdManagerAdView;
import com.google.android.gms.ads.formats.AdManagerAdViewOptions;
import com.google.android.gms.ads.formats.OnAdManagerAdViewLoadedListener;
import io.flutter.plugin.platform.PlatformView;

/**
* A central wrapper for {@link AdManagerAdView}, {@link NativeCustomFormatAd} and {@link NativeAd}
* instances served for a single {@link AdRequest} or {@link AdManagerAdRequest}
*/
class FlutterAdLoaderAd extends FlutterAd {
class FlutterAdLoaderAd extends FlutterAd implements OnAdManagerAdViewLoadedListener {
private static final String TAG = "FlutterAdLoaderAd";

@NonNull private final AdInstanceManager manager;
@NonNull private final String adUnitId;
@NonNull private final FlutterAdLoader adLoader;
@Nullable private FlutterAdRequest request;
@Nullable private FlutterAdManagerAdRequest adManagerRequest;
@Nullable private View view;
@Nullable protected BannerParameters bannerParameters;

static class Builder {
@Nullable private AdInstanceManager manager;
Expand All @@ -39,6 +48,7 @@ static class Builder {
@Nullable private FlutterAdManagerAdRequest adManagerRequest;
@Nullable private Integer id;
@Nullable private FlutterAdLoader adLoader;
@Nullable private FlutterBannerParameters bannerParameters;

public Builder setId(int id) {
this.id = id;
Expand Down Expand Up @@ -70,6 +80,11 @@ public Builder setFlutterAdLoader(@NonNull FlutterAdLoader adLoader) {
return this;
}

public Builder setBanner(@Nullable FlutterBannerParameters bannerParameters) {
this.bannerParameters = bannerParameters;
return this;
}

FlutterAdLoaderAd build() {
if (manager == null) {
throw new IllegalStateException("manager must be provided");
Expand All @@ -90,10 +105,32 @@ FlutterAdLoaderAd build() {
} else {
adLoaderAd = new FlutterAdLoaderAd(id, manager, adUnitId, request, adLoader);
}

if (bannerParameters != null) {
adLoaderAd.bannerParameters =
bannerParameters.asBannerParameters(
new FlutterAdManagerAdViewLoadedListener(adLoaderAd));
}

return adLoaderAd;
}
}

static class BannerParameters {
@NonNull final OnAdManagerAdViewLoadedListener listener;
@NonNull final AdSize[] adSizes;
@Nullable final AdManagerAdViewOptions adManagerAdViewOptions;

BannerParameters(
@NonNull OnAdManagerAdViewLoadedListener listener,
@NonNull AdSize[] adSizes,
@Nullable AdManagerAdViewOptions adManagerAdViewOptions) {
this.listener = listener;
this.adSizes = adSizes;
this.adManagerAdViewOptions = adManagerAdViewOptions;
}
}

protected FlutterAdLoaderAd(
int adId,
@NonNull AdInstanceManager manager,
Expand Down Expand Up @@ -126,19 +163,46 @@ void load() {
// Note we delegate loading the ad to FlutterAdLoader mainly for testing purposes.
// As of 20.0.0 of GMA, mockito is unable to mock AdLoader.
if (request != null) {
adLoader.loadAdLoaderAd(adUnitId, adListener, request.asAdRequest(adUnitId));
adLoader.loadAdLoaderAd(
adUnitId, adListener, request.asAdRequest(adUnitId), bannerParameters);
return;
}

if (adManagerRequest != null) {
adLoader.loadAdManagerAdLoaderAd(
adUnitId, adListener, adManagerRequest.asAdManagerAdRequest(adUnitId));
adUnitId, adListener, adManagerRequest.asAdManagerAdRequest(adUnitId), bannerParameters);
return;
}

Log.e(TAG, "A null or invalid ad request was provided.");
}

@Override
void dispose() {}
@Nullable
public PlatformView getPlatformView() {
if (view == null) {
return null;
}

return new FlutterPlatformView(view);
}

@Override
public void onAdManagerAdViewLoaded(@NonNull AdManagerAdView adView) {
view = adView;
manager.onAdLoaded(adId, adView.getResponseInfo());
}

@Override
void dispose() {
if (view == null) {
return;
}

if (view instanceof BaseAdView) {
((BaseAdView) view).destroy();
}

view = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2022 Google LLC
//
// 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
//
// https://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.c language governing permissions and
// limitations under the License.

package io.flutter.plugins.googlemobileads;

import androidx.annotation.Nullable;
import com.google.android.gms.ads.formats.AdManagerAdViewOptions;

/** A wrapper for {@link com.google.android.gms.ads.formats.AdManagerAdViewOptions}. */
class FlutterAdManagerAdViewOptions {

@Nullable final Boolean manualImpressionsEnabled;

FlutterAdManagerAdViewOptions(@Nullable Boolean manualImpressionsEnabled) {
this.manualImpressionsEnabled = manualImpressionsEnabled;
}

AdManagerAdViewOptions asAdManagerAdViewOptions() {
AdManagerAdViewOptions.Builder builder = new AdManagerAdViewOptions.Builder();
if (manualImpressionsEnabled != null) {
builder.setManualImpressionsEnabled(manualImpressionsEnabled);
}
return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 20222 Google LLC
//
// 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
//
// https://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 io.flutter.plugins.googlemobileads;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.formats.OnAdManagerAdViewLoadedListener;
import java.util.List;

class FlutterBannerParameters {
@NonNull final List<FlutterAdSize> sizes;
@Nullable final FlutterAdManagerAdViewOptions adManagerAdViewOptions;

FlutterBannerParameters(
@NonNull List<FlutterAdSize> sizes,
@Nullable FlutterAdManagerAdViewOptions adManagerAdViewOptions) {
this.sizes = sizes;
this.adManagerAdViewOptions = adManagerAdViewOptions;
}

FlutterAdLoaderAd.BannerParameters asBannerParameters(
@NonNull OnAdManagerAdViewLoadedListener listener) {
AdSize[] adSizes = new AdSize[sizes.size()];
int i = 0;
for (FlutterAdSize size : sizes) {
adSizes[i++] = size.getAdSize();
}
return new FlutterAdLoaderAd.BannerParameters(
listener,
adSizes,
adManagerAdViewOptions != null ? adManagerAdViewOptions.asAdManagerAdViewOptions() : null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ public void onAdInspectorClosed(@Nullable AdInspectorError adInspectorError) {
.setAdManagerRequest(call.<FlutterAdManagerAdRequest>argument("adManagerRequest"))
.setId(call.<Integer>argument("adId"))
.setFlutterAdLoader(new FlutterAdLoader(context))
.setBanner(call.<FlutterBannerParameters>argument("banner"))
.build();
instanceManager.trackAd(adLoaderAd, call.<Integer>argument("adId"));
adLoaderAd.load();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,4 +411,48 @@ public void encodeRequestConfiguration() {
RequestConfiguration.TAG_FOR_UNDER_AGE_OF_CONSENT_FALSE);
assertEquals(result.getTestDeviceIds(), Arrays.asList("test-device-id"));
}

@Test
public void encodeAdManagerAdViewOptionsNull() {
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(null));

final FlutterAdManagerAdViewOptions result =
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
assertNull(result.manualImpressionsEnabled);
}

@Test
public void encodeAdManagerAdViewOptionsTrue() {
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(true));

final FlutterAdManagerAdViewOptions result =
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
assertTrue(result.manualImpressionsEnabled);
}

@Test
public void encodeAdManagerAdViewOptionsFalse() {
final ByteBuffer data = codec.encodeMessage(new FlutterAdManagerAdViewOptions(false));

final FlutterAdManagerAdViewOptions result =
(FlutterAdManagerAdViewOptions) codec.decodeMessage((ByteBuffer) data.position(0));
assertFalse(result.manualImpressionsEnabled);
}

@Test
public void encodeBannerParameters() {
final ByteBuffer data =
codec.encodeMessage(
new FlutterBannerParameters(
Collections.singletonList(new FlutterAdSize(1, 2)),
new FlutterAdManagerAdViewOptions(null)));

final FlutterBannerParameters result =
(FlutterBannerParameters) codec.decodeMessage((ByteBuffer) data.position(0));

assertEquals(result.sizes.size(), 1);
assertEquals(result.sizes.get(0).width, 1);
assertEquals(result.sizes.get(0).height, 2);
assertNull(result.adManagerAdViewOptions.manualImpressionsEnabled);
}
}
Loading

0 comments on commit 08231cb

Please sign in to comment.