Implement Interactive Media Ads (IMA) SDK
This commit is contained in:
@@ -26,6 +26,7 @@ dependencies {
|
||||
implementation('com.google.android.exoplayer:exoplayer:2.10.5') {
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
implementation 'com.google.android.exoplayer:extension-ima:2.10.5'
|
||||
|
||||
// All support libs must use the same version
|
||||
implementation "androidx.annotation:annotation:1.1.0"
|
||||
|
@@ -18,16 +18,19 @@ import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.TextRenderer;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@TargetApi(16)
|
||||
public final class ExoPlayerView extends FrameLayout {
|
||||
public final class ExoPlayerView extends FrameLayout implements AdsLoader.AdViewProvider {
|
||||
|
||||
private View surfaceView;
|
||||
private final View shutterView;
|
||||
@@ -37,6 +40,7 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
private SimpleExoPlayer player;
|
||||
private Context context;
|
||||
private ViewGroup.LayoutParams layoutParams;
|
||||
private final FrameLayout adOverlayFrameLayout;
|
||||
|
||||
private boolean useTextureView = true;
|
||||
private boolean hideShutterView = false;
|
||||
@@ -81,7 +85,11 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
layout.addView(shutterView, 1, layoutParams);
|
||||
layout.addView(subtitleLayout, 2, layoutParams);
|
||||
|
||||
adOverlayFrameLayout = new FrameLayout(context);
|
||||
|
||||
addViewInLayout(layout, 0, aspectRatioParams);
|
||||
addViewInLayout(adOverlayFrameLayout, 1, layoutParams);
|
||||
|
||||
}
|
||||
|
||||
private void setVideoView() {
|
||||
@@ -111,6 +119,31 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestLayout() {
|
||||
super.requestLayout();
|
||||
post(measureAndLayout);
|
||||
}
|
||||
|
||||
// AdsLoader.AdViewProvider implementation.
|
||||
|
||||
@Override
|
||||
public ViewGroup getAdViewGroup() {
|
||||
return Assertions.checkNotNull(adOverlayFrameLayout, "exo_ad_overlay must be present for ad playback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public View[] getAdOverlayViews() {
|
||||
ArrayList<View> overlayViews = new ArrayList<>();
|
||||
if (adOverlayFrameLayout != null) {
|
||||
overlayViews.add(adOverlayFrameLayout);
|
||||
}
|
||||
// if (controller != null) {
|
||||
// overlayViews.add(controller);
|
||||
// }
|
||||
return overlayViews.toArray(new View[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#setTextOutput} and
|
||||
* {@link SimpleExoPlayer#setVideoListener} method of the player will be called and previous
|
||||
|
@@ -63,9 +63,13 @@ import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
|
||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -77,7 +81,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
BandwidthMeter.EventListener,
|
||||
BecomingNoisyListener,
|
||||
AudioManager.OnAudioFocusChangeListener,
|
||||
MetadataOutput {
|
||||
MetadataOutput,
|
||||
AdsMediaSource.MediaSourceFactory {
|
||||
|
||||
private static final String TAG = "ReactExoplayerView";
|
||||
|
||||
@@ -97,6 +102,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private Player.EventListener eventListener;
|
||||
|
||||
private ExoPlayerView exoPlayerView;
|
||||
private ImaAdsLoader adsLoader;
|
||||
|
||||
private DataSource.Factory mediaDataSourceFactory;
|
||||
private SimpleExoPlayer player;
|
||||
@@ -139,6 +145,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private Map<String, String> requestHeaders;
|
||||
private boolean mReportBandwidth = false;
|
||||
private boolean controls;
|
||||
private Uri adTagUrl;
|
||||
// \ End props
|
||||
|
||||
// React
|
||||
@@ -155,6 +162,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
&& player.getPlaybackState() == Player.STATE_READY
|
||||
&& player.getPlayWhenReady()
|
||||
) {
|
||||
if (isPlayingAd()) {
|
||||
playerControlView.hide();
|
||||
}
|
||||
long pos = player.getCurrentPosition();
|
||||
long bufferedDuration = player.getBufferedPercentage() * player.getDuration() / 100;
|
||||
eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration());
|
||||
@@ -173,6 +183,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
this.config = config;
|
||||
this.bandwidthMeter = config.getBandwidthMeter();
|
||||
|
||||
adsLoader = new ImaAdsLoader(this.themedReactContext, Uri.EMPTY);
|
||||
|
||||
createViews();
|
||||
|
||||
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
@@ -182,6 +194,10 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
initializePlayer();
|
||||
}
|
||||
|
||||
private boolean isPlayingAd() {
|
||||
return player != null && player.isPlayingAd() && player.getPlayWhenReady();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setId(int id) {
|
||||
@@ -288,7 +304,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
exoPlayerView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
togglePlayerControlVisibility();
|
||||
if (!isPlayingAd()) {
|
||||
togglePlayerControlVisibility();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -360,6 +378,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
trackSelector, defaultLoadControl, null, bandwidthMeter);
|
||||
player.addListener(self);
|
||||
player.addMetadataOutput(self);
|
||||
adsLoader.setPlayer(player);
|
||||
exoPlayerView.setPlayer(player);
|
||||
audioBecomingNoisyReceiver.setListener(self);
|
||||
bandwidthMeter.addEventListener(new Handler(), self);
|
||||
@@ -372,11 +391,12 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
if (playerNeedsSource && srcUri != null) {
|
||||
ArrayList<MediaSource> mediaSourceList = buildTextSources();
|
||||
MediaSource videoSource = buildMediaSource(srcUri, extension);
|
||||
MediaSource mediaSourceWithAds = new AdsMediaSource(videoSource, mediaDataSourceFactory, adsLoader, exoPlayerView);
|
||||
MediaSource mediaSource;
|
||||
if (mediaSourceList.size() == 0) {
|
||||
mediaSource = videoSource;
|
||||
mediaSource = mediaSourceWithAds;
|
||||
} else {
|
||||
mediaSourceList.add(0, videoSource);
|
||||
mediaSourceList.add(0, mediaSourceWithAds);
|
||||
MediaSource[] textSourceArray = mediaSourceList.toArray(
|
||||
new MediaSource[mediaSourceList.size()]
|
||||
);
|
||||
@@ -402,6 +422,19 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}, 1);
|
||||
}
|
||||
|
||||
// AdsMediaSource.MediaSourceFactory implementation.
|
||||
|
||||
@Override
|
||||
public MediaSource createMediaSource(Uri uri) {
|
||||
return buildMediaSource(uri, extension);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedTypes() {
|
||||
// IMA does not support Smooth Streaming ads.
|
||||
return new int[] {C.TYPE_DASH, C.TYPE_HLS, C.TYPE_OTHER};
|
||||
}
|
||||
|
||||
private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
|
||||
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
|
||||
: uri.getLastPathSegment());
|
||||
@@ -473,6 +506,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
trackSelector = null;
|
||||
player = null;
|
||||
}
|
||||
adsLoader.release();
|
||||
progressHandler.removeMessages(SHOW_PROGRESS);
|
||||
themedReactContext.removeLifecycleEventListener(this);
|
||||
audioBecomingNoisyReceiver.removeListener();
|
||||
@@ -914,6 +948,11 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
mReportBandwidth = reportBandwidth;
|
||||
}
|
||||
|
||||
public void setAdTagUrl(final Uri uri) {
|
||||
adTagUrl = uri;
|
||||
adsLoader = new ImaAdsLoader(this.themedReactContext, adTagUrl);
|
||||
}
|
||||
|
||||
public void setRawSrc(final Uri uri, final String extension) {
|
||||
if (uri != null) {
|
||||
boolean isOriginalSourceNull = srcUri == null;
|
||||
|
@@ -25,6 +25,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
|
||||
private static final String PROP_SRC = "src";
|
||||
private static final String PROP_SRC_URI = "uri";
|
||||
private static final String PROP_AD_TAG_URL = "adTagUrl";
|
||||
private static final String PROP_SRC_TYPE = "type";
|
||||
private static final String PROP_SRC_HEADERS = "requestHeaders";
|
||||
private static final String PROP_RESIZE_MODE = "resizeMode";
|
||||
@@ -140,6 +141,23 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_AD_TAG_URL)
|
||||
public void setAdTagUrl(final ReactExoplayerView videoView, final String uriString) {
|
||||
if (TextUtils.isEmpty(uriString)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (startsWithValidScheme(uriString)) {
|
||||
Uri adTagUrl = Uri.parse(uriString);
|
||||
|
||||
if (adTagUrl != null) {
|
||||
videoView.setAdTagUrl(adTagUrl);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ReactProp(name = PROP_RESIZE_MODE)
|
||||
public void setResizeMode(final ReactExoplayerView videoView, final String resizeModeOrdinalString) {
|
||||
videoView.setResizeModeModifier(convertToIntDef(resizeModeOrdinalString));
|
||||
|
Reference in New Issue
Block a user