From 6796c4d01ce856337ecb33ebb69089f1d7334595 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 7 Dec 2020 14:32:25 +0000 Subject: [PATCH] Add a setting for enabling continuous playback Issue: #3750 PiperOrigin-RevId: 346079830 --- RELEASENOTES.md | 2 + .../exoplayer2/ext/ima/AdTagLoader.java | 3 ++ .../exoplayer2/ext/ima/ImaAdsLoader.java | 16 ++++++ .../android/exoplayer2/ext/ima/ImaUtil.java | 3 ++ .../exoplayer2/ext/ima/ImaAdsLoaderTest.java | 52 +++++++++++++++++++ 5 files changed, 76 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index de2c38b86a..50860c2d7a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -45,6 +45,8 @@ ([#3750](https://github.com/google/ExoPlayer/issues/3750)). * Fix a condition where playback can get stuck before an empty ad ([#8205](https://github.com/google/ExoPlayer/issues/8205)). + * Add `ImaAdsLoader.Builder.setEnableContinuousPlayback` for setting + whether to request ads for continuous playback. * Metadata retriever: * Parse Google Photos HEIC motion photos metadata. * FFmpeg extension: diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java index 6745196214..6e4b4beaf5 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java @@ -517,6 +517,9 @@ import java.util.Map; } pendingAdRequestContext = new Object(); request.setUserRequestContext(pendingAdRequestContext); + if (configuration.enableContinuousPlayback != null) { + request.setContinuousPlayback(configuration.enableContinuousPlayback); + } if (configuration.vastLoadTimeoutMs != TIMEOUT_UNSET) { request.setVastLoadTimeout(configuration.vastLoadTimeoutMs); } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 50b8968b33..fa249eac28 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -114,6 +114,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { @Nullable private List adMediaMimeTypes; @Nullable private Set adUiElements; @Nullable private Collection companionAdSlots; + @Nullable private Boolean enableContinuousPlayback; private long adPreloadTimeoutMs; private int vastLoadTimeoutMs; private int mediaLoadTimeoutMs; @@ -235,6 +236,20 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { return this; } + /** + * Sets whether to enable continuous playback. Pass {@code true} if content videos will be + * played continuously, similar to a TV broadcast. This setting may modify the ads request but + * does not affect ad playback behavior. The requested value is unknown by default. + * + * @param enableContinuousPlayback Whether to enable continuous playback. + * @return This builder, for convenience. + * @see AdsRequest#setContinuousPlayback(boolean) + */ + public Builder setEnableContinuousPlayback(boolean enableContinuousPlayback) { + this.enableContinuousPlayback = enableContinuousPlayback; + return this; + } + /** * Sets the duration in milliseconds for which the player must buffer while preloading an ad * group before that ad group is skipped and marked as having failed to load. Pass {@link @@ -354,6 +369,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { focusSkipButtonWhenAvailable, playAdBeforeStartPosition, mediaBitrate, + enableContinuousPlayback, adMediaMimeTypes, adUiElements, companionAdSlots, diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java index ed3d3c74e1..0324e93713 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaUtil.java @@ -89,6 +89,7 @@ import java.util.Set; public final boolean focusSkipButtonWhenAvailable; public final boolean playAdBeforeStartPosition; public final int mediaBitrate; + @Nullable public final Boolean enableContinuousPlayback; @Nullable public final List adMediaMimeTypes; @Nullable public final Set adUiElements; @Nullable public final Collection companionAdSlots; @@ -105,6 +106,7 @@ import java.util.Set; boolean focusSkipButtonWhenAvailable, boolean playAdBeforeStartPosition, int mediaBitrate, + @Nullable Boolean enableContinuousPlayback, @Nullable List adMediaMimeTypes, @Nullable Set adUiElements, @Nullable Collection companionAdSlots, @@ -119,6 +121,7 @@ import java.util.Set; this.focusSkipButtonWhenAvailable = focusSkipButtonWhenAvailable; this.playAdBeforeStartPosition = playAdBeforeStartPosition; this.mediaBitrate = mediaBitrate; + this.enableContinuousPlayback = enableContinuousPlayback; this.adMediaMimeTypes = adMediaMimeTypes; this.adUiElements = adUiElements; this.companionAdSlots = companionAdSlots; diff --git a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java index 0510bf76b0..315ec8fa9d 100644 --- a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java +++ b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoaderTest.java @@ -19,6 +19,7 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.google.android.exoplayer2.ext.ima.ImaUtil.getAdGroupTimesUsForCuePoints; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyDouble; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; @@ -1128,6 +1129,57 @@ public final class ImaAdsLoaderTest { .isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs...= */ 0)); } + @Test + public void buildWithDefaultEnableContinuousPlayback_doesNotSetAdsRequestProperty() { + imaAdsLoader = + new ImaAdsLoader.Builder(getApplicationContext()) + .setImaFactory(mockImaFactory) + .setImaSdkSettings(mockImaSdkSettings) + .build(); + imaAdsLoader.setPlayer(fakePlayer); + adsMediaSource = + new AdsMediaSource( + new FakeMediaSource(CONTENT_TIMELINE), + TEST_DATA_SPEC, + TEST_ADS_ID, + new DefaultMediaSourceFactory((Context) getApplicationContext()), + imaAdsLoader, + adViewProvider); + when(mockAdsManager.getAdCuePoints()).thenReturn(PREROLL_CUE_POINTS_SECONDS); + + imaAdsLoader.setSupportedContentTypes(C.TYPE_OTHER); + imaAdsLoader.start( + adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener); + + verify(mockAdsRequest, never()).setContinuousPlayback(anyBoolean()); + } + + @Test + public void buildWithEnableContinuousPlayback_setsAdsRequestProperty() { + imaAdsLoader = + new ImaAdsLoader.Builder(getApplicationContext()) + .setEnableContinuousPlayback(true) + .setImaFactory(mockImaFactory) + .setImaSdkSettings(mockImaSdkSettings) + .build(); + imaAdsLoader.setPlayer(fakePlayer); + adsMediaSource = + new AdsMediaSource( + new FakeMediaSource(CONTENT_TIMELINE), + TEST_DATA_SPEC, + TEST_ADS_ID, + new DefaultMediaSourceFactory((Context) getApplicationContext()), + imaAdsLoader, + adViewProvider); + when(mockAdsManager.getAdCuePoints()).thenReturn(PREROLL_CUE_POINTS_SECONDS); + + imaAdsLoader.setSupportedContentTypes(C.TYPE_OTHER); + imaAdsLoader.start( + adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener); + + verify(mockAdsRequest).setContinuousPlayback(true); + } + private void setupMocks() { ArgumentCaptor userRequestContextCaptor = ArgumentCaptor.forClass(Object.class); doNothing().when(mockAdsRequest).setUserRequestContext(userRequestContextCaptor.capture());