Move functionality from DemoApplication to DemoUtil

https://developer.android.com/reference/android/app/Application recommends
against subclassing application.

PiperOrigin-RevId: 322163812
This commit is contained in:
andrewlewis 2020-07-20 17:47:29 +01:00 committed by Oliver Woodman
parent 97cc355baf
commit 9594aa45ff
8 changed files with 123 additions and 89 deletions

View File

@ -63,6 +63,7 @@ android {
}
dependencies {
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
implementation 'androidx.appcompat:appcompat:' + androidxAppCompatVersion
implementation 'androidx.multidex:multidex:' + androidxMultidexVersion

View File

@ -35,7 +35,7 @@
android:largeHeap="true"
android:allowBackup="false"
android:requestLegacyExternalStorage="true"
android:name="com.google.android.exoplayer2.demo.DemoApplication"
android:name="androidx.multidex.MultiDexApplication"
tools:ignore="UnusedAttribute">
<activity android:name="com.google.android.exoplayer2.demo.SampleChooserActivity"

View File

@ -15,7 +15,7 @@
*/
package com.google.android.exoplayer2.demo;
import static com.google.android.exoplayer2.demo.DemoApplication.DOWNLOAD_NOTIFICATION_CHANNEL_ID;
import static com.google.android.exoplayer2.demo.DemoUtil.DOWNLOAD_NOTIFICATION_CHANNEL_ID;
import android.app.Notification;
import android.content.Context;
@ -50,10 +50,9 @@ public class DemoDownloadService extends DownloadService {
protected DownloadManager getDownloadManager() {
// This will only happen once, because getDownloadManager is guaranteed to be called only once
// in the life cycle of the process.
DemoApplication application = (DemoApplication) getApplication();
DownloadManager downloadManager = application.getDownloadManager();
DownloadManager downloadManager = DemoUtil.getDownloadManager(/* context= */ this);
DownloadNotificationHelper downloadNotificationHelper =
application.getDownloadNotificationHelper();
DemoUtil.getDownloadNotificationHelper(/* context= */ this);
downloadManager.addListener(
new TerminalStateNotificationHelper(
this, downloadNotificationHelper, FOREGROUND_NOTIFICATION_ID + 1));
@ -68,10 +67,13 @@ public class DemoDownloadService extends DownloadService {
@Override
@NonNull
protected Notification getForegroundNotification(@NonNull List<Download> downloads) {
return ((DemoApplication) getApplication())
.getDownloadNotificationHelper()
return DemoUtil.getDownloadNotificationHelper(/* context= */ this)
.buildProgressNotification(
R.drawable.ic_download, /* contentIntent= */ null, /* message= */ null, downloads);
/* context= */ this,
R.drawable.ic_download,
/* contentIntent= */ null,
/* message= */ null,
downloads);
}
/**
@ -101,12 +103,14 @@ public class DemoDownloadService extends DownloadService {
if (download.state == Download.STATE_COMPLETED) {
notification =
notificationHelper.buildDownloadCompletedNotification(
context,
R.drawable.ic_download_done,
/* contentIntent= */ null,
Util.fromUtf8Bytes(download.request.data));
} else if (download.state == Download.STATE_FAILED) {
notification =
notificationHelper.buildDownloadFailedNotification(
context,
R.drawable.ic_download_done,
/* contentIntent= */ null,
Util.fromUtf8Bytes(download.request.data));

View File

@ -15,7 +15,7 @@
*/
package com.google.android.exoplayer2.demo;
import androidx.multidex.MultiDexApplication;
import android.content.Context;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.database.DatabaseProvider;
@ -38,53 +38,34 @@ import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executors;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* Placeholder application to facilitate overriding Application methods for debugging and testing.
*/
public class DemoApplication extends MultiDexApplication {
/** Utility methods for the demo app. */
public final class DemoUtil {
public static final String DOWNLOAD_NOTIFICATION_CHANNEL_ID = "download_channel";
private static final String TAG = "DemoApplication";
private static final String TAG = "DemoUtil";
private static final String DOWNLOAD_ACTION_FILE = "actions";
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
private HttpDataSource.Factory httpDataSourceFactory;
private DatabaseProvider databaseProvider;
private File downloadDirectory;
private Cache downloadCache;
private DownloadManager downloadManager;
private DownloadTracker downloadTracker;
private DownloadNotificationHelper downloadNotificationHelper;
@Override
public void onCreate() {
super.onCreate();
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(/* context= */ this, httpDataSourceFactory);
return buildReadOnlyCacheDataSource(upstreamFactory, getDownloadCache());
}
private static DataSource.@MonotonicNonNull Factory dataSourceFactory;
private static HttpDataSource.@MonotonicNonNull Factory httpDataSourceFactory;
private static @MonotonicNonNull DatabaseProvider databaseProvider;
private static @MonotonicNonNull File downloadDirectory;
private static @MonotonicNonNull Cache downloadCache;
private static @MonotonicNonNull DownloadManager downloadManager;
private static @MonotonicNonNull DownloadTracker downloadTracker;
private static @MonotonicNonNull DownloadNotificationHelper downloadNotificationHelper;
/** Returns whether extension renderers should be used. */
public boolean useExtensionRenderers() {
public static boolean useExtensionRenderers() {
return "withDecoderExtensions".equals(BuildConfig.FLAVOR);
}
public RenderersFactory buildRenderersFactory(boolean preferExtensionRenderer) {
public static RenderersFactory buildRenderersFactory(
Context context, boolean preferExtensionRenderer) {
@DefaultRenderersFactory.ExtensionRendererMode
int extensionRendererMode =
useExtensionRenderers()
@ -92,61 +73,96 @@ public class DemoApplication extends MultiDexApplication {
? DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER
: DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)
: DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF;
return new DefaultRenderersFactory(/* context= */ this)
return new DefaultRenderersFactory(context.getApplicationContext())
.setExtensionRendererMode(extensionRendererMode);
}
public DownloadNotificationHelper getDownloadNotificationHelper() {
public static synchronized HttpDataSource.Factory getHttpDataSourceFactory(Context context) {
if (httpDataSourceFactory == null) {
context = context.getApplicationContext();
CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper(context);
String userAgent = Util.getUserAgent(context, "ExoPlayerDemo");
httpDataSourceFactory =
new CronetDataSourceFactory(
cronetEngineWrapper,
Executors.newSingleThreadExecutor(),
/* transferListener= */ null,
userAgent);
}
return httpDataSourceFactory;
}
/** Returns a {@link DataSource.Factory}. */
public static synchronized DataSource.Factory buildDataSourceFactory(Context context) {
if (dataSourceFactory == null) {
context = context.getApplicationContext();
DefaultDataSourceFactory upstreamFactory =
new DefaultDataSourceFactory(context, getHttpDataSourceFactory(context));
dataSourceFactory = buildReadOnlyCacheDataSource(upstreamFactory, getDownloadCache(context));
}
return dataSourceFactory;
}
public static synchronized DownloadNotificationHelper getDownloadNotificationHelper(
Context context) {
if (downloadNotificationHelper == null) {
downloadNotificationHelper =
new DownloadNotificationHelper(this, DOWNLOAD_NOTIFICATION_CHANNEL_ID);
new DownloadNotificationHelper(context, DOWNLOAD_NOTIFICATION_CHANNEL_ID);
}
return downloadNotificationHelper;
}
public DownloadManager getDownloadManager() {
initDownloadManager();
public static synchronized DownloadManager getDownloadManager(Context context) {
ensureDownloadManagerInitialized(context);
return downloadManager;
}
public DownloadTracker getDownloadTracker() {
initDownloadManager();
public static synchronized DownloadTracker getDownloadTracker(Context context) {
ensureDownloadManagerInitialized(context);
return downloadTracker;
}
private synchronized Cache getDownloadCache() {
private static synchronized Cache getDownloadCache(Context context) {
if (downloadCache == null) {
File downloadContentDirectory = new File(getDownloadDirectory(), DOWNLOAD_CONTENT_DIRECTORY);
File downloadContentDirectory =
new File(getDownloadDirectory(context), DOWNLOAD_CONTENT_DIRECTORY);
downloadCache =
new SimpleCache(downloadContentDirectory, new NoOpCacheEvictor(), getDatabaseProvider());
new SimpleCache(
downloadContentDirectory, new NoOpCacheEvictor(), getDatabaseProvider(context));
}
return downloadCache;
}
private synchronized void initDownloadManager() {
private static synchronized void ensureDownloadManagerInitialized(Context context) {
if (downloadManager == null) {
DefaultDownloadIndex downloadIndex = new DefaultDownloadIndex(getDatabaseProvider());
DefaultDownloadIndex downloadIndex = new DefaultDownloadIndex(getDatabaseProvider(context));
upgradeActionFile(
DOWNLOAD_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ false);
context, DOWNLOAD_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ false);
upgradeActionFile(
DOWNLOAD_TRACKER_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ true);
context,
DOWNLOAD_TRACKER_ACTION_FILE,
downloadIndex,
/* addNewDownloadsAsCompleted= */ true);
downloadManager =
new DownloadManager(
/* context= */ this,
getDatabaseProvider(),
getDownloadCache(),
httpDataSourceFactory,
context,
getDatabaseProvider(context),
getDownloadCache(context),
getHttpDataSourceFactory(context),
Executors.newFixedThreadPool(/* nThreads= */ 6));
downloadTracker =
new DownloadTracker(/* context= */ this, buildDataSourceFactory(), downloadManager);
new DownloadTracker(context, buildDataSourceFactory(context), downloadManager);
}
}
private void upgradeActionFile(
String fileName, DefaultDownloadIndex downloadIndex, boolean addNewDownloadsAsCompleted) {
private static synchronized void upgradeActionFile(
Context context,
String fileName,
DefaultDownloadIndex downloadIndex,
boolean addNewDownloadsAsCompleted) {
try {
ActionFileUpgradeUtil.upgradeAndDelete(
new File(getDownloadDirectory(), fileName),
new File(getDownloadDirectory(context), fileName),
/* downloadIdProvider= */ null,
downloadIndex,
/* deleteOnFailure= */ true,
@ -156,18 +172,18 @@ public class DemoApplication extends MultiDexApplication {
}
}
private DatabaseProvider getDatabaseProvider() {
private static synchronized DatabaseProvider getDatabaseProvider(Context context) {
if (databaseProvider == null) {
databaseProvider = new ExoDatabaseProvider(this);
databaseProvider = new ExoDatabaseProvider(context);
}
return databaseProvider;
}
private File getDownloadDirectory() {
private static synchronized File getDownloadDirectory(Context context) {
if (downloadDirectory == null) {
downloadDirectory = getExternalFilesDir(null);
downloadDirectory = context.getExternalFilesDir(/* type= */ null);
if (downloadDirectory == null) {
downloadDirectory = getFilesDir();
downloadDirectory = context.getFilesDir();
}
}
return downloadDirectory;
@ -181,4 +197,6 @@ public class DemoApplication extends MultiDexApplication {
.setCacheWriteDataSinkFactory(null)
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
}
private DemoUtil() {}
}

View File

@ -315,7 +315,7 @@ public class PlayerActivity extends AppCompatActivity
boolean preferExtensionDecoders =
intent.getBooleanExtra(IntentUtil.PREFER_EXTENSION_DECODERS_EXTRA, false);
RenderersFactory renderersFactory =
((DemoApplication) getApplication()).buildRenderersFactory(preferExtensionDecoders);
DemoUtil.buildRenderersFactory(/* context= */ this, preferExtensionDecoders);
trackSelector = new DefaultTrackSelector(/* context= */ this, trackSelectionFactory);
trackSelector.setParameters(trackSelectorParameters);
@ -357,7 +357,7 @@ public class PlayerActivity extends AppCompatActivity
List<MediaItem> mediaItems =
IntentUtil.createMediaItemsFromIntent(
intent, ((DemoApplication) getApplication()).getDownloadTracker());
intent, DemoUtil.getDownloadTracker(/* context= */ this));
boolean hasAds = false;
for (int i = 0; i < mediaItems.size(); i++) {
MediaItem mediaItem = mediaItems.get(i);
@ -439,7 +439,7 @@ public class PlayerActivity extends AppCompatActivity
/** Returns a new DataSource factory. */
protected DataSource.Factory buildDataSourceFactory() {
return ((DemoApplication) getApplication()).buildDataSourceFactory();
return DemoUtil.buildDataSourceFactory(/* context= */ this);
}
// User controls

View File

@ -114,9 +114,8 @@ public class SampleChooserActivity extends AppCompatActivity
Arrays.sort(uris);
}
DemoApplication application = (DemoApplication) getApplication();
useExtensionRenderers = application.useExtensionRenderers();
downloadTracker = application.getDownloadTracker();
useExtensionRenderers = DemoUtil.useExtensionRenderers();
downloadTracker = DemoUtil.getDownloadTracker(/* context= */ this);
loadSample();
// Start the download service if it should be running but it's not currently.
@ -247,8 +246,8 @@ public class SampleChooserActivity extends AppCompatActivity
.show();
} else {
RenderersFactory renderersFactory =
((DemoApplication) getApplication())
.buildRenderersFactory(isNonNullAndChecked(preferExtensionDecodersMenuItem));
DemoUtil.buildRenderersFactory(
/* context= */ this, isNonNullAndChecked(preferExtensionDecodersMenuItem));
downloadTracker.toggleDownload(
getSupportFragmentManager(), playlistHolder.mediaItems.get(0), renderersFactory);
}

View File

@ -31,7 +31,6 @@ public final class DownloadNotificationHelper {
private static final @StringRes int NULL_STRING_ID = 0;
private final Context context;
private final NotificationCompat.Builder notificationBuilder;
/**
@ -39,14 +38,14 @@ public final class DownloadNotificationHelper {
* @param channelId The id of the notification channel to use.
*/
public DownloadNotificationHelper(Context context, String channelId) {
context = context.getApplicationContext();
this.context = context;
this.notificationBuilder = new NotificationCompat.Builder(context, channelId);
this.notificationBuilder =
new NotificationCompat.Builder(context.getApplicationContext(), channelId);
}
/**
* Returns a progress notification for the given downloads.
*
* @param context A context.
* @param smallIcon A small icon for the notification.
* @param contentIntent An optional content intent to send when the notification is clicked.
* @param message An optional message to display on the notification.
@ -54,6 +53,7 @@ public final class DownloadNotificationHelper {
* @return The notification.
*/
public Notification buildProgressNotification(
Context context,
@DrawableRes int smallIcon,
@Nullable PendingIntent contentIntent,
@Nullable String message,
@ -95,6 +95,7 @@ public final class DownloadNotificationHelper {
indeterminate = allDownloadPercentagesUnknown && haveDownloadedBytes;
}
return buildNotification(
context,
smallIcon,
contentIntent,
message,
@ -109,37 +110,47 @@ public final class DownloadNotificationHelper {
/**
* Returns a notification for a completed download.
*
* @param context A context.
* @param smallIcon A small icon for the notifications.
* @param contentIntent An optional content intent to send when the notification is clicked.
* @param message An optional message to display on the notification.
* @return The notification.
*/
public Notification buildDownloadCompletedNotification(
@DrawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message) {
Context context,
@DrawableRes int smallIcon,
@Nullable PendingIntent contentIntent,
@Nullable String message) {
int titleStringId = R.string.exo_download_completed;
return buildEndStateNotification(smallIcon, contentIntent, message, titleStringId);
return buildEndStateNotification(context, smallIcon, contentIntent, message, titleStringId);
}
/**
* Returns a notification for a failed download.
*
* @param context A context.
* @param smallIcon A small icon for the notifications.
* @param contentIntent An optional content intent to send when the notification is clicked.
* @param message An optional message to display on the notification.
* @return The notification.
*/
public Notification buildDownloadFailedNotification(
@DrawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message) {
Context context,
@DrawableRes int smallIcon,
@Nullable PendingIntent contentIntent,
@Nullable String message) {
@StringRes int titleStringId = R.string.exo_download_failed;
return buildEndStateNotification(smallIcon, contentIntent, message, titleStringId);
return buildEndStateNotification(context, smallIcon, contentIntent, message, titleStringId);
}
private Notification buildEndStateNotification(
Context context,
@DrawableRes int smallIcon,
@Nullable PendingIntent contentIntent,
@Nullable String message,
@StringRes int titleStringId) {
return buildNotification(
context,
smallIcon,
contentIntent,
message,
@ -152,6 +163,7 @@ public final class DownloadNotificationHelper {
}
private Notification buildNotification(
Context context,
@DrawableRes int smallIcon,
@Nullable PendingIntent contentIntent,
@Nullable String message,

View File

@ -52,7 +52,7 @@ public final class DownloadNotificationUtil {
@Nullable String message,
List<Download> downloads) {
return new DownloadNotificationHelper(context, channelId)
.buildProgressNotification(smallIcon, contentIntent, message, downloads);
.buildProgressNotification(context, smallIcon, contentIntent, message, downloads);
}
/**
@ -72,7 +72,7 @@ public final class DownloadNotificationUtil {
@Nullable PendingIntent contentIntent,
@Nullable String message) {
return new DownloadNotificationHelper(context, channelId)
.buildDownloadCompletedNotification(smallIcon, contentIntent, message);
.buildDownloadCompletedNotification(context, smallIcon, contentIntent, message);
}
/**
@ -92,6 +92,6 @@ public final class DownloadNotificationUtil {
@Nullable PendingIntent contentIntent,
@Nullable String message) {
return new DownloadNotificationHelper(context, channelId)
.buildDownloadFailedNotification(smallIcon, contentIntent, message);
.buildDownloadFailedNotification(context, smallIcon, contentIntent, message);
}
}