mirror of
https://github.com/androidx/media.git
synced 2025-05-16 03:59:54 +08:00
Add IMA and FLAC tests to the codebase
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=204302135
This commit is contained in:
parent
05a31dfd24
commit
a26bb350ee
17
extensions/flac/src/test/AndroidManifest.xml
Normal file
17
extensions/flac/src/test/AndroidManifest.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2016 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.
|
||||
-->
|
||||
|
||||
<manifest package="com.google.android.exoplayer2.ext.flac"/>
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.flac;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.extractor.amr.AmrExtractor;
|
||||
import com.google.android.exoplayer2.extractor.flv.FlvExtractor;
|
||||
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
|
||||
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
|
||||
import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor;
|
||||
import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
|
||||
import com.google.android.exoplayer2.extractor.ogg.OggExtractor;
|
||||
import com.google.android.exoplayer2.extractor.ts.Ac3Extractor;
|
||||
import com.google.android.exoplayer2.extractor.ts.AdtsExtractor;
|
||||
import com.google.android.exoplayer2.extractor.ts.PsExtractor;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsExtractor;
|
||||
import com.google.android.exoplayer2.extractor.wav.WavExtractor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
/** Unit test for {@link DefaultExtractorsFactory}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public final class DefaultExtractorsFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testCreateExtractors_returnExpectedClasses() {
|
||||
DefaultExtractorsFactory defaultExtractorsFactory = new DefaultExtractorsFactory();
|
||||
|
||||
Extractor[] extractors = defaultExtractorsFactory.createExtractors();
|
||||
List<Class> listCreatedExtractorClasses = new ArrayList<>();
|
||||
for (Extractor extractor : extractors) {
|
||||
listCreatedExtractorClasses.add(extractor.getClass());
|
||||
}
|
||||
|
||||
Class[] expectedExtractorClassses =
|
||||
new Class[] {
|
||||
MatroskaExtractor.class,
|
||||
FragmentedMp4Extractor.class,
|
||||
Mp4Extractor.class,
|
||||
Mp3Extractor.class,
|
||||
AdtsExtractor.class,
|
||||
Ac3Extractor.class,
|
||||
TsExtractor.class,
|
||||
FlvExtractor.class,
|
||||
OggExtractor.class,
|
||||
PsExtractor.class,
|
||||
WavExtractor.class,
|
||||
AmrExtractor.class,
|
||||
FlacExtractor.class
|
||||
};
|
||||
|
||||
assertThat(listCreatedExtractorClasses).containsNoDuplicates();
|
||||
assertThat(listCreatedExtractorClasses).containsExactlyElementsIn(expectedExtractorClassses);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
manifest=src/test/AndroidManifest.xml
|
16
extensions/ima/src/test/AndroidManifest.xml
Normal file
16
extensions/ima/src/test/AndroidManifest.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<manifest package="com.google.android.exoplayer2.ext.ima.test" />
|
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 com.google.ads.interactivemedia.v3.api.Ad;
|
||||
import com.google.ads.interactivemedia.v3.api.AdPodInfo;
|
||||
import com.google.ads.interactivemedia.v3.api.UiElement;
|
||||
import java.util.Set;
|
||||
|
||||
/** A fake ad for testing. */
|
||||
/* package */ final class FakeAd implements Ad {
|
||||
|
||||
private final boolean skippable;
|
||||
private final AdPodInfo adPodInfo;
|
||||
|
||||
public FakeAd(boolean skippable, int podIndex, int totalAds, int adPosition) {
|
||||
this.skippable = skippable;
|
||||
adPodInfo =
|
||||
new AdPodInfo() {
|
||||
@Override
|
||||
public int getTotalAds() {
|
||||
return totalAds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAdPosition() {
|
||||
return adPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPodIndex() {
|
||||
return podIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBumper() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMaxDuration() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTimeOffset() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkippable() {
|
||||
return skippable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdPodInfo getAdPodInfo() {
|
||||
return adPodInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdId() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCreativeId() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCreativeAdId() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniversalAdIdValue() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniversalAdIdRegistry() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdSystem() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAdWrapperIds() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAdWrapperSystems() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAdWrapperCreativeIds() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLinear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSkipTimeOffset() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUiDisabled() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdvertiserName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSurveyUrl() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDealId() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTraffickingParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDuration() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UiElement> getUiElements() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 com.google.ads.interactivemedia.v3.api.AdErrorEvent.AdErrorListener;
|
||||
import com.google.ads.interactivemedia.v3.api.AdsManager;
|
||||
import com.google.ads.interactivemedia.v3.api.AdsManagerLoadedEvent;
|
||||
import com.google.ads.interactivemedia.v3.api.AdsRequest;
|
||||
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
|
||||
import com.google.ads.interactivemedia.v3.api.StreamManager;
|
||||
import com.google.ads.interactivemedia.v3.api.StreamRequest;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** Fake {@link com.google.ads.interactivemedia.v3.api.AdsLoader} implementation for tests. */
|
||||
public final class FakeAdsLoader implements com.google.ads.interactivemedia.v3.api.AdsLoader {
|
||||
|
||||
private final ImaSdkSettings imaSdkSettings;
|
||||
private final AdsManager adsManager;
|
||||
private final ArrayList<AdsLoadedListener> adsLoadedListeners;
|
||||
private final ArrayList<AdErrorListener> adErrorListeners;
|
||||
|
||||
public FakeAdsLoader(ImaSdkSettings imaSdkSettings, AdsManager adsManager) {
|
||||
this.imaSdkSettings = Assertions.checkNotNull(imaSdkSettings);
|
||||
this.adsManager = Assertions.checkNotNull(adsManager);
|
||||
adsLoadedListeners = new ArrayList<>();
|
||||
adErrorListeners = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentComplete() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImaSdkSettings getSettings() {
|
||||
return imaSdkSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestAds(AdsRequest adsRequest) {
|
||||
for (AdsLoadedListener listener : adsLoadedListeners) {
|
||||
listener.onAdsManagerLoaded(
|
||||
new AdsManagerLoadedEvent() {
|
||||
@Override
|
||||
public AdsManager getAdsManager() {
|
||||
return adsManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamManager getStreamManager() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getUserRequestContext() {
|
||||
return adsRequest.getUserRequestContext();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestStream(StreamRequest streamRequest) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdsLoadedListener(AdsLoadedListener adsLoadedListener) {
|
||||
adsLoadedListeners.add(adsLoadedListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAdsLoadedListener(AdsLoadedListener adsLoadedListener) {
|
||||
adsLoadedListeners.remove(adsLoadedListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdErrorListener(AdErrorListener adErrorListener) {
|
||||
adErrorListeners.add(adErrorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAdErrorListener(AdErrorListener adErrorListener) {
|
||||
adErrorListeners.remove(adErrorListener);
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 com.google.ads.interactivemedia.v3.api.AdDisplayContainer;
|
||||
import com.google.ads.interactivemedia.v3.api.AdsRequest;
|
||||
import com.google.ads.interactivemedia.v3.api.player.ContentProgressProvider;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Fake {@link AdsRequest} implementation for tests. */
|
||||
public final class FakeAdsRequest implements AdsRequest {
|
||||
|
||||
private String adTagUrl;
|
||||
private String adsResponse;
|
||||
private Object userRequestContext;
|
||||
private AdDisplayContainer adDisplayContainer;
|
||||
private ContentProgressProvider contentProgressProvider;
|
||||
|
||||
@Override
|
||||
public void setAdTagUrl(String adTagUrl) {
|
||||
this.adTagUrl = adTagUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdTagUrl() {
|
||||
return adTagUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExtraParameter(String s, String s1) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtraParameter(String s) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getExtraParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserRequestContext(Object userRequestContext) {
|
||||
this.userRequestContext = userRequestContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getUserRequestContext() {
|
||||
return userRequestContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdDisplayContainer getAdDisplayContainer() {
|
||||
return adDisplayContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdDisplayContainer(AdDisplayContainer adDisplayContainer) {
|
||||
this.adDisplayContainer = adDisplayContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentProgressProvider getContentProgressProvider() {
|
||||
return contentProgressProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentProgressProvider(ContentProgressProvider contentProgressProvider) {
|
||||
this.contentProgressProvider = contentProgressProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdsResponse() {
|
||||
return adsResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdsResponse(String adsResponse) {
|
||||
this.adsResponse = adsResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdWillAutoPlay(boolean b) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdWillPlayMuted(boolean b) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentDuration(float v) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentKeywords(List<String> list) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentTitle(String s) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVastLoadTimeout(float v) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLiveStreamPrefetchSeconds(float v) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.testutil.StubExoPlayer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** A fake player for testing content/ad playback. */
|
||||
/* package */ final class FakePlayer extends StubExoPlayer {
|
||||
|
||||
private final ArrayList<Player.EventListener> listeners;
|
||||
private final Timeline.Window window;
|
||||
private final Timeline.Period period;
|
||||
|
||||
private boolean prepared;
|
||||
private Timeline timeline;
|
||||
private int state;
|
||||
private boolean playWhenReady;
|
||||
private long position;
|
||||
private long contentPosition;
|
||||
private boolean isPlayingAd;
|
||||
private int adGroupIndex;
|
||||
private int adIndexInAdGroup;
|
||||
|
||||
public FakePlayer() {
|
||||
listeners = new ArrayList<>();
|
||||
window = new Timeline.Window();
|
||||
period = new Timeline.Period();
|
||||
state = Player.STATE_IDLE;
|
||||
playWhenReady = true;
|
||||
timeline = Timeline.EMPTY;
|
||||
}
|
||||
|
||||
/** Sets the timeline on this fake player, which notifies listeners with the changed timeline. */
|
||||
public void updateTimeline(Timeline timeline) {
|
||||
for (Player.EventListener listener : listeners) {
|
||||
listener.onTimelineChanged(
|
||||
timeline,
|
||||
null,
|
||||
prepared ? TIMELINE_CHANGE_REASON_DYNAMIC : TIMELINE_CHANGE_REASON_PREPARED);
|
||||
}
|
||||
prepared = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of this player as if it were playing content at the given {@code position}. If
|
||||
* an ad is currently playing, this will trigger a position discontinuity.
|
||||
*/
|
||||
public void setPlayingContentPosition(long position) {
|
||||
boolean notify = isPlayingAd;
|
||||
isPlayingAd = false;
|
||||
adGroupIndex = C.INDEX_UNSET;
|
||||
adIndexInAdGroup = C.INDEX_UNSET;
|
||||
this.position = position;
|
||||
contentPosition = position;
|
||||
if (notify) {
|
||||
for (Player.EventListener listener : listeners) {
|
||||
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AD_INSERTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of this player as if it were playing an ad with the given indices at the given
|
||||
* {@code position}. If the player is playing a different ad or content, this will trigger a
|
||||
* position discontinuity.
|
||||
*/
|
||||
public void setPlayingAdPosition(
|
||||
int adGroupIndex, int adIndexInAdGroup, long position, long contentPosition) {
|
||||
boolean notify = !isPlayingAd || this.adIndexInAdGroup != adIndexInAdGroup;
|
||||
isPlayingAd = true;
|
||||
this.adGroupIndex = adGroupIndex;
|
||||
this.adIndexInAdGroup = adIndexInAdGroup;
|
||||
this.position = position;
|
||||
this.contentPosition = contentPosition;
|
||||
if (notify) {
|
||||
for (Player.EventListener listener : listeners) {
|
||||
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AD_INSERTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the state of this player with the given {@code STATE} constant. */
|
||||
public void setState(int state, boolean playWhenReady) {
|
||||
boolean notify = this.state != state || this.playWhenReady != playWhenReady;
|
||||
this.state = state;
|
||||
this.playWhenReady = playWhenReady;
|
||||
if (notify) {
|
||||
for (Player.EventListener listener : listeners) {
|
||||
listener.onPlayerStateChanged(playWhenReady, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExoPlayer methods. Other methods are unsupported.
|
||||
|
||||
@Override
|
||||
public void addListener(Player.EventListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Player.EventListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlaybackState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPlayWhenReady() {
|
||||
return playWhenReady;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timeline getCurrentTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentPeriodIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentWindowIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextWindowIndex() {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousWindowIndex() {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDuration() {
|
||||
if (timeline.isEmpty()) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
if (isPlayingAd()) {
|
||||
long adDurationUs =
|
||||
timeline.getPeriod(0, period).getAdDurationUs(adGroupIndex, adIndexInAdGroup);
|
||||
return C.usToMs(adDurationUs);
|
||||
} else {
|
||||
return timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayingAd() {
|
||||
return isPlayingAd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentAdGroupIndex() {
|
||||
return adGroupIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentAdIndexInAdGroup() {
|
||||
return adIndexInAdGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentPosition() {
|
||||
return contentPosition;
|
||||
}
|
||||
}
|
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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 static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import com.google.ads.interactivemedia.v3.api.Ad;
|
||||
import com.google.ads.interactivemedia.v3.api.AdDisplayContainer;
|
||||
import com.google.ads.interactivemedia.v3.api.AdEvent;
|
||||
import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventType;
|
||||
import com.google.ads.interactivemedia.v3.api.AdsManager;
|
||||
import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings;
|
||||
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
|
||||
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.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.upstream.DataSpec;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
/** Test for {@link ImaAdsLoader}. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
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);
|
||||
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}};
|
||||
private static final Float[] PREROLL_CUE_POINTS_SECONDS = new Float[] {0f};
|
||||
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;
|
||||
private ViewGroup adUiViewGroup;
|
||||
private TestAdsLoaderListener adsLoaderListener;
|
||||
private FakePlayer fakeExoPlayer;
|
||||
private ImaAdsLoader imaAdsLoader;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
FakeAdsRequest fakeAdsRequest = new FakeAdsRequest();
|
||||
FakeAdsLoader fakeAdsLoader = new FakeAdsLoader(imaSdkSettings, adsManager);
|
||||
testImaFactory =
|
||||
new SingletonImaFactory(
|
||||
imaSdkSettings,
|
||||
adsRenderingSettings,
|
||||
adDisplayContainer,
|
||||
fakeAdsRequest,
|
||||
fakeAdsLoader);
|
||||
adUiViewGroup = new FrameLayout(RuntimeEnvironment.application);
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
if (imaAdsLoader != null) {
|
||||
imaAdsLoader.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuilder_overridesPlayerType() {
|
||||
when(imaSdkSettings.getPlayerType()).thenReturn("test player type");
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
|
||||
verify(imaSdkSettings).setPlayerType("google/exo.ext.ima");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachPlayer_setsAdUiViewGroup() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
|
||||
verify(adDisplayContainer, atLeastOnce()).setAdContainer(adUiViewGroup);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachPlayer_updatesAdPlaybackState() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
|
||||
assertThat(adsLoaderListener.adPlaybackState)
|
||||
.isEqualTo(
|
||||
new AdPlaybackState(/* adGroupTimesUs= */ 0)
|
||||
.withAdDurationsUs(PREROLL_ADS_DURATIONS_US));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachAfterRelease() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
imaAdsLoader.release();
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachAndCallbacksAfterRelease() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
imaAdsLoader.release();
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
fakeExoPlayer.setPlayingContentPosition(/* position= */ 0);
|
||||
fakeExoPlayer.setState(Player.STATE_READY, true);
|
||||
|
||||
// If callbacks are invoked there is no crash.
|
||||
// Note: we can't currently call getContentProgress/getAdProgress as a VerifyError is thrown
|
||||
// when using Robolectric and accessing VideoProgressUpdate.VIDEO_TIME_NOT_READY, due to the IMA
|
||||
// SDK being proguarded.
|
||||
imaAdsLoader.requestAds(adUiViewGroup);
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.LOADED, UNSKIPPABLE_AD));
|
||||
imaAdsLoader.loadAd(TEST_URI.toString());
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.CONTENT_PAUSE_REQUESTED, UNSKIPPABLE_AD));
|
||||
imaAdsLoader.playAd();
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.STARTED, UNSKIPPABLE_AD));
|
||||
imaAdsLoader.pauseAd();
|
||||
imaAdsLoader.stopAd();
|
||||
imaAdsLoader.onPlayerError(ExoPlaybackException.createForSource(new IOException()));
|
||||
imaAdsLoader.onPositionDiscontinuity(Player.DISCONTINUITY_REASON_SEEK);
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.CONTENT_RESUME_REQUESTED, /* ad= */ null));
|
||||
imaAdsLoader.handlePrepareError(
|
||||
/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, new IOException());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlayback_withPrerollAd_marksAdAsPlayed() {
|
||||
setupPlayback(CONTENT_TIMELINE, PREROLL_ADS_DURATIONS_US, PREROLL_CUE_POINTS_SECONDS);
|
||||
|
||||
// Load the preroll ad.
|
||||
imaAdsLoader.attachPlayer(fakeExoPlayer, adsLoaderListener, adUiViewGroup);
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.LOADED, UNSKIPPABLE_AD));
|
||||
imaAdsLoader.loadAd(TEST_URI.toString());
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.CONTENT_PAUSE_REQUESTED, UNSKIPPABLE_AD));
|
||||
|
||||
// Play the preroll ad.
|
||||
imaAdsLoader.playAd();
|
||||
fakeExoPlayer.setPlayingAdPosition(
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
/* position= */ 0,
|
||||
/* contentPosition= */ 0);
|
||||
fakeExoPlayer.setState(Player.STATE_READY, true);
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.STARTED, UNSKIPPABLE_AD));
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.FIRST_QUARTILE, UNSKIPPABLE_AD));
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.MIDPOINT, UNSKIPPABLE_AD));
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.THIRD_QUARTILE, UNSKIPPABLE_AD));
|
||||
|
||||
// Play the content.
|
||||
fakeExoPlayer.setPlayingContentPosition(0);
|
||||
imaAdsLoader.stopAd();
|
||||
imaAdsLoader.onAdEvent(getAdEvent(AdEventType.CONTENT_RESUME_REQUESTED, /* ad= */ null));
|
||||
|
||||
// Verify that the preroll ad has been marked as played.
|
||||
assertThat(adsLoaderListener.adPlaybackState)
|
||||
.isEqualTo(
|
||||
new AdPlaybackState(/* adGroupTimesUs= */ 0)
|
||||
.withContentDurationUs(CONTENT_DURATION_US)
|
||||
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
|
||||
.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, /* uri= */ TEST_URI)
|
||||
.withAdDurationsUs(PREROLL_ADS_DURATIONS_US)
|
||||
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
|
||||
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
|
||||
}
|
||||
|
||||
private void setupPlayback(Timeline contentTimeline, long[][] adDurationsUs, Float[] cuePoints) {
|
||||
fakeExoPlayer = new FakePlayer();
|
||||
adsLoaderListener = new TestAdsLoaderListener(fakeExoPlayer, contentTimeline, adDurationsUs);
|
||||
when(adsManager.getAdCuePoints()).thenReturn(Arrays.asList(cuePoints));
|
||||
imaAdsLoader =
|
||||
new ImaAdsLoader.Builder(RuntimeEnvironment.application)
|
||||
.setImaFactory(testImaFactory)
|
||||
.setImaSdkSettings(imaSdkSettings)
|
||||
.buildForAdTag(TEST_URI);
|
||||
}
|
||||
|
||||
private static AdEvent getAdEvent(AdEventType adEventType, @Nullable Ad ad) {
|
||||
return new AdEvent() {
|
||||
@Override
|
||||
public AdEventType getType() {
|
||||
return adEventType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Ad getAd() {
|
||||
return ad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAdData() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Ad loader event listener that forwards ad playback state to a fake player. */
|
||||
private static final class TestAdsLoaderListener implements AdsLoader.EventListener {
|
||||
|
||||
private final FakePlayer fakeExoPlayer;
|
||||
private final Timeline contentTimeline;
|
||||
private final long[][] adDurationsUs;
|
||||
|
||||
public AdPlaybackState adPlaybackState;
|
||||
|
||||
public TestAdsLoaderListener(
|
||||
FakePlayer fakeExoPlayer, Timeline contentTimeline, long[][] adDurationsUs) {
|
||||
this.fakeExoPlayer = fakeExoPlayer;
|
||||
this.contentTimeline = contentTimeline;
|
||||
this.adDurationsUs = adDurationsUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdPlaybackState(AdPlaybackState adPlaybackState) {
|
||||
adPlaybackState = adPlaybackState.withAdDurationsUs(adDurationsUs);
|
||||
this.adPlaybackState = adPlaybackState;
|
||||
fakeExoPlayer.updateTimeline(new SinglePeriodAdTimeline(contentTimeline, adPlaybackState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdLoadError(AdLoadException error, DataSpec dataSpec) {
|
||||
assertThat(error.type).isNotEqualTo(AdLoadException.TYPE_UNEXPECTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdClicked() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdTapped() {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.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 com.google.ads.interactivemedia.v3.api.AdsLoader createAdsLoader(
|
||||
Context context, ImaSdkSettings imaSdkSettings) {
|
||||
return adsLoader;
|
||||
}
|
||||
}
|
1
extensions/ima/src/test/resources/robolectric.properties
Normal file
1
extensions/ima/src/test/resources/robolectric.properties
Normal file
@ -0,0 +1 @@
|
||||
manifest=src/test/AndroidManifest.xml
|
Loading…
x
Reference in New Issue
Block a user