mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Make DownloadManager watch requirements directly
PiperOrigin-RevId: 229544734
This commit is contained in:
parent
8adc16a623
commit
ec77f737ee
10 changed files with 249 additions and 149 deletions
|
|
@ -101,10 +101,12 @@ public class DemoApplication extends Application {
|
||||||
new DownloaderConstructorHelper(getDownloadCache(), buildHttpDataSourceFactory());
|
new DownloaderConstructorHelper(getDownloadCache(), buildHttpDataSourceFactory());
|
||||||
downloadManager =
|
downloadManager =
|
||||||
new DownloadManager(
|
new DownloadManager(
|
||||||
|
this,
|
||||||
new File(getDownloadDirectory(), DOWNLOAD_ACTION_FILE),
|
new File(getDownloadDirectory(), DOWNLOAD_ACTION_FILE),
|
||||||
new DefaultDownloaderFactory(downloaderConstructorHelper),
|
new DefaultDownloaderFactory(downloaderConstructorHelper),
|
||||||
MAX_SIMULTANEOUS_DOWNLOADS,
|
MAX_SIMULTANEOUS_DOWNLOADS,
|
||||||
DownloadManager.DEFAULT_MIN_RETRY_COUNT);
|
DownloadManager.DEFAULT_MIN_RETRY_COUNT,
|
||||||
|
DownloadManager.DEFAULT_REQUIREMENTS);
|
||||||
downloadTracker =
|
downloadTracker =
|
||||||
new DownloadTracker(
|
new DownloadTracker(
|
||||||
/* context= */ this,
|
/* context= */ this,
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import com.google.android.exoplayer2.offline.DownloadService;
|
||||||
import com.google.android.exoplayer2.offline.DownloadState;
|
import com.google.android.exoplayer2.offline.DownloadState;
|
||||||
import com.google.android.exoplayer2.offline.ProgressiveDownloadHelper;
|
import com.google.android.exoplayer2.offline.ProgressiveDownloadHelper;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.source.dash.offline.DashDownloadHelper;
|
import com.google.android.exoplayer2.source.dash.offline.DashDownloadHelper;
|
||||||
import com.google.android.exoplayer2.source.hls.offline.HlsDownloadHelper;
|
import com.google.android.exoplayer2.source.hls.offline.HlsDownloadHelper;
|
||||||
|
|
@ -159,6 +160,14 @@ public class DownloadTracker implements DownloadManager.Listener {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequirementsStateChanged(
|
||||||
|
DownloadManager downloadManager,
|
||||||
|
Requirements requirements,
|
||||||
|
@Requirements.RequirementFlags int notMetRequirements) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
// Internal methods
|
// Internal methods
|
||||||
|
|
||||||
private void loadTrackedActions() {
|
private void loadTrackedActions() {
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,15 @@ import static com.google.android.exoplayer2.offline.DownloadState.STATE_STOPPED;
|
||||||
import static com.google.android.exoplayer2.offline.DownloadState.STOP_FLAG_DOWNLOAD_MANAGER_NOT_READY;
|
import static com.google.android.exoplayer2.offline.DownloadState.STOP_FLAG_DOWNLOAD_MANAGER_NOT_READY;
|
||||||
import static com.google.android.exoplayer2.offline.DownloadState.STOP_FLAG_STOPPED;
|
import static com.google.android.exoplayer2.offline.DownloadState.STOP_FLAG_STOPPED;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.ConditionVariable;
|
import android.os.ConditionVariable;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
|
import com.google.android.exoplayer2.scheduler.RequirementsWatcher;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Log;
|
import com.google.android.exoplayer2.util.Log;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
@ -74,18 +77,35 @@ public final class DownloadManager {
|
||||||
* @param downloadManager The reporting instance.
|
* @param downloadManager The reporting instance.
|
||||||
*/
|
*/
|
||||||
void onIdle(DownloadManager downloadManager);
|
void onIdle(DownloadManager downloadManager);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the download requirements state changed.
|
||||||
|
*
|
||||||
|
* @param downloadManager The reporting instance.
|
||||||
|
* @param requirements Requirements needed to be met to start downloads.
|
||||||
|
* @param notMetRequirements {@link Requirements.RequirementFlags RequirementFlags} that are not
|
||||||
|
* met, or 0.
|
||||||
|
*/
|
||||||
|
void onRequirementsStateChanged(
|
||||||
|
DownloadManager downloadManager,
|
||||||
|
Requirements requirements,
|
||||||
|
@Requirements.RequirementFlags int notMetRequirements);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The default maximum number of simultaneous downloads. */
|
/** The default maximum number of simultaneous downloads. */
|
||||||
public static final int DEFAULT_MAX_SIMULTANEOUS_DOWNLOADS = 1;
|
public static final int DEFAULT_MAX_SIMULTANEOUS_DOWNLOADS = 1;
|
||||||
/** The default minimum number of times a download must be retried before failing. */
|
/** The default minimum number of times a download must be retried before failing. */
|
||||||
public static final int DEFAULT_MIN_RETRY_COUNT = 5;
|
public static final int DEFAULT_MIN_RETRY_COUNT = 5;
|
||||||
|
/** The default requirement is that the device has network connectivity. */
|
||||||
|
public static final Requirements DEFAULT_REQUIREMENTS =
|
||||||
|
new Requirements(Requirements.NETWORK_TYPE_ANY, false, false);
|
||||||
|
|
||||||
private static final String TAG = "DownloadManager";
|
private static final String TAG = "DownloadManager";
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
private final int maxActiveDownloads;
|
private final int maxActiveDownloads;
|
||||||
private final int minRetryCount;
|
private final int minRetryCount;
|
||||||
|
private final Context context;
|
||||||
private final ActionFile actionFile;
|
private final ActionFile actionFile;
|
||||||
private final DownloaderFactory downloaderFactory;
|
private final DownloaderFactory downloaderFactory;
|
||||||
private final ArrayList<Download> downloads;
|
private final ArrayList<Download> downloads;
|
||||||
|
|
@ -99,31 +119,43 @@ public final class DownloadManager {
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
private boolean released;
|
private boolean released;
|
||||||
@DownloadState.StopFlags private int stickyStopFlags;
|
@DownloadState.StopFlags private int stickyStopFlags;
|
||||||
|
private RequirementsWatcher requirementsWatcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@link DownloadManager}.
|
* Constructs a {@link DownloadManager}.
|
||||||
*
|
*
|
||||||
|
* @param context Any context.
|
||||||
* @param actionFile The file in which active actions are saved.
|
* @param actionFile The file in which active actions are saved.
|
||||||
* @param downloaderFactory A factory for creating {@link Downloader}s.
|
* @param downloaderFactory A factory for creating {@link Downloader}s.
|
||||||
*/
|
*/
|
||||||
public DownloadManager(File actionFile, DownloaderFactory downloaderFactory) {
|
public DownloadManager(Context context, File actionFile, DownloaderFactory downloaderFactory) {
|
||||||
this(
|
this(
|
||||||
actionFile, downloaderFactory, DEFAULT_MAX_SIMULTANEOUS_DOWNLOADS, DEFAULT_MIN_RETRY_COUNT);
|
context,
|
||||||
|
actionFile,
|
||||||
|
downloaderFactory,
|
||||||
|
DEFAULT_MAX_SIMULTANEOUS_DOWNLOADS,
|
||||||
|
DEFAULT_MIN_RETRY_COUNT,
|
||||||
|
DEFAULT_REQUIREMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@link DownloadManager}.
|
* Constructs a {@link DownloadManager}.
|
||||||
*
|
*
|
||||||
|
* @param context Any context.
|
||||||
* @param actionFile The file in which active actions are saved.
|
* @param actionFile The file in which active actions are saved.
|
||||||
* @param downloaderFactory A factory for creating {@link Downloader}s.
|
* @param downloaderFactory A factory for creating {@link Downloader}s.
|
||||||
* @param maxSimultaneousDownloads The maximum number of simultaneous downloads.
|
* @param maxSimultaneousDownloads The maximum number of simultaneous downloads.
|
||||||
* @param minRetryCount The minimum number of times a download must be retried before failing.
|
* @param minRetryCount The minimum number of times a download must be retried before failing.
|
||||||
|
* @param requirements The requirements needed to be met to start downloads.
|
||||||
*/
|
*/
|
||||||
public DownloadManager(
|
public DownloadManager(
|
||||||
|
Context context,
|
||||||
File actionFile,
|
File actionFile,
|
||||||
DownloaderFactory downloaderFactory,
|
DownloaderFactory downloaderFactory,
|
||||||
int maxSimultaneousDownloads,
|
int maxSimultaneousDownloads,
|
||||||
int minRetryCount) {
|
int minRetryCount,
|
||||||
|
Requirements requirements) {
|
||||||
|
this.context = context.getApplicationContext();
|
||||||
this.actionFile = new ActionFile(actionFile);
|
this.actionFile = new ActionFile(actionFile);
|
||||||
this.downloaderFactory = downloaderFactory;
|
this.downloaderFactory = downloaderFactory;
|
||||||
this.maxActiveDownloads = maxSimultaneousDownloads;
|
this.maxActiveDownloads = maxSimultaneousDownloads;
|
||||||
|
|
@ -146,10 +178,30 @@ public final class DownloadManager {
|
||||||
listeners = new CopyOnWriteArraySet<>();
|
listeners = new CopyOnWriteArraySet<>();
|
||||||
actionQueue = new ArrayDeque<>();
|
actionQueue = new ArrayDeque<>();
|
||||||
|
|
||||||
|
watchRequirements(requirements);
|
||||||
loadActions();
|
loadActions();
|
||||||
logd("Created");
|
logd("Created");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the requirements needed to be met to start downloads.
|
||||||
|
*
|
||||||
|
* @param requirements Need to be met to start downloads.
|
||||||
|
*/
|
||||||
|
public void setRequirements(Requirements requirements) {
|
||||||
|
Assertions.checkState(!released);
|
||||||
|
if (requirements.equals(requirementsWatcher.getRequirements())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
requirementsWatcher.stop();
|
||||||
|
notifyListenersRequirementsStateChange(watchRequirements(requirements));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the requirements needed to be met to start downloads. */
|
||||||
|
public Requirements getRequirements() {
|
||||||
|
return requirementsWatcher.getRequirements();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a {@link Listener}.
|
* Adds a {@link Listener}.
|
||||||
*
|
*
|
||||||
|
|
@ -278,6 +330,9 @@ public final class DownloadManager {
|
||||||
}
|
}
|
||||||
setStopFlags(STOP_FLAG_DOWNLOAD_MANAGER_NOT_READY);
|
setStopFlags(STOP_FLAG_DOWNLOAD_MANAGER_NOT_READY);
|
||||||
released = true;
|
released = true;
|
||||||
|
if (requirementsWatcher != null) {
|
||||||
|
requirementsWatcher.stop();
|
||||||
|
}
|
||||||
final ConditionVariable fileIOFinishedCondition = new ConditionVariable();
|
final ConditionVariable fileIOFinishedCondition = new ConditionVariable();
|
||||||
fileIOHandler.post(fileIOFinishedCondition::open);
|
fileIOHandler.post(fileIOFinishedCondition::open);
|
||||||
fileIOFinishedCondition.block();
|
fileIOFinishedCondition.block();
|
||||||
|
|
@ -346,6 +401,15 @@ public final class DownloadManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void notifyListenersRequirementsStateChange(
|
||||||
|
@Requirements.RequirementFlags int notMetRequirements) {
|
||||||
|
logdFlags("Not met requirements are changed", notMetRequirements);
|
||||||
|
for (Listener listener : listeners) {
|
||||||
|
listener.onRequirementsStateChanged(
|
||||||
|
DownloadManager.this, requirementsWatcher.getRequirements(), notMetRequirements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void loadActions() {
|
private void loadActions() {
|
||||||
fileIOHandler.post(
|
fileIOHandler.post(
|
||||||
() -> {
|
() -> {
|
||||||
|
|
@ -420,6 +484,18 @@ public final class DownloadManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Requirements.RequirementFlags
|
||||||
|
private int watchRequirements(Requirements requirements) {
|
||||||
|
requirementsWatcher = new RequirementsWatcher(context, new RequirementListener(), requirements);
|
||||||
|
@Requirements.RequirementFlags int notMetRequirements = requirementsWatcher.start();
|
||||||
|
if (notMetRequirements == 0) {
|
||||||
|
startDownloads();
|
||||||
|
} else {
|
||||||
|
stopDownloads();
|
||||||
|
}
|
||||||
|
return notMetRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
private static final class Download {
|
private static final class Download {
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
@ -693,4 +769,20 @@ public final class DownloadManager {
|
||||||
return Math.min((errorCount - 1) * 1000, 5000);
|
return Math.min((errorCount - 1) * 1000, 5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class RequirementListener implements RequirementsWatcher.Listener {
|
||||||
|
@Override
|
||||||
|
public void requirementsMet(RequirementsWatcher requirementsWatcher) {
|
||||||
|
startDownloads();
|
||||||
|
notifyListenersRequirementsStateChange(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requirementsNotMet(
|
||||||
|
RequirementsWatcher requirementsWatcher,
|
||||||
|
@Requirements.RequirementFlags int notMetRequirements) {
|
||||||
|
stopDownloads();
|
||||||
|
notifyListenersRequirementsStateChange(notMetRequirements);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import android.os.Looper;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import com.google.android.exoplayer2.scheduler.Requirements;
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
import com.google.android.exoplayer2.scheduler.RequirementsWatcher;
|
|
||||||
import com.google.android.exoplayer2.scheduler.Scheduler;
|
import com.google.android.exoplayer2.scheduler.Scheduler;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Log;
|
import com.google.android.exoplayer2.util.Log;
|
||||||
import com.google.android.exoplayer2.util.NotificationUtil;
|
import com.google.android.exoplayer2.util.NotificationUtil;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
@ -43,10 +43,6 @@ public abstract class DownloadService extends Service {
|
||||||
/** Starts a download service, adding a new {@link DownloadAction} to be executed. */
|
/** Starts a download service, adding a new {@link DownloadAction} to be executed. */
|
||||||
public static final String ACTION_ADD = "com.google.android.exoplayer.downloadService.action.ADD";
|
public static final String ACTION_ADD = "com.google.android.exoplayer.downloadService.action.ADD";
|
||||||
|
|
||||||
/** Reloads the download requirements. */
|
|
||||||
public static final String ACTION_RELOAD_REQUIREMENTS =
|
|
||||||
"com.google.android.exoplayer.downloadService.action.RELOAD_REQUIREMENTS";
|
|
||||||
|
|
||||||
/** Like {@link #ACTION_INIT}, but with {@link #KEY_FOREGROUND} implicitly set to true. */
|
/** Like {@link #ACTION_INIT}, but with {@link #KEY_FOREGROUND} implicitly set to true. */
|
||||||
private static final String ACTION_RESTART =
|
private static final String ACTION_RESTART =
|
||||||
"com.google.android.exoplayer.downloadService.action.RESTART";
|
"com.google.android.exoplayer.downloadService.action.RESTART";
|
||||||
|
|
@ -70,20 +66,16 @@ public abstract class DownloadService extends Service {
|
||||||
private static final String TAG = "DownloadService";
|
private static final String TAG = "DownloadService";
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
// Keep the requirements helper for each DownloadService as long as there are downloads (and the
|
// Keep DownloadManagerListeners for each DownloadService as long as there are downloads (and the
|
||||||
// process is running). This allows downloads to resume when there's no scheduler. It may also
|
// process is running). This allows DownloadService to restart when there's no scheduler.
|
||||||
// allow downloads the resume more quickly than when relying on the scheduler alone.
|
private static final HashMap<Class<? extends DownloadService>, DownloadManagerHelper>
|
||||||
private static final HashMap<Class<? extends DownloadService>, RequirementsHelper>
|
downloadManagerListeners = new HashMap<>();
|
||||||
requirementsHelpers = new HashMap<>();
|
|
||||||
private static final Requirements DEFAULT_REQUIREMENTS =
|
|
||||||
new Requirements(Requirements.NETWORK_TYPE_ANY, false, false);
|
|
||||||
|
|
||||||
private final @Nullable ForegroundNotificationUpdater foregroundNotificationUpdater;
|
private final @Nullable ForegroundNotificationUpdater foregroundNotificationUpdater;
|
||||||
private final @Nullable String channelId;
|
private final @Nullable String channelId;
|
||||||
private final @StringRes int channelName;
|
private final @StringRes int channelName;
|
||||||
|
|
||||||
private DownloadManager downloadManager;
|
private DownloadManager downloadManager;
|
||||||
private DownloadManagerListener downloadManagerListener;
|
|
||||||
private int lastStartId;
|
private int lastStartId;
|
||||||
private boolean startedInForeground;
|
private boolean startedInForeground;
|
||||||
private boolean taskRemoved;
|
private boolean taskRemoved;
|
||||||
|
|
@ -227,9 +219,16 @@ public abstract class DownloadService extends Service {
|
||||||
NotificationUtil.createNotificationChannel(
|
NotificationUtil.createNotificationChannel(
|
||||||
this, channelId, channelName, NotificationUtil.IMPORTANCE_LOW);
|
this, channelId, channelName, NotificationUtil.IMPORTANCE_LOW);
|
||||||
}
|
}
|
||||||
downloadManager = getDownloadManager();
|
Class<? extends DownloadService> clazz = getClass();
|
||||||
downloadManagerListener = new DownloadManagerListener();
|
DownloadManagerHelper downloadManagerHelper = downloadManagerListeners.get(clazz);
|
||||||
downloadManager.addListener(downloadManagerListener);
|
if (downloadManagerHelper == null) {
|
||||||
|
downloadManagerHelper =
|
||||||
|
new DownloadManagerHelper(
|
||||||
|
getApplicationContext(), getDownloadManager(), getScheduler(), clazz);
|
||||||
|
downloadManagerListeners.put(clazz, downloadManagerHelper);
|
||||||
|
}
|
||||||
|
downloadManager = downloadManagerHelper.downloadManager;
|
||||||
|
downloadManagerHelper.attachService(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -264,22 +263,11 @@ public abstract class DownloadService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_RELOAD_REQUIREMENTS:
|
|
||||||
stopWatchingRequirements();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "Ignoring unrecognized action: " + intentAction);
|
Log.e(TAG, "Ignoring unrecognized action: " + intentAction);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Requirements requirements = getRequirements();
|
|
||||||
if (requirements.checkRequirements(this)) {
|
|
||||||
downloadManager.startDownloads();
|
|
||||||
} else {
|
|
||||||
downloadManager.stopDownloads();
|
|
||||||
}
|
|
||||||
maybeStartWatchingRequirements(requirements);
|
|
||||||
|
|
||||||
if (downloadManager.isIdle()) {
|
if (downloadManager.isIdle()) {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
@ -295,11 +283,12 @@ public abstract class DownloadService extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
logd("onDestroy");
|
logd("onDestroy");
|
||||||
|
DownloadManagerHelper downloadManagerHelper = downloadManagerListeners.get(getClass());
|
||||||
|
boolean unschedule = downloadManager.getDownloadCount() <= 0;
|
||||||
|
downloadManagerHelper.detachService(this, unschedule);
|
||||||
if (foregroundNotificationUpdater != null) {
|
if (foregroundNotificationUpdater != null) {
|
||||||
foregroundNotificationUpdater.stopPeriodicUpdates();
|
foregroundNotificationUpdater.stopPeriodicUpdates();
|
||||||
}
|
}
|
||||||
downloadManager.removeListener(downloadManagerListener);
|
|
||||||
maybeStopWatchingRequirements();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DownloadService isn't designed to be bound. */
|
/** DownloadService isn't designed to be bound. */
|
||||||
|
|
@ -311,9 +300,7 @@ public abstract class DownloadService extends Service {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link DownloadManager} to be used to downloaded content. Called only once in the
|
* Returns a {@link DownloadManager} to be used to downloaded content. Called only once in the
|
||||||
* life cycle of the service. The service will call {@link DownloadManager#startDownloads()} and
|
* life cycle of the process.
|
||||||
* {@link DownloadManager#stopDownloads} as necessary when requirements returned by {@link
|
|
||||||
* #getRequirements()} are met or stop being met.
|
|
||||||
*/
|
*/
|
||||||
protected abstract DownloadManager getDownloadManager();
|
protected abstract DownloadManager getDownloadManager();
|
||||||
|
|
||||||
|
|
@ -324,14 +311,6 @@ public abstract class DownloadService extends Service {
|
||||||
*/
|
*/
|
||||||
protected abstract @Nullable Scheduler getScheduler();
|
protected abstract @Nullable Scheduler getScheduler();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns requirements for downloads to take place. By default the only requirement is that the
|
|
||||||
* device has network connectivity.
|
|
||||||
*/
|
|
||||||
protected Requirements getRequirements() {
|
|
||||||
return DEFAULT_REQUIREMENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be overridden in the subclass if the service will be run in the foreground.
|
* Should be overridden in the subclass if the service will be run in the foreground.
|
||||||
*
|
*
|
||||||
|
|
@ -363,32 +342,16 @@ public abstract class DownloadService extends Service {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeStartWatchingRequirements(Requirements requirements) {
|
private void notifyDownloadStateChange(DownloadState downloadState) {
|
||||||
if (downloadManager.getDownloadCount() == 0) {
|
onDownloadStateChanged(downloadState);
|
||||||
return;
|
if (foregroundNotificationUpdater != null) {
|
||||||
}
|
if (downloadState.state == DownloadState.STATE_DOWNLOADING
|
||||||
Class<? extends DownloadService> clazz = getClass();
|
|| downloadState.state == DownloadState.STATE_REMOVING
|
||||||
RequirementsHelper requirementsHelper = requirementsHelpers.get(clazz);
|
|| downloadState.state == DownloadState.STATE_RESTARTING) {
|
||||||
if (requirementsHelper == null) {
|
foregroundNotificationUpdater.startPeriodicUpdates();
|
||||||
requirementsHelper = new RequirementsHelper(this, requirements, getScheduler(), clazz);
|
} else {
|
||||||
requirementsHelpers.put(clazz, requirementsHelper);
|
foregroundNotificationUpdater.update();
|
||||||
requirementsHelper.start();
|
}
|
||||||
logd("started watching requirements");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeStopWatchingRequirements() {
|
|
||||||
if (downloadManager.getDownloadCount() > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stopWatchingRequirements();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopWatchingRequirements() {
|
|
||||||
RequirementsHelper requirementsHelper = requirementsHelpers.remove(getClass());
|
|
||||||
if (requirementsHelper != null) {
|
|
||||||
requirementsHelper.stop();
|
|
||||||
logd("stopped watching requirements");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -420,33 +383,6 @@ public abstract class DownloadService extends Service {
|
||||||
return new Intent(context, clazz).setAction(action);
|
return new Intent(context, clazz).setAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class DownloadManagerListener implements DownloadManager.Listener {
|
|
||||||
@Override
|
|
||||||
public void onInitialized(DownloadManager downloadManager) {
|
|
||||||
maybeStartWatchingRequirements(getRequirements());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDownloadStateChanged(
|
|
||||||
DownloadManager downloadManager, DownloadState downloadState) {
|
|
||||||
DownloadService.this.onDownloadStateChanged(downloadState);
|
|
||||||
if (foregroundNotificationUpdater != null) {
|
|
||||||
if (downloadState.state == DownloadState.STATE_DOWNLOADING
|
|
||||||
|| downloadState.state == DownloadState.STATE_REMOVING
|
|
||||||
|| downloadState.state == DownloadState.STATE_RESTARTING) {
|
|
||||||
foregroundNotificationUpdater.startPeriodicUpdates();
|
|
||||||
} else {
|
|
||||||
foregroundNotificationUpdater.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void onIdle(DownloadManager downloadManager) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class ForegroundNotificationUpdater implements Runnable {
|
private final class ForegroundNotificationUpdater implements Runnable {
|
||||||
|
|
||||||
private final int notificationId;
|
private final int notificationId;
|
||||||
|
|
@ -494,58 +430,87 @@ public abstract class DownloadService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class RequirementsHelper implements RequirementsWatcher.Listener {
|
private static final class DownloadManagerHelper implements DownloadManager.Listener {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final Requirements requirements;
|
private final DownloadManager downloadManager;
|
||||||
private final @Nullable Scheduler scheduler;
|
@Nullable private final Scheduler scheduler;
|
||||||
private final Class<? extends DownloadService> serviceClass;
|
private final Class<? extends DownloadService> serviceClass;
|
||||||
private final RequirementsWatcher requirementsWatcher;
|
@Nullable private DownloadService downloadService;
|
||||||
|
|
||||||
private RequirementsHelper(
|
private DownloadManagerHelper(
|
||||||
Context context,
|
Context context,
|
||||||
Requirements requirements,
|
DownloadManager downloadManager,
|
||||||
@Nullable Scheduler scheduler,
|
@Nullable Scheduler scheduler,
|
||||||
Class<? extends DownloadService> serviceClass) {
|
Class<? extends DownloadService> serviceClass) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.requirements = requirements;
|
this.downloadManager = downloadManager;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.serviceClass = serviceClass;
|
this.serviceClass = serviceClass;
|
||||||
requirementsWatcher = new RequirementsWatcher(context, this, requirements);
|
downloadManager.addListener(this);
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
requirementsWatcher.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
requirementsWatcher.stop();
|
|
||||||
if (scheduler != null) {
|
if (scheduler != null) {
|
||||||
|
Requirements requirements = downloadManager.getRequirements();
|
||||||
|
setSchedulerEnabled(/* enabled= */ !requirements.checkRequirements(context), requirements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attachService(DownloadService downloadService) {
|
||||||
|
Assertions.checkState(this.downloadService == null);
|
||||||
|
this.downloadService = downloadService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void detachService(DownloadService downloadService, boolean unschedule) {
|
||||||
|
Assertions.checkState(this.downloadService == downloadService);
|
||||||
|
this.downloadService = null;
|
||||||
|
if (unschedule) {
|
||||||
scheduler.cancel();
|
scheduler.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requirementsMet(RequirementsWatcher requirementsWatcher) {
|
public void onInitialized(DownloadManager downloadManager) {
|
||||||
try {
|
// Do nothing.
|
||||||
notifyService();
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
/* If we can't notify the service, don't stop the scheduler. */
|
@Override
|
||||||
return;
|
public void onDownloadStateChanged(
|
||||||
}
|
DownloadManager downloadManager, DownloadState downloadState) {
|
||||||
if (scheduler != null) {
|
if (downloadService != null) {
|
||||||
scheduler.cancel();
|
downloadService.notifyDownloadStateChange(downloadState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requirementsNotMet(RequirementsWatcher requirementsWatcher) {
|
public final void onIdle(DownloadManager downloadManager) {
|
||||||
try {
|
if (downloadService != null) {
|
||||||
notifyService();
|
downloadService.stop();
|
||||||
} catch (Exception e) {
|
}
|
||||||
/* Do nothing. The service isn't running anyway. */
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequirementsStateChanged(
|
||||||
|
DownloadManager downloadManager,
|
||||||
|
Requirements requirements,
|
||||||
|
@Requirements.RequirementFlags int notMetRequirements) {
|
||||||
|
boolean requirementsMet = notMetRequirements == 0;
|
||||||
|
if (downloadService == null && requirementsMet) {
|
||||||
|
try {
|
||||||
|
Intent intent = getIntent(context, serviceClass, DownloadService.ACTION_INIT);
|
||||||
|
context.startService(intent);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
/* startService fails if the app is in the background then don't stop the scheduler. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (scheduler != null) {
|
if (scheduler != null) {
|
||||||
|
setSchedulerEnabled(/* enabled= */ !requirementsMet, requirements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSchedulerEnabled(boolean enabled, Requirements requirements) {
|
||||||
|
if (!enabled) {
|
||||||
|
scheduler.cancel();
|
||||||
|
} else {
|
||||||
String servicePackage = context.getPackageName();
|
String servicePackage = context.getPackageName();
|
||||||
boolean success = scheduler.schedule(requirements, servicePackage, ACTION_RESTART);
|
boolean success = scheduler.schedule(requirements, servicePackage, ACTION_RESTART);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
@ -553,15 +518,5 @@ public abstract class DownloadService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyService() throws Exception {
|
|
||||||
Intent intent = getIntent(context, serviceClass, DownloadService.ACTION_INIT);
|
|
||||||
try {
|
|
||||||
context.startService(intent);
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
/* startService will fail if the app is in the background and the service isn't running. */
|
|
||||||
throw new Exception(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,16 +155,14 @@ public final class Requirements {
|
||||||
* @return Whether the requirements are met.
|
* @return Whether the requirements are met.
|
||||||
*/
|
*/
|
||||||
public boolean checkRequirements(Context context) {
|
public boolean checkRequirements(Context context) {
|
||||||
return checkNetworkRequirements(context)
|
return getNotMetRequirements(context) == 0;
|
||||||
&& checkChargingRequirement(context)
|
|
||||||
&& checkIdleRequirement(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the requirement flags that are not met, or 0.
|
* Returns {@link RequirementFlags} that are not met, or 0.
|
||||||
*
|
*
|
||||||
* @param context Any context.
|
* @param context Any context.
|
||||||
* @return The requirement flags that are not met, or 0.
|
* @return RequirementFlags that are not met, or 0.
|
||||||
*/
|
*/
|
||||||
@RequirementFlags
|
@RequirementFlags
|
||||||
public int getNotMetRequirements(Context context) {
|
public int getNotMetRequirements(Context context) {
|
||||||
|
|
@ -285,4 +283,20 @@ public final class Requirements {
|
||||||
+ (isIdleRequired() ? ",idle" : "")
|
+ (isIdleRequired() ? ",idle" : "")
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return requirements == ((Requirements) o).requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return requirements;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,12 @@ public final class RequirementsWatcher {
|
||||||
* requirements are not met.
|
* requirements are not met.
|
||||||
*
|
*
|
||||||
* @param requirementsWatcher Calling instance.
|
* @param requirementsWatcher Calling instance.
|
||||||
|
* @param notMetRequirements {@link Requirements.RequirementFlags RequirementFlags} that are not
|
||||||
|
* met, or 0.
|
||||||
*/
|
*/
|
||||||
void requirementsNotMet(RequirementsWatcher requirementsWatcher);
|
void requirementsNotMet(
|
||||||
|
RequirementsWatcher requirementsWatcher,
|
||||||
|
@Requirements.RequirementFlags int notMetRequirements);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TAG = "RequirementsWatcher";
|
private static final String TAG = "RequirementsWatcher";
|
||||||
|
|
@ -66,7 +70,7 @@ public final class RequirementsWatcher {
|
||||||
private final Requirements requirements;
|
private final Requirements requirements;
|
||||||
private DeviceStatusChangeReceiver receiver;
|
private DeviceStatusChangeReceiver receiver;
|
||||||
|
|
||||||
private int notMetRequirements;
|
@Requirements.RequirementFlags private int notMetRequirements;
|
||||||
private CapabilityValidatedCallback networkCallback;
|
private CapabilityValidatedCallback networkCallback;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
|
||||||
|
|
@ -85,8 +89,11 @@ public final class RequirementsWatcher {
|
||||||
/**
|
/**
|
||||||
* Starts watching for changes. Must be called from a thread that has an associated {@link
|
* Starts watching for changes. Must be called from a thread that has an associated {@link
|
||||||
* Looper}. Listener methods are called on the caller thread.
|
* Looper}. Listener methods are called on the caller thread.
|
||||||
|
*
|
||||||
|
* @return Initial {@link Requirements.RequirementFlags RequirementFlags} that are not met, or 0.
|
||||||
*/
|
*/
|
||||||
public void start() {
|
@Requirements.RequirementFlags
|
||||||
|
public int start() {
|
||||||
Assertions.checkNotNull(Looper.myLooper());
|
Assertions.checkNotNull(Looper.myLooper());
|
||||||
handler = new Handler();
|
handler = new Handler();
|
||||||
|
|
||||||
|
|
@ -115,6 +122,7 @@ public final class RequirementsWatcher {
|
||||||
receiver = new DeviceStatusChangeReceiver();
|
receiver = new DeviceStatusChangeReceiver();
|
||||||
context.registerReceiver(receiver, filter, null, handler);
|
context.registerReceiver(receiver, filter, null, handler);
|
||||||
logd(this + " started");
|
logd(this + " started");
|
||||||
|
return notMetRequirements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stops watching for changes. */
|
/** Stops watching for changes. */
|
||||||
|
|
@ -162,6 +170,7 @@ public final class RequirementsWatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkRequirements() {
|
private void checkRequirements() {
|
||||||
|
@Requirements.RequirementFlags
|
||||||
int notMetRequirements = requirements.getNotMetRequirements(context);
|
int notMetRequirements = requirements.getNotMetRequirements(context);
|
||||||
if (this.notMetRequirements == notMetRequirements) {
|
if (this.notMetRequirements == notMetRequirements) {
|
||||||
logd("notMetRequirements hasn't changed: " + notMetRequirements);
|
logd("notMetRequirements hasn't changed: " + notMetRequirements);
|
||||||
|
|
@ -173,7 +182,7 @@ public final class RequirementsWatcher {
|
||||||
listener.requirementsMet(this);
|
listener.requirementsMet(this);
|
||||||
} else {
|
} else {
|
||||||
logd("stop job");
|
logd("stop job");
|
||||||
listener.requirementsNotMet(this);
|
listener.requirementsNotMet(this, notMetRequirements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import static org.junit.Assert.fail;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.offline.DownloadState.State;
|
import com.google.android.exoplayer2.offline.DownloadState.State;
|
||||||
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
||||||
import com.google.android.exoplayer2.testutil.RobolectricUtil;
|
import com.google.android.exoplayer2.testutil.RobolectricUtil;
|
||||||
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
|
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
|
||||||
|
|
@ -426,7 +427,12 @@ public class DownloadManagerTest {
|
||||||
() -> {
|
() -> {
|
||||||
downloadManager =
|
downloadManager =
|
||||||
new DownloadManager(
|
new DownloadManager(
|
||||||
actionFile, downloaderFactory, maxActiveDownloadTasks, MIN_RETRY_COUNT);
|
RuntimeEnvironment.application,
|
||||||
|
actionFile,
|
||||||
|
downloaderFactory,
|
||||||
|
maxActiveDownloadTasks,
|
||||||
|
MIN_RETRY_COUNT,
|
||||||
|
new Requirements(0));
|
||||||
downloadManagerListener =
|
downloadManagerListener =
|
||||||
new TestDownloadManagerListener(downloadManager, dummyMainThread);
|
new TestDownloadManagerListener(downloadManager, dummyMainThread);
|
||||||
downloadManager.startDownloads();
|
downloadManager.startDownloads();
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import com.google.android.exoplayer2.offline.DownloadAction;
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
import com.google.android.exoplayer2.offline.DownloadManager;
|
||||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
||||||
import com.google.android.exoplayer2.testutil.FakeDataSet;
|
import com.google.android.exoplayer2.testutil.FakeDataSet;
|
||||||
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||||
|
|
@ -241,11 +242,13 @@ public class DownloadManagerDashTest {
|
||||||
Factory fakeDataSourceFactory = new FakeDataSource.Factory().setFakeDataSet(fakeDataSet);
|
Factory fakeDataSourceFactory = new FakeDataSource.Factory().setFakeDataSet(fakeDataSet);
|
||||||
downloadManager =
|
downloadManager =
|
||||||
new DownloadManager(
|
new DownloadManager(
|
||||||
|
RuntimeEnvironment.application,
|
||||||
actionFile,
|
actionFile,
|
||||||
new DefaultDownloaderFactory(
|
new DefaultDownloaderFactory(
|
||||||
new DownloaderConstructorHelper(cache, fakeDataSourceFactory)),
|
new DownloaderConstructorHelper(cache, fakeDataSourceFactory)),
|
||||||
/* maxSimultaneousDownloads= */ 1,
|
/* maxSimultaneousDownloads= */ 1,
|
||||||
/* minRetryCount= */ 3);
|
/* minRetryCount= */ 3,
|
||||||
|
new Requirements(0));
|
||||||
|
|
||||||
downloadManagerListener =
|
downloadManagerListener =
|
||||||
new TestDownloadManagerListener(downloadManager, dummyMainThread);
|
new TestDownloadManagerListener(downloadManager, dummyMainThread);
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import com.google.android.exoplayer2.offline.DownloadManager;
|
||||||
import com.google.android.exoplayer2.offline.DownloadService;
|
import com.google.android.exoplayer2.offline.DownloadService;
|
||||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
import com.google.android.exoplayer2.scheduler.Scheduler;
|
import com.google.android.exoplayer2.scheduler.Scheduler;
|
||||||
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
||||||
import com.google.android.exoplayer2.testutil.FakeDataSet;
|
import com.google.android.exoplayer2.testutil.FakeDataSet;
|
||||||
|
|
@ -117,11 +118,13 @@ public class DownloadServiceDashTest {
|
||||||
actionFile.delete();
|
actionFile.delete();
|
||||||
final DownloadManager dashDownloadManager =
|
final DownloadManager dashDownloadManager =
|
||||||
new DownloadManager(
|
new DownloadManager(
|
||||||
|
RuntimeEnvironment.application,
|
||||||
actionFile,
|
actionFile,
|
||||||
new DefaultDownloaderFactory(
|
new DefaultDownloaderFactory(
|
||||||
new DownloaderConstructorHelper(cache, fakeDataSourceFactory)),
|
new DownloaderConstructorHelper(cache, fakeDataSourceFactory)),
|
||||||
/* maxSimultaneousDownloads= */ 1,
|
/* maxSimultaneousDownloads= */ 1,
|
||||||
/* minRetryCount= */ 3);
|
/* minRetryCount= */ 3,
|
||||||
|
new Requirements(0));
|
||||||
downloadManagerListener =
|
downloadManagerListener =
|
||||||
new TestDownloadManagerListener(dashDownloadManager, dummyMainThread);
|
new TestDownloadManagerListener(dashDownloadManager, dummyMainThread);
|
||||||
dashDownloadManager.startDownloads();
|
dashDownloadManager.startDownloads();
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||||
import android.os.ConditionVariable;
|
import android.os.ConditionVariable;
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
import com.google.android.exoplayer2.offline.DownloadManager;
|
||||||
import com.google.android.exoplayer2.offline.DownloadState;
|
import com.google.android.exoplayer2.offline.DownloadState;
|
||||||
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
@ -82,6 +83,12 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequirementsStateChanged(
|
||||||
|
DownloadManager downloadManager, Requirements requirements, int notMetRequirements) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks until all remove and download tasks are complete and throws an exception if there was an
|
* Blocks until all remove and download tasks are complete and throws an exception if there was an
|
||||||
* error.
|
* error.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue