Rename TaskState to DownloadState

PiperOrigin-RevId: 225145311
This commit is contained in:
eguven 2018-12-12 09:40:43 +00:00 committed by Oliver Woodman
parent 230a798f23
commit 4bf42bd2ad
8 changed files with 205 additions and 217 deletions

View file

@ -27,6 +27,7 @@
([#5169](https://github.com/google/ExoPlayer/issues/5169)).
* DownloadManager:
* Create only one task for all DownloadActions for the same content.
* Rename TaskState to DownloadState.
### 2.9.2 ###

View file

@ -17,7 +17,7 @@ package com.google.android.exoplayer2.demo;
import android.app.Notification;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
import com.google.android.exoplayer2.offline.DownloadService;
import com.google.android.exoplayer2.scheduler.PlatformScheduler;
import com.google.android.exoplayer2.ui.DownloadNotificationUtil;
@ -50,40 +50,40 @@ public class DemoDownloadService extends DownloadService {
}
@Override
protected Notification getForegroundNotification(TaskState[] taskStates) {
protected Notification getForegroundNotification(DownloadState[] downloadStates) {
return DownloadNotificationUtil.buildProgressNotification(
/* context= */ this,
R.drawable.ic_download,
CHANNEL_ID,
/* contentIntent= */ null,
/* message= */ null,
taskStates);
downloadStates);
}
@Override
protected void onTaskStateChanged(TaskState taskState) {
if (taskState.action.isRemoveAction) {
protected void onDownloadStateChanged(DownloadState downloadState) {
if (downloadState.action.isRemoveAction) {
return;
}
Notification notification = null;
if (taskState.state == TaskState.STATE_COMPLETED) {
if (downloadState.state == DownloadState.STATE_COMPLETED) {
notification =
DownloadNotificationUtil.buildDownloadCompletedNotification(
/* context= */ this,
R.drawable.ic_download_done,
CHANNEL_ID,
/* contentIntent= */ null,
Util.fromUtf8Bytes(taskState.action.data));
} else if (taskState.state == TaskState.STATE_FAILED) {
Util.fromUtf8Bytes(downloadState.action.data));
} else if (downloadState.state == DownloadState.STATE_FAILED) {
notification =
DownloadNotificationUtil.buildDownloadFailedNotification(
/* context= */ this,
R.drawable.ic_download_done,
CHANNEL_ID,
/* contentIntent= */ null,
Util.fromUtf8Bytes(taskState.action.data));
Util.fromUtf8Bytes(downloadState.action.data));
}
int notificationId = FOREGROUND_NOTIFICATION_ID + 1 + taskState.taskId;
int notificationId = FOREGROUND_NOTIFICATION_ID + 1 + downloadState.id;
NotificationUtil.setNotification(this, notificationId, notification);
}
}

View file

@ -37,7 +37,7 @@ import com.google.android.exoplayer2.offline.ActionFile;
import com.google.android.exoplayer2.offline.DownloadAction;
import com.google.android.exoplayer2.offline.DownloadHelper;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
import com.google.android.exoplayer2.offline.DownloadService;
import com.google.android.exoplayer2.offline.ProgressiveDownloadHelper;
import com.google.android.exoplayer2.offline.StreamKey;
@ -144,11 +144,11 @@ public class DownloadTracker implements DownloadManager.Listener {
}
@Override
public void onTaskStateChanged(DownloadManager downloadManager, TaskState taskState) {
DownloadAction action = taskState.action;
public void onDownloadStateChanged(DownloadManager downloadManager, DownloadState downloadState) {
DownloadAction action = downloadState.action;
Uri uri = action.uri;
if ((action.isRemoveAction && taskState.state == TaskState.STATE_COMPLETED)
|| (!action.isRemoveAction && taskState.state == TaskState.STATE_FAILED)) {
if ((action.isRemoveAction && downloadState.state == DownloadState.STATE_COMPLETED)
|| (!action.isRemoveAction && downloadState.state == DownloadState.STATE_FAILED)) {
// A download has been removed, or has failed. Stop tracking it.
if (trackedDownloadStates.remove(uri) != null) {
handleTrackedDownloadStatesChanged();

View file

@ -15,10 +15,10 @@
*/
package com.google.android.exoplayer2.offline;
import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_COMPLETED;
import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_FAILED;
import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_QUEUED;
import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_STARTED;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_COMPLETED;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_FAILED;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_QUEUED;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_STARTED;
import android.os.ConditionVariable;
import android.os.Handler;
@ -58,41 +58,41 @@ public final class DownloadManager {
*/
void onInitialized(DownloadManager downloadManager);
/**
* Called when the state of a task changes.
* Called when the state of a download changes.
*
* @param downloadManager The reporting instance.
* @param taskState The state of the task.
* @param downloadState The state of the download.
*/
void onTaskStateChanged(DownloadManager downloadManager, TaskState taskState);
void onDownloadStateChanged(DownloadManager downloadManager, DownloadState downloadState);
/**
* Called when there is no active task left.
* Called when there is no active download left.
*
* @param downloadManager The reporting instance.
*/
void onIdle(DownloadManager downloadManager);
}
/** The default maximum number of simultaneous download tasks. */
/** The default maximum number of simultaneous downloads. */
public static final int DEFAULT_MAX_SIMULTANEOUS_DOWNLOADS = 1;
/** The default minimum number of times a task 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;
private static final String TAG = "DownloadManager";
private static final boolean DEBUG = false;
private final int maxActiveDownloadTasks;
private final int maxActiveDownloads;
private final int minRetryCount;
private final ActionFile actionFile;
private final DownloaderFactory downloaderFactory;
private final ArrayList<Task> tasks;
private final ArrayList<Task> activeDownloadTasks;
private final ArrayList<Download> downloads;
private final ArrayList<Download> activeDownloads;
private final Handler handler;
private final HandlerThread fileIOThread;
private final Handler fileIOHandler;
private final CopyOnWriteArraySet<Listener> listeners;
private int nextTaskId;
private int nextDownloadId;
private boolean initialized;
private boolean released;
private boolean downloadsStopped;
@ -113,8 +113,8 @@ public final class DownloadManager {
*
* @param actionFile The file in which active actions are saved.
* @param downloaderFactory A factory for creating {@link Downloader}s.
* @param maxSimultaneousDownloads The maximum number of simultaneous download tasks.
* @param minRetryCount The minimum number of times a task must be retried before failing.
* @param maxSimultaneousDownloads The maximum number of simultaneous downloads.
* @param minRetryCount The minimum number of times a download must be retried before failing.
*/
public DownloadManager(
File actionFile,
@ -123,12 +123,12 @@ public final class DownloadManager {
int minRetryCount) {
this.actionFile = new ActionFile(actionFile);
this.downloaderFactory = downloaderFactory;
this.maxActiveDownloadTasks = maxSimultaneousDownloads;
this.maxActiveDownloads = maxSimultaneousDownloads;
this.minRetryCount = minRetryCount;
this.downloadsStopped = true;
tasks = new ArrayList<>();
activeDownloadTasks = new ArrayList<>();
downloads = new ArrayList<>();
activeDownloads = new ArrayList<>();
Looper looper = Looper.myLooper();
if (looper == null) {
@ -164,23 +164,23 @@ public final class DownloadManager {
listeners.remove(listener);
}
/** Starts the download tasks. */
/** Starts the downloads. */
public void startDownloads() {
Assertions.checkState(!released);
if (downloadsStopped) {
downloadsStopped = false;
maybeStartTasks();
maybeStartDownloads();
logd("Downloads are started");
}
}
/** Stops all of the download tasks. Call {@link #startDownloads()} to restart tasks. */
/** Stops all of the downloads. Call {@link #startDownloads()} to restart downloads. */
public void stopDownloads() {
Assertions.checkState(!released);
if (!downloadsStopped) {
downloadsStopped = true;
for (int i = 0; i < activeDownloadTasks.size(); i++) {
activeDownloadTasks.get(i).stop();
for (int i = 0; i < activeDownloads.size(); i++) {
activeDownloads.get(i).stop();
}
logd("Downloads are stopping");
}
@ -189,64 +189,50 @@ public final class DownloadManager {
/**
* Handles the given action.
*
* <p>A task is created and added to the task queue if there isn't one already for the same
* content.
*
* @param action The action to be executed.
* @return The id of the newly created or the existing task.
* @return The id of the newly created or the existing download.
*/
public int handleAction(DownloadAction action) {
Assertions.checkState(!released);
Task task = addTaskForAction(action);
Download download = getDownloadForAction(action);
if (initialized) {
saveActions();
maybeStartTasks();
if (task.state == STATE_QUEUED) {
// Task did not change out of its initial state, and so its initial state won't have been
maybeStartDownloads();
if (download.state == STATE_QUEUED) {
// Download did not change out of its initial state, and so its initial state won't have
// been
// reported to listeners. Do so now.
notifyListenersTaskStateChange(task);
notifyListenersDownloadStateChange(download);
}
}
return task.id;
return download.id;
}
/** Returns the number of tasks. */
public int getTaskCount() {
Assertions.checkState(!released);
return tasks.size();
}
/** Returns the number of download tasks. */
/** Returns the number of downloads. */
public int getDownloadCount() {
int count = 0;
for (int i = 0; i < tasks.size(); i++) {
for (DownloadAction action : tasks.get(i).actionQueue) {
if (!action.isRemoveAction) {
count++;
}
}
}
return count;
Assertions.checkState(!released);
return downloads.size();
}
/** Returns the state of a task, or null if no such task exists */
public @Nullable TaskState getTaskState(int taskId) {
/** Returns the state of a download, or null if no such download exists */
@Nullable
public DownloadState getDownloadState(int downloadId) {
Assertions.checkState(!released);
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
if (task.id == taskId) {
return task.getTaskState();
for (int i = 0; i < downloads.size(); i++) {
Download download = downloads.get(i);
if (download.id == downloadId) {
return download.getDownloadState();
}
}
return null;
}
/** Returns the states of all current tasks. */
public TaskState[] getAllTaskStates() {
/** Returns the states of all current downloads. */
public DownloadState[] getAllDownloadStates() {
Assertions.checkState(!released);
TaskState[] states = new TaskState[tasks.size()];
DownloadState[] states = new DownloadState[downloads.size()];
for (int i = 0; i < states.length; i++) {
states[i] = tasks.get(i).getTaskState();
states[i] = downloads.get(i).getDownloadState();
}
return states;
}
@ -257,14 +243,14 @@ public final class DownloadManager {
return initialized;
}
/** Returns whether there are no active tasks. */
/** Returns whether there are no active downloads. */
public boolean isIdle() {
Assertions.checkState(!released);
if (!initialized) {
return false;
}
for (int i = 0; i < tasks.size(); i++) {
if (tasks.get(i).isStarted()) {
for (int i = 0; i < downloads.size(); i++) {
if (downloads.get(i).isStarted()) {
return false;
}
}
@ -272,16 +258,17 @@ public final class DownloadManager {
}
/**
* Stops all of the tasks and releases resources. If the action file isn't up to date, waits for
* the changes to be written. The manager must not be accessed after this method has been called.
* Stops all of the downloads and releases resources. If the action file isn't up to date, waits
* for the changes to be written. The manager must not be accessed after this method has been
* called.
*/
public void release() {
if (released) {
return;
}
released = true;
for (int i = 0; i < tasks.size(); i++) {
tasks.get(i).stop();
for (int i = 0; i < downloads.size(); i++) {
downloads.get(i).stop();
}
final ConditionVariable fileIOFinishedCondition = new ConditionVariable();
fileIOHandler.post(fileIOFinishedCondition::open);
@ -290,47 +277,47 @@ public final class DownloadManager {
logd("Released");
}
private Task addTaskForAction(DownloadAction action) {
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
if (task.action.isSameMedia(action)) {
task.addAction(action);
logd("Action is added to existing task", task);
return task;
private Download getDownloadForAction(DownloadAction action) {
for (int i = 0; i < downloads.size(); i++) {
Download download = downloads.get(i);
if (download.action.isSameMedia(action)) {
download.addAction(action);
logd("Action is added to existing download", download);
return download;
}
}
Task task = new Task(nextTaskId++, this, downloaderFactory, action, minRetryCount);
tasks.add(task);
logd("Task is added", task);
return task;
Download download =
new Download(nextDownloadId++, this, downloaderFactory, action, minRetryCount);
downloads.add(download);
logd("Download is added", download);
return download;
}
/**
* Iterates through the task queue and starts any task if all of the following are true:
* Iterates through the download queue and starts any download if all of the following are true:
*
* <ul>
* <li>It hasn't started yet.
* <li>If it's a download task then the maximum number of active downloads hasn't been reached.
* <li>The maximum number of active downloads hasn't been reached.
* </ul>
*/
private void maybeStartTasks() {
private void maybeStartDownloads() {
if (!initialized || released) {
return;
}
boolean skipDownloadActions = downloadsStopped
|| activeDownloadTasks.size() == maxActiveDownloadTasks;
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
if (!task.canStart()) {
boolean skipDownloads = downloadsStopped || activeDownloads.size() == maxActiveDownloads;
for (int i = 0; i < downloads.size(); i++) {
Download download = downloads.get(i);
if (!download.canStart()) {
continue;
}
boolean isRemoveAction = task.action.isRemoveAction;
if (isRemoveAction || !skipDownloadActions) {
task.start();
boolean isRemoveAction = download.action.isRemoveAction;
if (isRemoveAction || !skipDownloads) {
download.start();
if (!isRemoveAction) {
activeDownloadTasks.add(task);
skipDownloadActions = activeDownloadTasks.size() == maxActiveDownloadTasks;
activeDownloads.add(download);
skipDownloads = activeDownloads.size() == maxActiveDownloads;
}
}
}
@ -346,30 +333,30 @@ public final class DownloadManager {
}
}
private void onTaskStateChange(Task task) {
private void onDownloadStateChange(Download download) {
if (released) {
return;
}
boolean stopped = !task.isStarted();
boolean stopped = !download.isStarted();
if (stopped) {
activeDownloadTasks.remove(task);
activeDownloads.remove(download);
}
notifyListenersTaskStateChange(task);
if (task.isFinished()) {
tasks.remove(task);
notifyListenersDownloadStateChange(download);
if (download.isFinished()) {
downloads.remove(download);
saveActions();
}
if (stopped) {
maybeStartTasks();
maybeStartDownloads();
maybeNotifyListenersIdle();
}
}
private void notifyListenersTaskStateChange(Task task) {
logd("Task state is changed", task);
TaskState taskState = task.getTaskState();
private void notifyListenersDownloadStateChange(Download download) {
logd("Download state is changed", download);
DownloadState downloadState = download.getDownloadState();
for (Listener listener : listeners) {
listener.onTaskStateChanged(this, taskState);
listener.onDownloadStateChanged(this, downloadState);
}
}
@ -390,27 +377,27 @@ public final class DownloadManager {
if (released) {
return;
}
List<Task> pendingTasks = new ArrayList<>(tasks);
tasks.clear();
List<Download> pendingDownloads = new ArrayList<>(downloads);
downloads.clear();
for (DownloadAction action : actions) {
addTaskForAction(action);
getDownloadForAction(action);
}
logd("Tasks are created.");
logd("Downloads are created.");
initialized = true;
for (Listener listener : listeners) {
listener.onInitialized(DownloadManager.this);
}
if (!pendingTasks.isEmpty()) {
tasks.addAll(pendingTasks);
if (!pendingDownloads.isEmpty()) {
downloads.addAll(pendingDownloads);
saveActions();
}
maybeStartTasks();
for (int i = 0; i < tasks.size(); i++) {
Task task = tasks.get(i);
if (task.state == STATE_QUEUED) {
// Task did not change out of its initial state, and so its initial state
maybeStartDownloads();
for (int i = 0; i < downloads.size(); i++) {
Download download = downloads.get(i);
if (download.state == STATE_QUEUED) {
// Download did not change out of its initial state, and so its initial state
// won't have been reported to listeners. Do so now.
notifyListenersTaskStateChange(task);
notifyListenersDownloadStateChange(download);
}
}
});
@ -421,9 +408,9 @@ public final class DownloadManager {
if (released) {
return;
}
ArrayList<DownloadAction> actions = new ArrayList<>(tasks.size());
for (int i = 0; i < tasks.size(); i++) {
actions.addAll(tasks.get(i).actionQueue);
ArrayList<DownloadAction> actions = new ArrayList<>(downloads.size());
for (int i = 0; i < downloads.size(); i++) {
actions.addAll(downloads.get(i).actionQueue);
}
final DownloadAction[] actionsArray = actions.toArray(new DownloadAction[0]);
fileIOHandler.post(
@ -443,16 +430,16 @@ public final class DownloadManager {
}
}
private static void logd(String message, Task task) {
logd(message + ": " + task);
private static void logd(String message, Download download) {
logd(message + ": " + download);
}
/** Represents state of a task. */
public static final class TaskState {
/** Represents state of a download. */
public static final class DownloadState {
/**
* Task states. One of {@link #STATE_QUEUED}, {@link #STATE_STARTED}, {@link #STATE_COMPLETED}
* or {@link #STATE_FAILED}.
* Download states. One of {@link #STATE_QUEUED}, {@link #STATE_STARTED}, {@link
* #STATE_COMPLETED} or {@link #STATE_FAILED}.
*
* <p>Transition diagram:
*
@ -465,13 +452,13 @@ public final class DownloadManager {
@Retention(RetentionPolicy.SOURCE)
@IntDef({STATE_QUEUED, STATE_STARTED, STATE_COMPLETED, STATE_FAILED})
public @interface State {}
/** The task is waiting to be started. */
/** The download is waiting to be started. */
public static final int STATE_QUEUED = 0;
/** The task is currently started. */
/** The download is currently started. */
public static final int STATE_STARTED = 1;
/** The task completed. */
/** The download completed. */
public static final int STATE_COMPLETED = 2;
/** The task failed. */
/** The download failed. */
public static final int STATE_FAILED = 3;
/** Returns the state string for the given state value. */
@ -490,16 +477,15 @@ public final class DownloadManager {
}
}
/** The unique task id. */
public final int taskId;
/** The unique download id. */
public final int id;
/** The action being executed. */
public final DownloadAction action;
/** The state of the task. */
/** The state of the download. */
public final @State int state;
/**
* The estimated download percentage, or {@link C#PERCENTAGE_UNSET} if no estimate is available
* or if this is a removal task.
* The estimated download percentage, or {@link C#PERCENTAGE_UNSET} if no estimate is available.
*/
public final float downloadPercentage;
/** The total number of downloaded bytes. */
@ -510,15 +496,15 @@ public final class DownloadManager {
/** If {@link #state} is {@link #STATE_FAILED} then this is the cause, otherwise null. */
@Nullable public final Throwable error;
private TaskState(
int taskId,
private DownloadState(
int id,
DownloadAction action,
@State int state,
float downloadPercentage,
long downloadedBytes,
long totalBytes,
@Nullable Throwable error) {
this.taskId = taskId;
this.id = id;
this.action = action;
this.state = state;
this.downloadPercentage = downloadPercentage;
@ -529,7 +515,7 @@ public final class DownloadManager {
}
private static final class Task {
private static final class Download {
/** Target states for the download thread. */
@Documented
@ -543,10 +529,10 @@ public final class DownloadManager {
private final int minRetryCount;
private final ArrayDeque<DownloadAction> actionQueue;
private DownloadAction action;
/** The current state of the task. */
@TaskState.State private int state;
/** The current state of the download. */
@DownloadState.State private int state;
/**
* When started, this is the target state that the task will transition to when the download
* When started, this is the target state that the download will transition to when the download
* thread stops.
*/
@TargetState private volatile int targetState;
@ -555,7 +541,7 @@ public final class DownloadManager {
@MonotonicNonNull private DownloadThread downloadThread;
@MonotonicNonNull private Throwable error;
private Task(
private Download(
int id,
DownloadManager downloadManager,
DownloaderFactory downloaderFactory,
@ -586,11 +572,11 @@ public final class DownloadManager {
} else {
Assertions.checkState(state == STATE_QUEUED);
action = updatedAction;
downloadManager.onTaskStateChange(this);
downloadManager.onDownloadStateChange(this);
}
}
public TaskState getTaskState() {
public DownloadState getDownloadState() {
float downloadPercentage = C.PERCENTAGE_UNSET;
long downloadedBytes = 0;
long totalBytes = C.LENGTH_UNSET;
@ -599,16 +585,16 @@ public final class DownloadManager {
downloadedBytes = downloader.getDownloadedBytes();
totalBytes = downloader.getTotalBytes();
}
return new TaskState(
return new DownloadState(
id, action, state, downloadPercentage, downloadedBytes, totalBytes, error);
}
/** Returns whether the task is finished. */
/** Returns whether the download is finished. */
public boolean isFinished() {
return state == STATE_FAILED || state == STATE_COMPLETED;
}
/** Returns whether the task is started. */
/** Returns whether the download is started. */
public boolean isStarted() {
return state == STATE_STARTED;
}
@ -619,9 +605,9 @@ public final class DownloadManager {
+ ' '
+ (action.isRemoveAction ? "remove" : "download")
+ ' '
+ TaskState.getStateString(state)
+ DownloadState.getStateString(state)
+ ' '
+ TaskState.getStateString(targetState);
+ DownloadState.getStateString(targetState);
}
public boolean canStart() {
@ -637,7 +623,7 @@ public final class DownloadManager {
downloadThread =
new DownloadThread(
this, downloader, action.isRemoveAction, minRetryCount, downloadManager.handler);
downloadManager.onTaskStateChange(this);
downloadManager.onDownloadStateChange(this);
}
}
@ -650,7 +636,7 @@ public final class DownloadManager {
// Internal methods running on the main thread.
private void stopDownloadThread() {
this.targetState = TaskState.STATE_QUEUED;
this.targetState = DownloadState.STATE_QUEUED;
Assertions.checkNotNull(downloadThread).cancel();
}
@ -664,19 +650,19 @@ public final class DownloadManager {
} else {
actionQueue.remove();
if (!actionQueue.isEmpty()) {
// Don't continue running. Wait to be restarted by maybeStartTasks().
// Don't continue running. Wait to be restarted by maybeStartDownloads().
state = STATE_QUEUED;
action = actionQueue.peek();
}
}
}
downloadManager.onTaskStateChange(this);
downloadManager.onDownloadStateChange(this);
}
}
private static class DownloadThread implements Runnable {
private final Task task;
private final Download download;
private final Downloader downloader;
private final boolean remove;
private final int minRetryCount;
@ -685,12 +671,12 @@ public final class DownloadManager {
private volatile boolean isCanceled;
private DownloadThread(
Task task,
Download download,
Downloader downloader,
boolean remove,
int minRetryCount,
Handler callbackHandler) {
this.task = task;
this.download = download;
this.downloader = downloader;
this.remove = remove;
this.minRetryCount = minRetryCount;
@ -709,7 +695,7 @@ public final class DownloadManager {
@Override
public void run() {
logd("Task is started", task);
logd("Download is started", download);
Throwable error = null;
try {
if (remove) {
@ -725,14 +711,14 @@ public final class DownloadManager {
if (!isCanceled) {
long downloadedBytes = downloader.getDownloadedBytes();
if (downloadedBytes != errorPosition) {
logd("Reset error count. downloadedBytes = " + downloadedBytes, task);
logd("Reset error count. downloadedBytes = " + downloadedBytes, download);
errorPosition = downloadedBytes;
errorCount = 0;
}
if (++errorCount > minRetryCount) {
throw e;
}
logd("Download error. Retry " + errorCount, task);
logd("Download error. Retry " + errorCount, download);
Thread.sleep(getRetryDelayMillis(errorCount));
}
}
@ -742,7 +728,7 @@ public final class DownloadManager {
error = e;
}
final Throwable finalError = error;
callbackHandler.post(() -> task.onDownloadThreadStopped(isCanceled ? null : finalError));
callbackHandler.post(() -> download.onDownloadThreadStopped(isCanceled ? null : finalError));
}
private int getRetryDelayMillis(int errorCount) {

View file

@ -24,7 +24,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.scheduler.RequirementsWatcher;
import com.google.android.exoplayer2.scheduler.Scheduler;
@ -71,9 +71,9 @@ public abstract class DownloadService extends Service {
private static final String TAG = "DownloadService";
private static final boolean DEBUG = false;
// Keep the requirements helper for each DownloadService as long as there are tasks (and the
// process is running). This allows tasks to resume when there's no scheduler. It may also allow
// tasks the resume more quickly than when relying on the scheduler alone.
// Keep the requirements helper 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
// allow downloads the resume more quickly than when relying on the scheduler alone.
private static final HashMap<Class<? extends DownloadService>, RequirementsHelper>
requirementsHelpers = new HashMap<>();
private static final Requirements DEFAULT_REQUIREMENTS =
@ -99,7 +99,7 @@ public abstract class DownloadService extends Service {
* <p>If {@code foregroundNotificationId} isn't {@link #FOREGROUND_NOTIFICATION_ID_NONE} (value
* {@value #FOREGROUND_NOTIFICATION_ID_NONE}) the service runs in the foreground with {@link
* #DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL}. In that case {@link
* #getForegroundNotification(TaskState[])} should be overridden in the subclass.
* #getForegroundNotification(DownloadState[])} should be overridden in the subclass.
*
* @param foregroundNotificationId The notification id for the foreground notification, or {@link
* #FOREGROUND_NOTIFICATION_ID_NONE} (value {@value #FOREGROUND_NOTIFICATION_ID_NONE})
@ -110,7 +110,7 @@ public abstract class DownloadService extends Service {
/**
* Creates a DownloadService which will run in the foreground. {@link
* #getForegroundNotification(TaskState[])} should be overridden in the subclass.
* #getForegroundNotification(DownloadState[])} should be overridden in the subclass.
*
* @param foregroundNotificationId The notification id for the foreground notification, must not
* be 0.
@ -128,7 +128,7 @@ public abstract class DownloadService extends Service {
/**
* Creates a DownloadService which will run in the foreground. {@link
* #getForegroundNotification(TaskState[])} should be overridden in the subclass.
* #getForegroundNotification(DownloadState[])} should be overridden in the subclass.
*
* @param foregroundNotificationId The notification id for the foreground notification. Must not
* be 0.
@ -338,29 +338,29 @@ public abstract class DownloadService extends Service {
*
* <p>Returns a notification to be displayed when this service running in the foreground.
*
* <p>This method is called when there is a task state change and periodically while there are
* active tasks. The periodic update interval can be set using {@link #DownloadService(int,
* <p>This method is called when there is a download state change and periodically while there are
* active downloads. The periodic update interval can be set using {@link #DownloadService(int,
* long)}.
*
* <p>On API level 26 and above, this method may also be called just before the service stops,
* with an empty {@code taskStates} array. The returned notification is used to satisfy system
* with an empty {@code downloadStates} array. The returned notification is used to satisfy system
* requirements for foreground services.
*
* @param taskStates The states of all current tasks.
* @param downloadStates The states of all current downloads.
* @return The foreground notification to display.
*/
protected Notification getForegroundNotification(TaskState[] taskStates) {
protected Notification getForegroundNotification(DownloadState[] downloadStates) {
throw new IllegalStateException(
getClass().getName()
+ " is started in the foreground but getForegroundNotification() is not implemented.");
}
/**
* Called when the state of a task changes.
* Called when the state of a download changes.
*
* @param taskState The state of the task.
* @param downloadState The state of the download.
*/
protected void onTaskStateChanged(TaskState taskState) {
protected void onDownloadStateChanged(DownloadState downloadState) {
// Do nothing.
}
@ -428,10 +428,11 @@ public abstract class DownloadService extends Service {
}
@Override
public void onTaskStateChanged(DownloadManager downloadManager, TaskState taskState) {
DownloadService.this.onTaskStateChanged(taskState);
public void onDownloadStateChanged(
DownloadManager downloadManager, DownloadState downloadState) {
DownloadService.this.onDownloadStateChanged(downloadState);
if (foregroundNotificationUpdater != null) {
if (taskState.state == TaskState.STATE_STARTED) {
if (downloadState.state == DownloadState.STATE_STARTED) {
foregroundNotificationUpdater.startPeriodicUpdates();
} else {
foregroundNotificationUpdater.update();
@ -471,8 +472,8 @@ public abstract class DownloadService extends Service {
}
public void update() {
TaskState[] taskStates = downloadManager.getAllTaskStates();
startForeground(notificationId, getForegroundNotification(taskStates));
DownloadState[] downloadStates = downloadManager.getAllDownloadStates();
startForeground(notificationId, getForegroundNotification(downloadStates));
notificationDisplayed = true;
if (periodicUpdatesStarted) {
handler.removeCallbacks(this);

View file

@ -20,8 +20,8 @@ import static org.junit.Assert.fail;
import android.net.Uri;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState.State;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState.State;
import com.google.android.exoplayer2.testutil.DummyMainThread;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
@ -371,11 +371,11 @@ public class DownloadManagerTest {
TaskWrapper task2 = new DownloadRunner(uri2).postDownloadAction().getTask();
TaskWrapper task3 = new DownloadRunner(uri3).postRemoveAction().getTask();
TaskState[] states = downloadManager.getAllTaskStates();
DownloadState[] states = downloadManager.getAllDownloadStates();
assertThat(states).hasLength(3);
int[] taskIds = {task1.taskId, task2.taskId, task3.taskId};
int[] stateTaskIds = {states[0].taskId, states[1].taskId, states[2].taskId};
int[] stateTaskIds = {states[0].id, states[1].id, states[2].id};
assertThat(stateTaskIds).isEqualTo(taskIds);
}
@ -522,19 +522,19 @@ public class DownloadManagerTest {
}
private TaskWrapper assertStarted() throws InterruptedException {
return assertState(TaskState.STATE_STARTED);
return assertState(DownloadState.STATE_STARTED);
}
private TaskWrapper assertCompleted() {
return assertState(TaskState.STATE_COMPLETED);
return assertState(DownloadState.STATE_COMPLETED);
}
private TaskWrapper assertFailed() {
return assertState(TaskState.STATE_FAILED);
return assertState(DownloadState.STATE_FAILED);
}
private TaskWrapper assertQueued() {
return assertState(TaskState.STATE_QUEUED);
return assertState(DownloadState.STATE_QUEUED);
}
private TaskWrapper assertState(@State int expectedState) {

View file

@ -23,7 +23,7 @@ import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.app.NotificationCompat;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
/** Helper for creating download notifications. */
public final class DownloadNotificationUtil {
@ -33,7 +33,7 @@ public final class DownloadNotificationUtil {
private DownloadNotificationUtil() {}
/**
* Returns a progress notification for the given task states.
* Returns a progress notification for the given download states.
*
* @param context A context for accessing resources.
* @param smallIcon A small icon for the notification.
@ -41,7 +41,7 @@ public final class DownloadNotificationUtil {
* above.
* @param contentIntent An optional content intent to send when the notification is clicked.
* @param message An optional message to display on the notification.
* @param taskStates The task states.
* @param downloadStates The download states.
* @return The notification.
*/
public static Notification buildProgressNotification(
@ -50,28 +50,28 @@ public final class DownloadNotificationUtil {
String channelId,
@Nullable PendingIntent contentIntent,
@Nullable String message,
TaskState[] taskStates) {
DownloadState[] downloadStates) {
float totalPercentage = 0;
int downloadTaskCount = 0;
boolean allDownloadPercentagesUnknown = true;
boolean haveDownloadedBytes = false;
boolean haveDownloadTasks = false;
boolean haveRemoveTasks = false;
for (TaskState taskState : taskStates) {
if (taskState.state != TaskState.STATE_STARTED
&& taskState.state != TaskState.STATE_COMPLETED) {
for (DownloadState downloadState : downloadStates) {
if (downloadState.state != DownloadState.STATE_STARTED
&& downloadState.state != DownloadState.STATE_COMPLETED) {
continue;
}
if (taskState.action.isRemoveAction) {
if (downloadState.action.isRemoveAction) {
haveRemoveTasks = true;
continue;
}
haveDownloadTasks = true;
if (taskState.downloadPercentage != C.PERCENTAGE_UNSET) {
if (downloadState.downloadPercentage != C.PERCENTAGE_UNSET) {
allDownloadPercentagesUnknown = false;
totalPercentage += taskState.downloadPercentage;
totalPercentage += downloadState.downloadPercentage;
}
haveDownloadedBytes |= taskState.downloadedBytes > 0;
haveDownloadedBytes |= downloadState.downloadedBytes > 0;
downloadTaskCount++;
}

View file

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
import java.util.HashMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
@ -56,12 +57,11 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
}
@Override
public void onTaskStateChanged(
DownloadManager downloadManager, DownloadManager.TaskState taskState) {
if (taskState.state == DownloadManager.TaskState.STATE_FAILED && downloadError == null) {
downloadError = taskState.error;
public void onDownloadStateChanged(DownloadManager downloadManager, DownloadState downloadState) {
if (downloadState.state == DownloadState.STATE_FAILED && downloadError == null) {
downloadError = downloadState.error;
}
getStateQueue(taskState.taskId).add(taskState.state);
getStateQueue(downloadState.id).add(downloadState.state);
}
@Override