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 edaa4cde29..e6c0852bc8 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 @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.ext.ima; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.verify; @@ -39,11 +40,14 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; -import com.google.android.exoplayer2.source.SinglePeriodTimeline; +import com.google.android.exoplayer2.Timeline.Period; +import com.google.android.exoplayer2.ext.ima.ImaAdsLoader.ImaFactory; +import com.google.android.exoplayer2.source.MaskingMediaSource; import com.google.android.exoplayer2.source.ads.AdPlaybackState; import com.google.android.exoplayer2.source.ads.AdsLoader; import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException; import com.google.android.exoplayer2.source.ads.SinglePeriodAdTimeline; +import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.upstream.DataSpec; import java.io.IOException; import java.util.Arrays; @@ -63,8 +67,11 @@ public class ImaAdsLoaderTest { private static final long CONTENT_DURATION_US = 10 * C.MICROS_PER_SECOND; private static final Timeline CONTENT_TIMELINE = - new SinglePeriodTimeline( - CONTENT_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false, /* isLive= */ false); + new FakeTimeline( + new FakeTimeline.TimelineWindowDefinition( + /* isSeekable= */ true, /* isDynamic= */ false, CONTENT_DURATION_US)); + private static final long CONTENT_PERIOD_DURATION_US = + CONTENT_TIMELINE.getPeriod(/* periodIndex= */ 0, new Period()).durationUs; private static final Uri TEST_URI = Uri.EMPTY; private static final long TEST_AD_DURATION_US = 5 * C.MICROS_PER_SECOND; private static final long[][] PREROLL_ADS_DURATIONS_US = new long[][] {{TEST_AD_DURATION_US}}; @@ -72,11 +79,11 @@ public class ImaAdsLoaderTest { private static final FakeAd UNSKIPPABLE_AD = new FakeAd(/* skippable= */ false, /* podIndex= */ 0, /* totalAds= */ 1, /* adPosition= */ 1); - private @Mock ImaSdkSettings imaSdkSettings; - private @Mock AdsRenderingSettings adsRenderingSettings; - private @Mock AdDisplayContainer adDisplayContainer; - private @Mock AdsManager adsManager; - private SingletonImaFactory testImaFactory; + @Mock private ImaSdkSettings imaSdkSettings; + @Mock private AdsRenderingSettings adsRenderingSettings; + @Mock private AdDisplayContainer adDisplayContainer; + @Mock private AdsManager adsManager; + @Mock private ImaFactory mockImaFactory; private ViewGroup adViewGroup; private View adOverlayView; private AdsLoader.AdViewProvider adViewProvider; @@ -89,13 +96,11 @@ public class ImaAdsLoaderTest { MockitoAnnotations.initMocks(this); FakeAdsRequest fakeAdsRequest = new FakeAdsRequest(); FakeAdsLoader fakeAdsLoader = new FakeAdsLoader(imaSdkSettings, adsManager); - testImaFactory = - new SingletonImaFactory( - imaSdkSettings, - adsRenderingSettings, - adDisplayContainer, - fakeAdsRequest, - fakeAdsLoader); + when(mockImaFactory.createAdDisplayContainer()).thenReturn(adDisplayContainer); + when(mockImaFactory.createAdsRenderingSettings()).thenReturn(adsRenderingSettings); + when(mockImaFactory.createAdsRequest()).thenReturn(fakeAdsRequest); + when(mockImaFactory.createImaSdkSettings()).thenReturn(imaSdkSettings); + when(mockImaFactory.createAdsLoader(any(), any(), any())).thenReturn(fakeAdsLoader); adViewGroup = new FrameLayout(ApplicationProvider.getApplicationContext()); adOverlayView = new View(ApplicationProvider.getApplicationContext()); adViewProvider = @@ -136,6 +141,16 @@ public class ImaAdsLoaderTest { verify(adDisplayContainer, atLeastOnce()).registerVideoControlsOverlay(adOverlayView); } + @Test + public void testStart_withPlaceholderContent_initializedAdsLoader() { + Timeline placeholderTimeline = new MaskingMediaSource.DummyTimeline(/* tag= */ null); + setupPlayback(placeholderTimeline, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS); + imaAdsLoader.start(adsLoaderListener, adViewProvider); + + // We'll only create the rendering settings when initializing the ads loader. + verify(mockImaFactory).createAdsRenderingSettings(); + } + @Test public void testStart_updatesAdPlaybackState() { setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS); @@ -143,9 +158,9 @@ public class ImaAdsLoaderTest { assertThat(adsLoaderListener.adPlaybackState) .isEqualTo( - new AdPlaybackState(/* adGroupTimesUs= */ 0) + new AdPlaybackState(/* adGroupTimesUs...= */ 0) .withAdDurationsUs(PREROLL_ADS_DURATIONS_US) - .withContentDurationUs(CONTENT_DURATION_US)); + .withContentDurationUs(CONTENT_PERIOD_DURATION_US)); } @Test @@ -213,8 +228,8 @@ public class ImaAdsLoaderTest { // Verify that the preroll ad has been marked as played. assertThat(adsLoaderListener.adPlaybackState) .isEqualTo( - new AdPlaybackState(/* adGroupTimesUs= */ 0) - .withContentDurationUs(CONTENT_DURATION_US) + new AdPlaybackState(/* adGroupTimesUs...= */ 0) + .withContentDurationUs(CONTENT_PERIOD_DURATION_US) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, /* uri= */ TEST_URI) .withAdDurationsUs(PREROLL_ADS_DURATIONS_US) @@ -240,7 +255,7 @@ public class ImaAdsLoaderTest { when(adsManager.getAdCuePoints()).thenReturn(Arrays.asList(cuePoints)); imaAdsLoader = new ImaAdsLoader.Builder(ApplicationProvider.getApplicationContext()) - .setImaFactory(testImaFactory) + .setImaFactory(mockImaFactory) .setImaSdkSettings(imaSdkSettings) .buildForAdTag(TEST_URI); imaAdsLoader.setPlayer(fakeExoPlayer); diff --git a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/SingletonImaFactory.java b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/SingletonImaFactory.java deleted file mode 100644 index 4efd8cf38c..0000000000 --- a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/SingletonImaFactory.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * 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 - * - * http://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 com.google.android.exoplayer2.ext.ima; - -import android.content.Context; -import com.google.ads.interactivemedia.v3.api.AdDisplayContainer; -import com.google.ads.interactivemedia.v3.api.AdsLoader; -import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings; -import com.google.ads.interactivemedia.v3.api.AdsRequest; -import com.google.ads.interactivemedia.v3.api.ImaSdkSettings; - -/** {@link ImaAdsLoader.ImaFactory} that returns provided instances from each getter, for tests. */ -final class SingletonImaFactory implements ImaAdsLoader.ImaFactory { - - private final ImaSdkSettings imaSdkSettings; - private final AdsRenderingSettings adsRenderingSettings; - private final AdDisplayContainer adDisplayContainer; - private final AdsRequest adsRequest; - private final com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader; - - public SingletonImaFactory( - ImaSdkSettings imaSdkSettings, - AdsRenderingSettings adsRenderingSettings, - AdDisplayContainer adDisplayContainer, - AdsRequest adsRequest, - com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader) { - this.imaSdkSettings = imaSdkSettings; - this.adsRenderingSettings = adsRenderingSettings; - this.adDisplayContainer = adDisplayContainer; - this.adsRequest = adsRequest; - this.adsLoader = adsLoader; - } - - @Override - public ImaSdkSettings createImaSdkSettings() { - return imaSdkSettings; - } - - @Override - public AdsRenderingSettings createAdsRenderingSettings() { - return adsRenderingSettings; - } - - @Override - public AdDisplayContainer createAdDisplayContainer() { - return adDisplayContainer; - } - - @Override - public AdsRequest createAdsRequest() { - return adsRequest; - } - - @Override - public AdsLoader createAdsLoader( - Context context, ImaSdkSettings imaSdkSettings, AdDisplayContainer adDisplayContainer) { - return adsLoader; - } -} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java index 891cb351c1..47279f2358 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MaskingMediaSource.java @@ -293,7 +293,7 @@ public final class MaskingMediaSource extends CompositeMediaSource { } /** Dummy placeholder timeline with one dynamic window with a period of indeterminate duration. */ - private static final class DummyTimeline extends Timeline { + public static final class DummyTimeline extends Timeline { @Nullable private final Object tag;