Encapsulate ImaAdsLoader configuration in a class

This will reduce the amount of boilerplate required to pass the configuration
values around (especially in a planned future change when logic is factored out
of ImaAdsLoader).

PiperOrigin-RevId: 337058355
This commit is contained in:
andrewlewis 2020-10-14 11:52:19 +01:00 committed by Oliver Woodman
parent 53c4a393f3
commit 5cc6dac77c
2 changed files with 122 additions and 56 deletions

View File

@ -347,7 +347,11 @@ public final class ImaAdsLoader
@Deprecated @Deprecated
public ImaAdsLoader buildForAdTag(Uri adTagUri) { public ImaAdsLoader buildForAdTag(Uri adTagUri) {
return new ImaAdsLoader( return new ImaAdsLoader(
/* builder= */ this, /* adTagUri= */ adTagUri, /* adsResponse= */ null); context,
getConfiguration(),
imaFactory,
/* adTagUri= */ adTagUri,
/* adsResponse= */ null);
} }
/** /**
@ -364,12 +368,31 @@ public final class ImaAdsLoader
*/ */
@Deprecated @Deprecated
public ImaAdsLoader buildForAdsResponse(String adsResponse) { public ImaAdsLoader buildForAdsResponse(String adsResponse) {
return new ImaAdsLoader(/* builder= */ this, /* adTagUri= */ null, adsResponse); return new ImaAdsLoader(
context, getConfiguration(), imaFactory, /* adTagUri= */ null, adsResponse);
} }
/** Returns a new {@link ImaAdsLoader}. */ /** Returns a new {@link ImaAdsLoader}. */
public ImaAdsLoader build() { public ImaAdsLoader build() {
return new ImaAdsLoader(/* builder= */ this, /* adTagUri= */ null, /* adsResponse= */ null); return new ImaAdsLoader(
context, getConfiguration(), imaFactory, /* adTagUri= */ null, /* adsResponse= */ null);
}
// TODO(internal: b/169646419): Remove/hide once the deprecated constructor has been removed.
/* package */ ImaUtil.Configuration getConfiguration() {
return new ImaUtil.Configuration(
adPreloadTimeoutMs,
vastLoadTimeoutMs,
mediaLoadTimeoutMs,
focusSkipButtonWhenAvailable,
playAdBeforeStartPosition,
mediaBitrate,
adUiElements,
companionAdSlots,
adErrorListener,
adEventListener,
videoAdPlayerCallback,
imaSdkSettings);
} }
} }
@ -426,20 +449,11 @@ public final class ImaAdsLoader
private static final DataSpec EMPTY_AD_TAG_DATA_SPEC = new DataSpec(Uri.EMPTY); private static final DataSpec EMPTY_AD_TAG_DATA_SPEC = new DataSpec(Uri.EMPTY);
private final ImaUtil.Configuration configuration;
private final Context context; private final Context context;
private final ImaUtil.ImaFactory imaFactory;
@Nullable private final Uri adTagUri; @Nullable private final Uri adTagUri;
@Nullable private final String adsResponse; @Nullable private final String adsResponse;
private final long adPreloadTimeoutMs;
private final int vastLoadTimeoutMs;
private final int mediaLoadTimeoutMs;
private final boolean focusSkipButtonWhenAvailable;
private final boolean playAdBeforeStartPosition;
private final int mediaBitrate;
@Nullable private final Set<UiElement> adUiElements;
@Nullable private final Collection<CompanionAdSlot> companionAdSlots;
@Nullable private final AdErrorListener adErrorListener;
@Nullable private final AdEventListener adEventListener;
private final ImaUtil.ImaFactory imaFactory;
private final ImaSdkSettings imaSdkSettings; private final ImaSdkSettings imaSdkSettings;
private final Timeline.Period period; private final Timeline.Period period;
private final Handler handler; private final Handler handler;
@ -539,26 +553,27 @@ public final class ImaAdsLoader
*/ */
@Deprecated @Deprecated
public ImaAdsLoader(Context context, Uri adTagUri) { public ImaAdsLoader(Context context, Uri adTagUri) {
this(new Builder(context), adTagUri, /* adsResponse= */ null); this(
context,
new Builder(context).getConfiguration(),
new DefaultImaFactory(),
adTagUri,
/* adsResponse= */ null);
} }
@SuppressWarnings({"nullness:argument.type.incompatible", "methodref.receiver.bound.invalid"}) @SuppressWarnings({"nullness:argument.type.incompatible", "methodref.receiver.bound.invalid"})
private ImaAdsLoader(Builder builder, @Nullable Uri adTagUri, @Nullable String adsResponse) { private ImaAdsLoader(
this.context = builder.context.getApplicationContext(); Context context,
ImaUtil.Configuration configuration,
ImaUtil.ImaFactory imaFactory,
@Nullable Uri adTagUri,
@Nullable String adsResponse) {
this.context = context.getApplicationContext();
this.configuration = configuration;
this.imaFactory = imaFactory;
this.adTagUri = adTagUri; this.adTagUri = adTagUri;
this.adsResponse = adsResponse; this.adsResponse = adsResponse;
this.adPreloadTimeoutMs = builder.adPreloadTimeoutMs; @Nullable ImaSdkSettings imaSdkSettings = configuration.imaSdkSettings;
this.vastLoadTimeoutMs = builder.vastLoadTimeoutMs;
this.mediaLoadTimeoutMs = builder.mediaLoadTimeoutMs;
this.mediaBitrate = builder.mediaBitrate;
this.focusSkipButtonWhenAvailable = builder.focusSkipButtonWhenAvailable;
this.playAdBeforeStartPosition = builder.playAdBeforeStartPosition;
this.adUiElements = builder.adUiElements;
this.companionAdSlots = builder.companionAdSlots;
this.adErrorListener = builder.adErrorListener;
this.adEventListener = builder.adEventListener;
this.imaFactory = builder.imaFactory;
@Nullable ImaSdkSettings imaSdkSettings = builder.imaSdkSettings;
if (imaSdkSettings == null) { if (imaSdkSettings == null) {
imaSdkSettings = imaFactory.createImaSdkSettings(); imaSdkSettings = imaFactory.createImaSdkSettings();
if (DEBUG) { if (DEBUG) {
@ -572,8 +587,8 @@ public final class ImaAdsLoader
handler = Util.createHandler(getImaLooper(), /* callback= */ null); handler = Util.createHandler(getImaLooper(), /* callback= */ null);
componentListener = new ComponentListener(); componentListener = new ComponentListener();
adCallbacks = new ArrayList<>(/* initialCapacity= */ 1); adCallbacks = new ArrayList<>(/* initialCapacity= */ 1);
if (builder.videoAdPlayerCallback != null) { if (configuration.applicationVideoAdPlayerCallback != null) {
adCallbacks.add(builder.videoAdPlayerCallback); adCallbacks.add(configuration.applicationVideoAdPlayerCallback);
} }
updateAdProgressRunnable = this::updateAdProgress; updateAdProgressRunnable = this::updateAdProgress;
adInfoByAdMediaInfo = HashBiMap.create(); adInfoByAdMediaInfo = HashBiMap.create();
@ -675,8 +690,8 @@ public final class ImaAdsLoader
this.adTagDataSpec = adTagDataSpec; this.adTagDataSpec = adTagDataSpec;
pendingAdRequestContext = new Object(); pendingAdRequestContext = new Object();
request.setUserRequestContext(pendingAdRequestContext); request.setUserRequestContext(pendingAdRequestContext);
if (vastLoadTimeoutMs != TIMEOUT_UNSET) { if (configuration.vastLoadTimeoutMs != TIMEOUT_UNSET) {
request.setVastLoadTimeout(vastLoadTimeoutMs); request.setVastLoadTimeout(configuration.vastLoadTimeoutMs);
} }
request.setContentProgressProvider(componentListener); request.setContentProgressProvider(componentListener);
@ -687,14 +702,14 @@ public final class ImaAdsLoader
adDisplayContainer = adDisplayContainer =
imaFactory.createAudioAdDisplayContainer(context, /* player= */ componentListener); imaFactory.createAudioAdDisplayContainer(context, /* player= */ componentListener);
} }
if (companionAdSlots != null) { if (configuration.companionAdSlots != null) {
adDisplayContainer.setCompanionSlots(companionAdSlots); adDisplayContainer.setCompanionSlots(configuration.companionAdSlots);
} }
adsLoader = imaFactory.createAdsLoader(context, imaSdkSettings, adDisplayContainer); adsLoader = imaFactory.createAdsLoader(context, imaSdkSettings, adDisplayContainer);
adsLoader.addAdErrorListener(componentListener); adsLoader.addAdErrorListener(componentListener);
if (adErrorListener != null) { if (configuration.applicationAdErrorListener != null) {
adsLoader.addAdErrorListener(adErrorListener); adsLoader.addAdErrorListener(configuration.applicationAdErrorListener);
} }
adsLoader.addAdsLoadedListener(componentListener); adsLoader.addAdsLoadedListener(componentListener);
adsLoader.requestAds(request); adsLoader.requestAds(request);
@ -819,8 +834,8 @@ public final class ImaAdsLoader
if (adsLoader != null) { if (adsLoader != null) {
adsLoader.removeAdsLoadedListener(componentListener); adsLoader.removeAdsLoadedListener(componentListener);
adsLoader.removeAdErrorListener(componentListener); adsLoader.removeAdErrorListener(componentListener);
if (adErrorListener != null) { if (configuration.applicationAdErrorListener != null) {
adsLoader.removeAdErrorListener(adErrorListener); adsLoader.removeAdErrorListener(configuration.applicationAdErrorListener);
} }
} }
imaPausedContent = false; imaPausedContent = false;
@ -924,7 +939,7 @@ public final class ImaAdsLoader
long adGroupTimeMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]); long adGroupTimeMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
long contentPositionMs = getContentPeriodPositionMs(player, timeline, period); long contentPositionMs = getContentPeriodPositionMs(player, timeline, period);
long timeUntilAdMs = adGroupTimeMs - contentPositionMs; long timeUntilAdMs = adGroupTimeMs - contentPositionMs;
if (timeUntilAdMs < adPreloadTimeoutMs) { if (timeUntilAdMs < configuration.adPreloadTimeoutMs) {
waitingForPreloadElapsedRealtimeMs = SystemClock.elapsedRealtime(); waitingForPreloadElapsedRealtimeMs = SystemClock.elapsedRealtime();
} }
} else if (playbackState == Player.STATE_READY) { } else if (playbackState == Player.STATE_READY) {
@ -974,15 +989,16 @@ public final class ImaAdsLoader
AdsRenderingSettings adsRenderingSettings = imaFactory.createAdsRenderingSettings(); AdsRenderingSettings adsRenderingSettings = imaFactory.createAdsRenderingSettings();
adsRenderingSettings.setEnablePreloading(true); adsRenderingSettings.setEnablePreloading(true);
adsRenderingSettings.setMimeTypes(supportedMimeTypes); adsRenderingSettings.setMimeTypes(supportedMimeTypes);
if (mediaLoadTimeoutMs != TIMEOUT_UNSET) { if (configuration.mediaLoadTimeoutMs != TIMEOUT_UNSET) {
adsRenderingSettings.setLoadVideoTimeout(mediaLoadTimeoutMs); adsRenderingSettings.setLoadVideoTimeout(configuration.mediaLoadTimeoutMs);
} }
if (mediaBitrate != BITRATE_UNSET) { if (configuration.mediaBitrate != BITRATE_UNSET) {
adsRenderingSettings.setBitrateKbps(mediaBitrate / 1000); adsRenderingSettings.setBitrateKbps(configuration.mediaBitrate / 1000);
} }
adsRenderingSettings.setFocusSkipButtonWhenAvailable(focusSkipButtonWhenAvailable); adsRenderingSettings.setFocusSkipButtonWhenAvailable(
if (adUiElements != null) { configuration.focusSkipButtonWhenAvailable);
adsRenderingSettings.setUiElements(adUiElements); if (configuration.adUiElements != null) {
adsRenderingSettings.setUiElements(configuration.adUiElements);
} }
// Skip ads based on the start position as required. // Skip ads based on the start position as required.
@ -993,7 +1009,7 @@ public final class ImaAdsLoader
C.msToUs(contentPositionMs), C.msToUs(contentDurationMs)); C.msToUs(contentPositionMs), C.msToUs(contentDurationMs));
if (adGroupForPositionIndex != C.INDEX_UNSET) { if (adGroupForPositionIndex != C.INDEX_UNSET) {
boolean playAdWhenStartingPlayback = boolean playAdWhenStartingPlayback =
playAdBeforeStartPosition configuration.playAdBeforeStartPosition
|| adGroupTimesUs[adGroupForPositionIndex] == C.msToUs(contentPositionMs); || adGroupTimesUs[adGroupForPositionIndex] == C.msToUs(contentPositionMs);
if (!playAdWhenStartingPlayback) { if (!playAdWhenStartingPlayback) {
adGroupForPositionIndex++; adGroupForPositionIndex++;
@ -1605,12 +1621,12 @@ public final class ImaAdsLoader
private void destroyAdsManager() { private void destroyAdsManager() {
if (adsManager != null) { if (adsManager != null) {
adsManager.removeAdErrorListener(componentListener); adsManager.removeAdErrorListener(componentListener);
if (adErrorListener != null) { if (configuration.applicationAdErrorListener != null) {
adsManager.removeAdErrorListener(adErrorListener); adsManager.removeAdErrorListener(configuration.applicationAdErrorListener);
} }
adsManager.removeAdEventListener(componentListener); adsManager.removeAdEventListener(componentListener);
if (adEventListener != null) { if (configuration.applicationAdEventListener != null) {
adsManager.removeAdEventListener(adEventListener); adsManager.removeAdEventListener(configuration.applicationAdEventListener);
} }
adsManager.destroy(); adsManager.destroy();
adsManager = null; adsManager = null;
@ -1636,12 +1652,12 @@ public final class ImaAdsLoader
pendingAdRequestContext = null; pendingAdRequestContext = null;
ImaAdsLoader.this.adsManager = adsManager; ImaAdsLoader.this.adsManager = adsManager;
adsManager.addAdErrorListener(this); adsManager.addAdErrorListener(this);
if (adErrorListener != null) { if (configuration.applicationAdErrorListener != null) {
adsManager.addAdErrorListener(adErrorListener); adsManager.addAdErrorListener(configuration.applicationAdErrorListener);
} }
adsManager.addAdEventListener(this); adsManager.addAdEventListener(this);
if (adEventListener != null) { if (configuration.applicationAdEventListener != null) {
adsManager.addAdEventListener(adEventListener); adsManager.addAdEventListener(configuration.applicationAdEventListener);
} }
if (player != null) { if (player != null) {
// If a player is attached already, start playback immediately. // If a player is attached already, start playback immediately.

View File

@ -21,13 +21,17 @@ import android.view.ViewGroup;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.ads.interactivemedia.v3.api.AdDisplayContainer; import com.google.ads.interactivemedia.v3.api.AdDisplayContainer;
import com.google.ads.interactivemedia.v3.api.AdError; import com.google.ads.interactivemedia.v3.api.AdError;
import com.google.ads.interactivemedia.v3.api.AdErrorEvent;
import com.google.ads.interactivemedia.v3.api.AdEvent;
import com.google.ads.interactivemedia.v3.api.AdsLoader; import com.google.ads.interactivemedia.v3.api.AdsLoader;
import com.google.ads.interactivemedia.v3.api.AdsManager; import com.google.ads.interactivemedia.v3.api.AdsManager;
import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings; import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings;
import com.google.ads.interactivemedia.v3.api.AdsRequest; import com.google.ads.interactivemedia.v3.api.AdsRequest;
import com.google.ads.interactivemedia.v3.api.CompanionAdSlot;
import com.google.ads.interactivemedia.v3.api.FriendlyObstruction; import com.google.ads.interactivemedia.v3.api.FriendlyObstruction;
import com.google.ads.interactivemedia.v3.api.FriendlyObstructionPurpose; import com.google.ads.interactivemedia.v3.api.FriendlyObstructionPurpose;
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings; import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
import com.google.ads.interactivemedia.v3.api.UiElement;
import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer; import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.ads.AdPlaybackState; import com.google.android.exoplayer2.source.ads.AdPlaybackState;
@ -37,7 +41,9 @@ import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
/** Utilities for working with IMA SDK and IMA extension data types. */ /** Utilities for working with IMA SDK and IMA extension data types. */
/* package */ final class ImaUtil { /* package */ final class ImaUtil {
@ -73,6 +79,50 @@ import java.util.List;
Context context, ImaSdkSettings imaSdkSettings, AdDisplayContainer adDisplayContainer); Context context, ImaSdkSettings imaSdkSettings, AdDisplayContainer adDisplayContainer);
} }
/** Stores configuration for ad loading and playback. */
public static final class Configuration {
public final long adPreloadTimeoutMs;
public final int vastLoadTimeoutMs;
public final int mediaLoadTimeoutMs;
public final boolean focusSkipButtonWhenAvailable;
public final boolean playAdBeforeStartPosition;
public final int mediaBitrate;
@Nullable public final Set<UiElement> adUiElements;
@Nullable public final Collection<CompanionAdSlot> companionAdSlots;
@Nullable public final AdErrorEvent.AdErrorListener applicationAdErrorListener;
@Nullable public final AdEvent.AdEventListener applicationAdEventListener;
@Nullable public final VideoAdPlayer.VideoAdPlayerCallback applicationVideoAdPlayerCallback;
@Nullable public final ImaSdkSettings imaSdkSettings;
public Configuration(
long adPreloadTimeoutMs,
int vastLoadTimeoutMs,
int mediaLoadTimeoutMs,
boolean focusSkipButtonWhenAvailable,
boolean playAdBeforeStartPosition,
int mediaBitrate,
@Nullable Set<UiElement> adUiElements,
@Nullable Collection<CompanionAdSlot> companionAdSlots,
@Nullable AdErrorEvent.AdErrorListener applicationAdErrorListener,
@Nullable AdEvent.AdEventListener applicationAdEventListener,
@Nullable VideoAdPlayer.VideoAdPlayerCallback applicationVideoAdPlayerCallback,
@Nullable ImaSdkSettings imaSdkSettings) {
this.adPreloadTimeoutMs = adPreloadTimeoutMs;
this.vastLoadTimeoutMs = vastLoadTimeoutMs;
this.mediaLoadTimeoutMs = mediaLoadTimeoutMs;
this.focusSkipButtonWhenAvailable = focusSkipButtonWhenAvailable;
this.playAdBeforeStartPosition = playAdBeforeStartPosition;
this.mediaBitrate = mediaBitrate;
this.adUiElements = adUiElements;
this.companionAdSlots = companionAdSlots;
this.applicationAdErrorListener = applicationAdErrorListener;
this.applicationAdEventListener = applicationAdEventListener;
this.applicationVideoAdPlayerCallback = applicationVideoAdPlayerCallback;
this.imaSdkSettings = imaSdkSettings;
}
}
/** /**
* Returns the IMA {@link FriendlyObstructionPurpose} corresponding to the given {@link * Returns the IMA {@link FriendlyObstructionPurpose} corresponding to the given {@link
* OverlayInfo#purpose}. * OverlayInfo#purpose}.