From 7fce04a67f6cbbd11a6f441f47bb867d257817f0 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 20 Jul 2020 11:16:30 +0100 Subject: [PATCH] Depend on the IMA extension in noExtensions variant Also use the cronet extension in the demo app. PiperOrigin-RevId: 322108530 --- RELEASENOTES.md | 5 ++- demos/main/build.gradle | 25 +++++++------ demos/main/proguard-rules.txt | 5 --- .../exoplayer2/demo/DemoApplication.java | 32 ++++++++-------- .../exoplayer2/demo/PlayerActivity.java | 37 ++----------------- demos/main/src/main/res/values/strings.xml | 2 - extensions/ima/README.md | 10 ++--- 7 files changed, 41 insertions(+), 75 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 208997a1ae..cb7dbae348 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -250,7 +250,10 @@ * Migrate to new 'friendly obstruction' IMA SDK APIs, and allow apps to register a purpose and detail reason for overlay views via `AdsLoader.AdViewProvider`. -* Demo app: Retain previous position in list of samples. +* Demo app: + * Retain previous position in list of samples. + * Replace the `extensions` variant with `decoderExtensions` and make the + demo app use the Cronet and IMA extensions by default. * Add Guava dependency. ### 2.11.7 (2020-06-29) ### diff --git a/demos/main/build.gradle b/demos/main/build.gradle index f26fd7dc32..abf5a471b8 100644 --- a/demos/main/build.gradle +++ b/demos/main/build.gradle @@ -50,14 +50,14 @@ android { disable 'GoogleAppIndexingWarning','MissingTranslation','IconDensities' } - flavorDimensions "extensions" + flavorDimensions "decoderExtensions" productFlavors { - noExtensions { - dimension "extensions" + noDecoderExtensions { + dimension "decoderExtensions" } - withExtensions { - dimension "extensions" + withDecoderExtensions { + dimension "decoderExtensions" } } } @@ -72,13 +72,14 @@ dependencies { implementation project(modulePrefix + 'library-hls') implementation project(modulePrefix + 'library-smoothstreaming') implementation project(modulePrefix + 'library-ui') - withExtensionsImplementation project(path: modulePrefix + 'extension-av1') - withExtensionsImplementation project(path: modulePrefix + 'extension-ffmpeg') - withExtensionsImplementation project(path: modulePrefix + 'extension-flac') - withExtensionsImplementation project(path: modulePrefix + 'extension-ima') - withExtensionsImplementation project(path: modulePrefix + 'extension-opus') - withExtensionsImplementation project(path: modulePrefix + 'extension-vp9') - withExtensionsImplementation project(path: modulePrefix + 'extension-rtmp') + implementation project(modulePrefix + 'extension-cronet') + implementation project(modulePrefix + 'extension-ima') + withDecoderExtensionsImplementation project(modulePrefix + 'extension-av1') + withDecoderExtensionsImplementation project(modulePrefix + 'extension-ffmpeg') + withDecoderExtensionsImplementation project(modulePrefix + 'extension-flac') + withDecoderExtensionsImplementation project(modulePrefix + 'extension-opus') + withDecoderExtensionsImplementation project(modulePrefix + 'extension-vp9') + withDecoderExtensionsImplementation project(modulePrefix + 'extension-rtmp') } apply plugin: 'com.google.android.gms.strict-version-matcher-plugin' diff --git a/demos/main/proguard-rules.txt b/demos/main/proguard-rules.txt index cd201892ab..5358f3cec7 100644 --- a/demos/main/proguard-rules.txt +++ b/demos/main/proguard-rules.txt @@ -1,7 +1,2 @@ # Proguard rules specific to the main demo app. -# Constructor accessed via reflection in PlayerActivity --dontnote com.google.android.exoplayer2.ext.ima.ImaAdsLoader --keepclassmembers class com.google.android.exoplayer2.ext.ima.ImaAdsLoader { - (android.content.Context, android.net.Uri); -} diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoApplication.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoApplication.java index 39e64f8025..f4205efbb4 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoApplication.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoApplication.java @@ -20,13 +20,14 @@ import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.ExoDatabaseProvider; +import com.google.android.exoplayer2.ext.cronet.CronetDataSourceFactory; +import com.google.android.exoplayer2.ext.cronet.CronetEngineWrapper; import com.google.android.exoplayer2.offline.ActionFileUpgradeUtil; import com.google.android.exoplayer2.offline.DefaultDownloadIndex; import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.ui.DownloadNotificationHelper; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; -import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.cache.Cache; import com.google.android.exoplayer2.upstream.cache.CacheDataSource; @@ -50,8 +51,7 @@ public class DemoApplication extends MultiDexApplication { private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions"; private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads"; - protected String userAgent; - + private HttpDataSource.Factory httpDataSourceFactory; private DatabaseProvider databaseProvider; private File downloadDirectory; private Cache downloadCache; @@ -62,24 +62,26 @@ public class DemoApplication extends MultiDexApplication { @Override public void onCreate() { super.onCreate(); - userAgent = Util.getUserAgent(this, "ExoPlayerDemo"); + CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper(/* context= */ this); + String userAgent = Util.getUserAgent(this, "ExoPlayerDemo"); + httpDataSourceFactory = + new CronetDataSourceFactory( + cronetEngineWrapper, + Executors.newSingleThreadExecutor(), + /* transferListener= */ null, + userAgent); } /** Returns a {@link DataSource.Factory}. */ public DataSource.Factory buildDataSourceFactory() { DefaultDataSourceFactory upstreamFactory = - new DefaultDataSourceFactory(this, buildHttpDataSourceFactory()); + new DefaultDataSourceFactory(/* context= */ this, httpDataSourceFactory); return buildReadOnlyCacheDataSource(upstreamFactory, getDownloadCache()); } - /** Returns a {@link HttpDataSource.Factory}. */ - public HttpDataSource.Factory buildHttpDataSourceFactory() { - return new DefaultHttpDataSourceFactory(userAgent); - } - /** Returns whether extension renderers should be used. */ public boolean useExtensionRenderers() { - return "withExtensions".equals(BuildConfig.FLAVOR); + return "withDecoderExtensions".equals(BuildConfig.FLAVOR); } public RenderersFactory buildRenderersFactory(boolean preferExtensionRenderer) { @@ -112,7 +114,7 @@ public class DemoApplication extends MultiDexApplication { return downloadTracker; } - protected synchronized Cache getDownloadCache() { + private synchronized Cache getDownloadCache() { if (downloadCache == null) { File downloadContentDirectory = new File(getDownloadDirectory(), DOWNLOAD_CONTENT_DIRECTORY); downloadCache = @@ -130,10 +132,10 @@ public class DemoApplication extends MultiDexApplication { DOWNLOAD_TRACKER_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ true); downloadManager = new DownloadManager( - this, + /* context= */ this, getDatabaseProvider(), getDownloadCache(), - buildHttpDataSourceFactory(), + httpDataSourceFactory, Executors.newFixedThreadPool(/* nThreads= */ 6)); downloadTracker = new DownloadTracker(/* context= */ this, buildDataSourceFactory(), downloadManager); @@ -171,7 +173,7 @@ public class DemoApplication extends MultiDexApplication { return downloadDirectory; } - protected static CacheDataSource.Factory buildReadOnlyCacheDataSource( + private static CacheDataSource.Factory buildReadOnlyCacheDataSource( DataSource.Factory upstreamFactory, Cache cache) { return new CacheDataSource.Factory() .setCache(cache) diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index bf203159f9..5983f41255 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -29,7 +29,6 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; @@ -39,6 +38,7 @@ import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.audio.AudioAttributes; +import com.google.android.exoplayer2.ext.ima.ImaAdsLoader; import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer2.source.BehindLiveWindowException; @@ -60,7 +60,6 @@ import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.ErrorMessageProvider; import com.google.android.exoplayer2.util.EventLogger; import com.google.android.exoplayer2.util.Util; -import java.lang.reflect.Constructor; import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookiePolicy; @@ -447,31 +446,6 @@ public class PlayerActivity extends AppCompatActivity return ((DemoApplication) getApplication()).buildDataSourceFactory(); } - /** - * Returns an ads loader for the Interactive Media Ads SDK if found in the classpath, or null - * otherwise. - */ - @Nullable - private AdsLoader maybeCreateAdsLoader(Uri adTagUri) { - // Load the extension source using reflection so the demo app doesn't have to depend on it. - try { - Class loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader"); - // Full class names used so the lint rule triggers should any of the classes move. - // LINT.IfChange - Constructor loaderConstructor = - loaderClass - .asSubclass(AdsLoader.class) - .getConstructor(android.content.Context.class, android.net.Uri.class); - // LINT.ThenChange(../../../../../../../../proguard-rules.txt) - return loaderConstructor.newInstance(this, adTagUri); - } catch (ClassNotFoundException e) { - // IMA extension not loaded. - return null; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - // User controls private void updateButtonVisibility() { @@ -585,7 +559,6 @@ public class PlayerActivity extends AppCompatActivity private class AdSupportProvider implements DefaultMediaSourceFactory.AdSupportProvider { - @Nullable @Override public AdsLoader getAdsLoader(Uri adTagUri) { if (mediaItems.size() > 1) { @@ -599,13 +572,9 @@ public class PlayerActivity extends AppCompatActivity } // The ads loader is reused for multiple playbacks, so that ad playback can resume. if (adsLoader == null) { - adsLoader = maybeCreateAdsLoader(adTagUri); - } - if (adsLoader != null) { - adsLoader.setPlayer(player); - } else { - showToast(R.string.ima_not_loaded); + adsLoader = new ImaAdsLoader(/* context= */ PlayerActivity.this, adTagUri); } + adsLoader.setPlayer(player); return adsLoader; } diff --git a/demos/main/src/main/res/values/strings.xml b/demos/main/src/main/res/values/strings.xml index 671303a522..fab74d03cc 100644 --- a/demos/main/src/main/res/values/strings.xml +++ b/demos/main/src/main/res/values/strings.xml @@ -51,8 +51,6 @@ One or more sample lists failed to load - Playing sample without ads, as the IMA extension was not loaded - Playing sample without ads, as ads are not supported in concatenations Failed to start download diff --git a/extensions/ima/README.md b/extensions/ima/README.md index f28ba2977e..0a9bf1aa5e 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -46,12 +46,10 @@ On returning to the foreground, seek to that position before preparing the new player instance. Finally, it is important to call `ImaAdsLoader.release()` when playback of the content/ads has finished and will not be resumed. -You can try the IMA extension in the ExoPlayer demo app. To do this you must -select and build one of the `withExtensions` build variants of the demo app in -Android Studio. You can find IMA test content in the "IMA sample ad tags" -section of the app. The demo app's `PlayerActivity` also shows how to persist -the `ImaAdsLoader` instance and the player position when backgrounded during ad -playback. +You can try the IMA extension in the ExoPlayer demo app, which has test content +in the "IMA sample ad tags" section of the sample chooser. The demo app's +`PlayerActivity` also shows how to persist the `ImaAdsLoader` instance and the +player position when backgrounded during ad playback. [top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md [sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags